-
Notifications
You must be signed in to change notification settings - Fork 7.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UART RS485 Failing to Enable Transmitter After Some Time (IDFGH-1983) #4178
Comments
I have performed a test by changing esp-idf/components/driver/uart.c Line 1003 in 6ccb4cf
to uart_reg->conf0.sw_rts = 1;
__asm__ __volatile__("nop;nop;nop;nop;nop;nop;nop;");
uart_reg->conf0.sw_rts = 0;
__asm__ __volatile__("nop;nop;nop;nop;nop;nop;nop;");
uart_reg->conf0.sw_rts = 1; in order to see if it was the interrupt setting RTS low, or if it was being set from an external source. After waiting around 30 minutes again I found that it is the isr function that is setting RTS low. |
Have you tried clearing UART_TX_DONE_INT right before it is enabled? |
I have tried adding esp-idf/components/driver/uart.c Line 1083 in 6ccb4cf
and it seems to be working properly now. However I will test it overnight to see how it goes |
OK, it looks like that change (clearing the UART_TX_DONE_INT interrupt before writing to the FIFO) has fixed it! After leaving it overnight I have come back to the system still working happily this morning. |
Hi dasrue, Thank you for your issue report. I have hard time trying to reproduce the issue with Modbus examples and with specific RS485 test example and it was working good for even much more time. Your solution looks good to me but I have to reproduce it first to fix it appropriately. -- |
Hi @dasrue, components/driver/uart.c: line 1109: } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) {
if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX) && uart_reg->status.st_utx_out != 0) {
// The TX_DONE interrupt is triggered in RS485 half duplex mode but transmission is active
// then postpone interrupt processing for next interrupt
uart_event.type = UART_EVENT_MAX;
} else {
// Disable TX_DONE interrupt and clear interrupt status
uart_disable_intr_mask_from_isr(uart_num, UART_TX_DONE_INT_ENA_M);
uart_clear_intr_status(uart_num, UART_TX_DONE_INT_CLR_M);
// Workaround for RS485: If the RS485 half duplex mode is active
// and transmitter is in idle state then reset received buffer and reset RTS pin
// skip this behavior for other UART modes
if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) {
UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
uart_reg->conf0.sw_rts = 1;
uart_reset_rx_fifo(uart_num); // Allows to avoid hardware issue with the RXFIFO reset
UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
}
xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken);
} This workaround allows to control the transmission state and reset RTS pin when transmission is done. If it is not done the interrupt will be activated later because status bit is not cleared. |
@alisitsyn isn't not clearing the interrupt basically the same as |
@negativekelvin, Not clearing interrupt is similar to waiting but in case of waiting in interrupt handler we block other interrupts processing on the same CPU but even on other CPU while waiting. |
You are saying UART_TX_DONE_INT does not provide the correct timing for rts, but that wasn't the issue reported here. The issue was UART_TX_DONE_INT was pending before the start of packet. Are you saying waiting for idle state will prevent spurious UART_TX_DONE_INT? What is the typical delay between UART_TX_DONE_INT and st_utx_out = 0? |
I can just guess why TX_DONE interrupt is triggered in this case, but the scenario looks like:
Let us imagine worse case: User app sending the data and fills fifo. Default uart interrupt handler is in flash. User task is switched and other higher priority task disables CPU cache (access flash memory). First portion of data sent out and other portion written into fifo later and transmission is started but TX_DONE interrupt processing is delayed and triggered in the middle of transmission of next portion of data (in the middle of the byte). In this case the RTS will be reset and byte will be transmitted incorrectly. This fix will keep RTS line in logic one while transmission is not done and allow to avoid incorrect transmission. So, I think this fix helps to solve both issues with direction control in RS485 HF mode. |
I think the clear before enable is more important. I'm not convinced about st_utx_out because if it is not guaranteed to be a short time then it is better to clear the interrupt but not disable it instead of keep entering the isr. |
@negativekelvin, |
@dasrue @negativekelvin Thanks for reporting, would you please help share if any updates for the issue? Thanks. |
Thanks for reporting, will close due to short of feedback. Feel free to reopen with more details/updates. Thanks. |
It seems the issue is still actual and discussed here: https://esp32.com/viewtopic.php?f=13&t=21835&p=80501#p80501 |
I recently encountered the exact same issue; my workaround is to manually switch the RTS signal (as a normal GPIO) instead of relying on the uart driver. |
What is your esp-idf version (git describe --tags)? |
v4.3-970-g7467c68a17 |
Please apply patch below 0001_driver_uart_fix_tx_bytes_rts_assert_failure.patch.log Thank you. |
Hi @Maldus512 , Could you please share your results here? |
Sorry for getting back at you so late. |
Thank you for the update. Please post the results here once the problem comes again. |
The fix was merged into master with commit ID: 09c1fba |
Environment
Problem Description
After running for some time (around 30 minutes), the UART driver fails to enable the RS485 driver properly. After probing with a scope, I found that the driver is enabled breifly, then disabled before the UART tries to send the data.
Expected Behavior
RTS pin goes high, data is transmitted, then RTS pin goes low
Actual Behavior
Behaviour is OK for around 30 Minutes after reset.
After 30 Minutes:
RTS pin goes high for around 50us then RTS pin goes low, data is transmitted from UART, but is not transmitted onto RS485 bus due to driver EN signal being off.
Steps to repropduce
Code to reproduce this issue
Working on creating a program to reproduce bug
Debug Logs
No errors printed to log.
The text was updated successfully, but these errors were encountered: