RS485 Enable pin issue
RS485 Enable pin issue
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]
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]
Re: RS485 Enable pin issue
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.
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.
-
- Posts: 203
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: RS485 Enable pin issue
@orbitcoms,
Do you use the `uart_wait_tx_done()` function in your code to wait for completion of transmission?
Do you use the `uart_wait_tx_done()` function in your code to wait for completion of transmission?
Re: RS485 Enable pin issue
My code is in previous code.
BTW: should tx_done check be done immediately after sending or before to ensure buffer empty first?
BTW: should tx_done check be done immediately after sending or before to ensure buffer empty first?
Re: RS485 Enable pin issue
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?
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?
-
- Posts: 203
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: RS485 Enable pin issue
@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.
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.
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
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 512 times
-
- RTS line deassertion issue when transmission is in progress
- echo_test1.png (198.29 KiB) Viewed 6394 times
Last edited by ESP_alisitsyn on Wed Jul 21, 2021 6:49 am, edited 2 times in total.
Re: RS485 Enable pin issue
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);
}
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);
}
-
- Posts: 203
- Joined: Fri Feb 01, 2019 4:02 pm
- Contact:
Re: RS485 Enable pin issue
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)
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.
Re: RS485 Enable pin issue
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?)
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: Google [Bot] and 161 guests