Closed MightyPork closed 3 years ago
.source_clk = UART_SCLK_REF_TICK can only support up to 115200 baudrate. Use .source_clk = UART_SCLK_APB for higher baudrate.
Thanks, unfortunately that did not change anything.
Here is 1Mbps with UART_SCLK_APB:
same problem down to 200000 baud, like before.
200_000:
Here is my sdkconfig, in case something is wrong there:
@MightyPork Thanks for the detailed report and sharing the waveforms, we will look into.
Hello @MightyPork,
Thank you for the issue and good details. The UART driver uses the interrupt driven RS485 control using TX_EMPTY and TX_DONE interrupt. This approach was selected because the automatic direction control feature on ESP32 is available only on UART0 and does not work on other UARTs. The interrupts have the latency time up to ~10us that may prevent to process packets properly on higher speed. There is the kconfig value CONFIG_UART_ISR_IN_IRAM to place the UART interrupt handler into IRAM that can help to decrease the latency. In your config the interrupt handler is placed in FLASH memory. If your code uses tasks with nvs, spi_flash access API this may increase latency even more because these functions disable the CPU cache.
I investigate the issue, try to check solutions and will provide the ideas/solutions little bit later. Please try the key above for now to decrease latency for now.
Thanks.
Hello @MightyPork,
Thank you for the issue and good details. The UART driver uses the interrupt driven RS485 control using TX_EMPTY and TX_DONE interrupt. This approach was selected because the automatic direction control feature on ESP32 is available only on UART0 and does not work on other UARTs. The interrupts have the latency time up to ~10us that may prevent to process packets properly on higher speed. There is the kconfig value CONFIG_UART_ISR_IN_IRAM to place the UART interrupt handler into IRAM that can help to decrease the latency.
Hi @alisitsyn I'm wondering why CONFIG_UART_ISR_IN_IRAM is disabled by default? Is there any drawback with CONFIG_UART_ISR_IN_IRAM=y?
Hi @AxelLin,
The option is disabled for the automatic test application to decrease IRAM size. The test application for v4.1 consumes a lot of IRAM and it cause errors. This is drawback of this option.
Folks, I have to apologize for blaming the UART driver too quickly.
I discovered that a library we were using was sending the frame in multiple small pieces. This made delays in the driver visible as RTS (DE) gaps.
Now I have an explanation why this problem was not apparent at slow baud rates: The FIFO was still processing the last chunk when a new one was added, so the driver / peripheral never saw the FIFO empty and did not toggle DE.
I added a buffer to collect the message and send it in one piece. The waveforms are looking much better now.
Some interesting observations:
The impact of CONFIG_UART_ISR_IN_IRAM=n
is only a delay of 15us between RTS and the first start bit - at 1 Mbps. I think that's negligible if it means we get more RAM.
UART works fine up to (tested) 1Mbps with UART_SCLK_REF_TICK - I will still keep ABP, but it does not seem to matter.
So this is probably a myth:
.source_clk = UART_SCLK_REF_TICK can only support up to 115200 baudrate
We are using CONFIG_FREERTOS_HZ=1000
, maybe it's a problem with CONFIG_FREERTOS_HZ=100
.
Bulk of the delays I was seeing was caused by the RTS (DE) switching in the driver.
uart_set_rts()
calls made it slow again. Something to do with the critical sections? I'm not sure.Again thanks for the help
@MightyPork,
Bulk of the delays I was seeing was caused by the RTS (DE) switching in the driver.
The ESP32 chip has an error in UART peripheral and is not able to control RTS line automatically in RS485 mode. There is workaround to mitigate this issue in UART driver which uses the TX_DONE and TX_EMPTY interrupts to de/assert RTS line manually and flush buffer to clear zero bytes related to switching of transceiver. This adds delays for interrupt latency. However the hardware of UART0 on ESP32 allows to control the DE pin of transceiver over DTRN_OUT signal. Other UARTs of ESP32 do not support this feature. This feature is available in ESP32S2 chip UARTs but is not supported by ESP-IDF UART driver yet. I can propose you to try this feature. However no any guaranties while it is not officially supported. The UART should be configured in APP_CTRL mode and the code below will allow to configure the DTRN_OUT pin of ESP32:
#include "driver/gpio.h"
#include "soc/gpio_sig_map.h" //for DTRN pin configuration
#include "esp_rom_gpio.h"
// The DTRN_OUT hw signal will be assigned to this pin in RS485 Half-Duplex Mode (Only on UART_NUM_0)
#define ECHO_TEST_DTR (19) // The GPIO19 shall be used to control RS485 transceiver DE pin
static void uart_conf_dtrn_out(int dtr_io_num)
{
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[dtr_io_num], PIN_FUNC_GPIO);
gpio_set_direction(dtr_io_num, GPIO_MODE_OUTPUT);
esp_rom_gpio_connect_out_signal(dtr_io_num, U0DTR_OUT_IDX, 0, 0);
}
....
// app_main: uart initialization code addition:
uart_set_pin(EX_UART_NUM, DMX_TEST_TXD, DMX_TEST_RXD, DMX_TEST_RTS, UART_PIN_NO_CHANGE);
uart_conf_dtrn_out(DMX_TEST_DTR); // Configure the GPIO DMX_TEST_DTR pin number for DTRN_OUT signal on UART0
Platform:
I'm investigating a bug with the DE line in UART RS485 mode. I have a report of lost packets, I'm not exactly sure what was happening. Nonetheless...
I discovered that the DE line becomes intermittent when the baud rate is roughly above 200000 bps. 9600, 150000 and 115200 are OK. It doesn't make any sense to me, so I thought it's worth a report. Maybe it's a driver bug? Or something in the hardware peripheral?
Here are some of the waveforms:
Oscilloscope screenshots
## 115200, all OK ![115200_ok](https://user-images.githubusercontent.com/2041118/101226121-c0f05380-3693-11eb-8732-c33bace22c95.png) 9600 is also OK. ## 200000, groups of 2 bytes ![200kbps_frame](https://user-images.githubusercontent.com/2041118/101226453-d619b200-3694-11eb-965e-a1a26e491eb0.png) ## 250000, each byte sent separately ![250k_decode](https://user-images.githubusercontent.com/2041118/101226323-61df0e80-3694-11eb-8348-14d9ffd4fef0.png) ## 500000, increasingly strange ![500k](https://user-images.githubusercontent.com/2041118/101226332-67d4ef80-3694-11eb-9347-04933e3fa4de.png) The gap has 40us.Excerpt from the config:
Bytes are sent using
uart_write_bytes()
from a heap allocated buffer.appreciate any ideas