RS485 Enable pin issue

orbitcoms
Posts: 141
Joined: Fri Aug 03, 2018 10:08 pm
Location: Sydney, Australia

RS485 Enable pin issue

Postby orbitcoms » Mon Jul 05, 2021 12:45 am

I have set up a UART on ESP32 that sends RS485 data every few hundred ms.

After a long time (it might be several hours or a couple of days), the ENABLE pin stops working correctly and I loose connection to remote devices on the RS485 bus, it does not recover until I reset the power supply. At first I thought it was a hardware issue but when I looked on a scope the ENABLE pin was set high for entire duration of data packet ok for long time but when it plays up the enable goes high for a short period of time before the data packet and goes low before data is sent.

Is there any known issue with the UART driver software that could cause this? Should I disable the enable function and manually toggle the enable using GPIO during transmission instead?

My config is below.

[code]
#define RX_BUFFER_SIZE (128*2)
#define rs485_uart (UART_NUM_1)
#define RS485_TXD_PIN (27)
#define RS485_RXD_PIN (13)
#define RS485_EN_PIN (14)

void init_rs485_uart(void)
{
const uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
uart_param_config(rs485_uart, &uart_config);
uart_set_pin(rs485_uart, RS485_TXD_PIN, RS485_RXD_PIN, RS485_EN_PIN, UART_PIN_NO_CHANGE);
ESP_ERROR_CHECK(uart_driver_install(rs485_uart, RX_BUFFER_SIZE,0,UART_QUEUE_SIZE,&uart_queue,0));
ESP_ERROR_CHECK(uart_set_mode(rs485_uart, UART_MODE_RS485_HALF_DUPLEX));
uart_set_rx_timeout(rs485_uart,UART_BREAK_TIME);
//uart_set_always_rx_timeout(rs485_uart,true);
xTaskCreate(uart_event_task,"uart event task",2048,NULL,20,NULL);
}

int send_rs845_uart_data(char *command,int numbytes)
{
uart_write_bytes(rs485_uart, command, numbytes);
return true;
}

[/code]

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: RS485 Enable pin issue

Postby WiFive » Mon Jul 05, 2021 3:53 am


orbitcoms
Posts: 141
Joined: Fri Aug 03, 2018 10:08 pm
Location: Sydney, Australia

Re: RS485 Enable pin issue

Postby orbitcoms » Mon Jul 05, 2021 4:05 am

Thanks,
That is the exact error I have and same signals on scope.
I am a bit confused about the solution. There is a suggestion to add this line below. Is this added in my code somewhere or does the actual uart library component need it added (I am using ESP-IDF 4.3, if this needs editing does it mean no fix was implemented in the component)?
"uart_clear_intr_status(uart_num, UART_TX_DONE_INT_CLR_M);"

Where should this line be placed and is it all that is required to fix the issue? The post does not seem to have a resolution accepted.

ESP_alisitsyn
Posts: 203
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: RS485 Enable pin issue

Postby ESP_alisitsyn » Tue Jul 20, 2021 10:35 am

@orbitcoms,

Do you use the `uart_wait_tx_done()` function in your code to wait for completion of transmission?

orbitcoms
Posts: 141
Joined: Fri Aug 03, 2018 10:08 pm
Location: Sydney, Australia

Re: RS485 Enable pin issue

Postby orbitcoms » Tue Jul 20, 2021 9:15 pm

My code is in previous code.

BTW: should tx_done check be done immediately after sending or before to ensure buffer empty first?

sramberg2
Posts: 9
Joined: Tue Jul 20, 2021 9:35 pm

Re: RS485 Enable pin issue

Postby sramberg2 » Tue Jul 20, 2021 9:51 pm

I have the same issue. Using ESP-IDF 4.3.

I call uart_write_bytes() to send 7 bytes, then I wait 10ms+ (in other tasks) and never call uart_wait_tx_done().

Is uart_wait_tx_done() required even if the transmission is completed?

ESP_alisitsyn
Posts: 203
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: RS485 Enable pin issue

Postby ESP_alisitsyn » Wed Jul 21, 2021 4:52 am

@sramberg2, @orbitcoms,

Thank you for answers. I am asking about using of uart_write_bytes() because this function has side effects when RS485 HF mode is used. It may disable the TX_DONE interrupt after timeout and interrupt will never come. You can avoid using of wait_tx_done() for now in your code.
During my investigation some time ago it was not possible to reproduce the issue you are mentioned but it was possible to reproduce other issue when during active transmission the TX_DONE interrupt come and disables RTS line (this one was fixed in the driver, see the picture attached echo_test1.png).

So, in order to solve the issue I would propose to do steps below:
1. Try to place default UART interrupt handler into IRAM to avoid possible latency of interrupt activation (when access to nvs or flash). Set CONFIG_UART_ISR_IN_IRAM = y for this.
2. The patch attached can be used to check approach from github issue #4178.

Code: Select all

git apply 0001_driver_uart_fix_rts_assertion_issue.diff
3. Compile your application and start to check issue with the RTS line.

I need your help to check this approach because it takes time to reproduce. I will continue with the investigation of the issue.
Please follow the suggetions above and keep me posted about results.

Thanks.
Attachments
0001_driver_uart_fix_rts_assertion_issue.diff.txt
patch to check approach issue #4178
(3.49 KiB) Downloaded 506 times
echo_test1.png
RTS line deassertion issue when transmission is in progress
echo_test1.png (198.29 KiB) Viewed 6276 times
Last edited by ESP_alisitsyn on Wed Jul 21, 2021 6:49 am, edited 2 times in total.

orbitcoms
Posts: 141
Joined: Fri Aug 03, 2018 10:08 pm
Location: Sydney, Australia

Re: RS485 Enable pin issue

Postby orbitcoms » Wed Jul 21, 2021 5:00 am

Thanks,

Where does the function to place defult isr into iram go?

Here is my init code.

void init_rs485_uart(void)
{
const uart_config_t uart_config = {
.baud_rate = 115200,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
ESP_ERROR_CHECK(uart_driver_install(rs485_uart, RX_BUFFER_SIZE,0,UART_QUEUE_SIZE,&uart_queue,0));
uart_param_config(rs485_uart, &uart_config);
uart_set_pin(rs485_uart, RS485_TXD_PIN, RS485_RXD_PIN, RS485_EN_PIN, UART_PIN_NO_CHANGE);
ESP_ERROR_CHECK(uart_set_mode(rs485_uart, UART_MODE_RS485_HALF_DUPLEX));
uart_set_rx_timeout(rs485_uart,UART_BREAK_TIME);
//uart_set_always_rx_timeout(rs485_uart,true);
xTaskCreate(uart_event_task,"uart event task",2048,NULL,20,NULL);
}

ESP_alisitsyn
Posts: 203
Joined: Fri Feb 01, 2019 4:02 pm
Contact:

Re: RS485 Enable pin issue

Postby ESP_alisitsyn » Wed Jul 21, 2021 6:37 am

Where does the function to place defult isr into iram go?

Code: Select all

esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags)
When you install driver the `intr_alloc_flags` flag tells where to place the interrupt handler. This flag can be `ESP_INTR_FLAG_IRAM` for IRAM safe and `ESP_INTR_FLAG_LOWMED` for flash handler.
Actually you do not need to change your code to place the interrupt handler into IRAM and can even leave the intr_alloc_flags = 0. It is usually enough to set CONFIG_UART_ISR_IN_IRAM =y in `Component config -> Driver configurations -> UART configuration` menu.
The flag will be overriden accordingly then and the default handler will be placed into appropriate memory. This can allow avoiding possible handling delays when CPU cache is disabled.

orbitcoms
Posts: 141
Joined: Fri Aug 03, 2018 10:08 pm
Location: Sydney, Australia

Re: RS485 Enable pin issue

Postby orbitcoms » Wed Jul 21, 2021 8:27 am

Thanks

I just need to set this in the menuconfig and not do anything else in code and not use the tx_done check right?

I see you can do same for TWAI (which I use in another project) do you usually want TWAI int in IRAM also?)

Who is online

Users browsing this forum: Bing [Bot], ESP_rrtandler, zelenecul and 118 guests