Hello,
I've assembled an ESP32WROOM module on a breakout board and set up some tests. I'd like to wire it up to an RS-485 transceiver chip for bus communication.
My first efforts were to get UART input working with the USB serial console UART0, the one that is used to program the device. That worked well. I could type commands in the serial port monitor of VSCode (Platform IO) and my code would react and do something, then log a message that I could see.
Now I've changed this to accept commands on UART2 and also send the response there. This is wired on different pins. The UART0 log is still active and running in parallel as set up during boot.
The problem is that I cannot receive any data from the RS-485 line. I've tried two different pins for RXD (default 16 and the adjacent number 5) but none work. I'm following the example code here, but for UART_NUM_2.
My code also regularly sends a counter over the RS-485 line as well as logging it and I can see both. So UART2/RS-485 sending works, but receiving does not.
I've checked that the DE signal isn't always-on by removing that pin and leaving it with its pulldown resistor. That stopped the sending but receiving still didn't work.
What should I look at to find out what's wrong?
UART2 does not receive anything
Re: UART2 does not receive anything
A few tests later, I see that the problem is not limited to UART2. None of the UARTs can receive anymore. I've changed it to UART_NUM_1 with the same effect (it can use any pins) and with UART_NUM_0 it would mix up my serial output with the formatted logging, but still not receive any input.
Here is the code I use now:
Here is the code I use now:
Code: Select all
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "sdkconfig.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "esp_log.h"
static const char *TAG = "App";
#define BUF_SIZE (1024)
#define GPIO_LED (33)
// Default is UART_PIN_NO_CHANGE
#define RS485TXD (17)
#define RS485RXD (16)
#define RS485RTS (4)
#define RS485BAUDRATE (115200)
#define UART_NUM (UART_NUM_2)
void uart_send(const int port, const char* str, size_t length);
void handle_command(const char* line);
void app_main()
{
gpio_set_direction(GPIO_LED, GPIO_MODE_OUTPUT);
gpio_set_level(GPIO_LED, 1);
vTaskDelay(5000 / portTICK_PERIOD_MS);
uart_config_t uart_config = {
.baud_rate = RS485BAUDRATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.rx_flow_ctrl_thresh = 122,
};
// Configure UART parameters
int intr_alloc_flags = 0;
ESP_ERROR_CHECK(uart_driver_install(UART_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM, RS485TXD, RS485RXD, RS485RTS, UART_PIN_NO_CHANGE));
ESP_ERROR_CHECK(uart_set_mode(UART_NUM, UART_MODE_RS485_HALF_DUPLEX));
ESP_ERROR_CHECK(uart_set_rx_timeout(UART_NUM, 3));
uart_send(UART_NUM, "Device ready.\r\n", 15);
// Configure a temporary buffer for the incoming data
uint8_t* data = (uint8_t*)malloc(BUF_SIZE);
int usedData = 0;
int count = 0;
while (true)
{
// Read data from the UART
int len = uart_read_bytes(UART_NUM, data + usedData, BUF_SIZE - 1 - usedData, 20 / portTICK_PERIOD_MS);
if (len > 0)
{
usedData += len;
for (int i = usedData - len; i < usedData; i++)
{
// Handle CR-LF
if (i < usedData - 1 && data[i] == '\r' && data[i + 1] == '\n')
{
// Skip to LF
data[i] = '\0';
i++;
}
// Handle LF
if (data[i] == '\n')
{
data[i] = '\0';
ESP_LOGI(TAG, "Recv line: %s", (char*)data);
uart_send(UART_NUM, "Recv line: ", 11);
uart_send(UART_NUM, (char*)data, i);
uart_send(UART_NUM, "\r\n", 2);
handle_command((char*)data);
for (int j = i + 1; j < usedData; j++)
{
data[j - (i + 1)] = data[j];
}
usedData -= (i + 1);
i = -1;
}
}
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Free memory: %d bytes", esp_get_free_heap_size());
//ESP_LOGI(TAG, "IDF version: %s", esp_get_idf_version());
ESP_LOGI(TAG, "Count: %d", count);
char senddata[20] = {0};
sprintf(senddata, "Count: %d\r\n", count);
uart_send(UART_NUM, senddata, strlen(senddata));
count++;
if (count == 2)
{
gpio_set_level(GPIO_LED, 0);
}
else if (count > 2)
{
gpio_set_level(GPIO_LED, 1);
vTaskDelay(10 / portTICK_PERIOD_MS);
gpio_set_level(GPIO_LED, 0);
}
}
}
void uart_send(const int port, const char* str, size_t length)
{
if (uart_write_bytes(port, str, length) != length)
{
ESP_LOGE(TAG, "Send data critical failure.");
// add your code to handle sending failure here
abort();
}
}
void handle_command(const char* line)
{
if (!strcmp(line, "free"))
{
ESP_LOGI(TAG, "Free memory: %d bytes", esp_get_free_heap_size());
char data[40] = {0};
sprintf(data, "Free memory: %d bytes\r\n", esp_get_free_heap_size());
uart_send(UART_NUM, data, strlen(data));
}
else if (!strcmp(line, "ver"))
{
ESP_LOGI(TAG, "IDF version: %s", esp_get_idf_version());
char data[40] = {0};
sprintf(data, "IDF version: %s\r\n", esp_get_idf_version());
uart_send(UART_NUM, data, strlen(data));
}
else
{
ESP_LOGE(TAG, "Unknown command: %s", line);
char data[100] = {0};
sprintf(data, "Unknown command: %s\r\n", line);
uart_send(UART_NUM, data, strlen(data));
}
}
Re: UART2 does not receive anything
New experiments, still no success.
I've discovered that the U2RTS signal was kept high all the time, enabling the RS-485 driver permanently. The ESP32 UART driver would never release the bus. It was only released when I disconnected the IO4 pin from the transceiver's DE input.
Even with this line disconnected and the bus free to receive, the ESP32 UART never receives anything. I can verify with a scope that the bytes I sent from a terminal was correctly received by the RS-485 transceiver and fed into the ESP32 chip. Yet it totally ignores this.
IO4 seems to be a bad choice for the U2RTS signal. It is always high, never low. Switching this to IO22 (the default for U0RTS) works better. It only enables the RS-485 driver when it's sending something. I've measured the on time and verified that it's the expected duration for the data that was sent. I could also still read all sent data in my terminal.
Unfortunately, with IO22 connected to the (weakly pulled-down) DE pin, the firmware upload with the standard RTS/DTR circuit fails. It could upload the firmware but not properly reset the chip. When I disconnected the IO22/DE line and pressed the RESET button on the breakout board, it would boot into download mode (according to the serial port monitor). Only disconnecting the power with IO22 disconnected properly booted the code.
I'm still not sure what this obscure TOUT feature is. The code I've shown above sets it to "3" and also has a UART driver config of "rx_flow_ctrl_thresh = 122". When removing both, the code won't start. With "uart_set_rx_timeout(UART_NUM, 0)" added back, it still can't receive.
It remains a complete mess. As it stands now, ESP32 does not support RS-485 on UART2. Is there any solution to this?
I've discovered that the U2RTS signal was kept high all the time, enabling the RS-485 driver permanently. The ESP32 UART driver would never release the bus. It was only released when I disconnected the IO4 pin from the transceiver's DE input.
Even with this line disconnected and the bus free to receive, the ESP32 UART never receives anything. I can verify with a scope that the bytes I sent from a terminal was correctly received by the RS-485 transceiver and fed into the ESP32 chip. Yet it totally ignores this.
IO4 seems to be a bad choice for the U2RTS signal. It is always high, never low. Switching this to IO22 (the default for U0RTS) works better. It only enables the RS-485 driver when it's sending something. I've measured the on time and verified that it's the expected duration for the data that was sent. I could also still read all sent data in my terminal.
Unfortunately, with IO22 connected to the (weakly pulled-down) DE pin, the firmware upload with the standard RTS/DTR circuit fails. It could upload the firmware but not properly reset the chip. When I disconnected the IO22/DE line and pressed the RESET button on the breakout board, it would boot into download mode (according to the serial port monitor). Only disconnecting the power with IO22 disconnected properly booted the code.
I'm still not sure what this obscure TOUT feature is. The code I've shown above sets it to "3" and also has a UART driver config of "rx_flow_ctrl_thresh = 122". When removing both, the code won't start. With "uart_set_rx_timeout(UART_NUM, 0)" added back, it still can't receive.
It remains a complete mess. As it stands now, ESP32 does not support RS-485 on UART2. Is there any solution to this?
Re: UART2 does not receive anything
Hi there, I am not having the time to dive too much into this, but for a quick view and my understanding
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
is the cause. HW flow control should be enabled if you wanna use the library to control this functionality.
However, HW flow control includes RTS and DTR signals.
As you know in your code at what time you send something you may consider to set the IO pin yourself and remain with flow control disabled. That is how I deal with RS485 drivers. It also gives you control if you need RTS high or low for your driver chip.
Not sure if that helps
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
is the cause. HW flow control should be enabled if you wanna use the library to control this functionality.
However, HW flow control includes RTS and DTR signals.
As you know in your code at what time you send something you may consider to set the IO pin yourself and remain with flow control disabled. That is how I deal with RS485 drivers. It also gives you control if you need RTS high or low for your driver chip.
Not sure if that helps
Re: UART2 does not receive anything
ESP's example code has exactly this, and the documentation (last paragraph here) suggests that hw flow control must be disabled for this circuit "B" which I use.
Who is online
Users browsing this forum: No registered users and 70 guests