ESP32 UART FIFO Operation
Posted: Fri Oct 20, 2023 10:45 pm
Hello All,
I have been developing with ESP-IDF v4.3.2. Under this version, I have UART communications working flawlessly over both UART0 and UART2.
I recently attempted to upgrade the project to utilize the more recent releases of ESP-IDF. I discovered that the UART receive FIFO operation is no longer working as expected. While the transmit function is working well (and allowing me to dump diagnostic information) the receive operations are fouled up. After much testing of the project builds under different versions of the IDF, I discovered that this apparently crept in with v4.4.x.
My testing focused on UART0 operation and included the use of several dumps of the GPIO and UART configuration registers to determine if I could detect any differences in the configuration of the hardware between v4.3.2 and v4.4.1. I am attempting to utilize UART0 with its default connections for TxD and RxD signals (GPIO1 and GPIO3). I noticed the following changes in the GPIO configuration register values between the two builds:
Obviously the discrepancies in routing the U0TxD to the GPIO1 output pin do not pose any issues, as the transmitter is producing traffic just fine.
The comparison of the UART configuration registers did not yield any significant differences, with the exception that the MEM_RX_STATUS register "rd_addr" parameter was non-zero on the nonworking build under v4.4.1 (register offset 0x60). Here are the dumps of the full register values for each version:
v4.3.1:
04:00002020 08:00000000 0C:00004113 10:00000000 14:009000AD 18:00001000 1C:6678C000 20:0800001C 24:82006470 28:000FFFFF 2C:000FFFFF 30:00000000 34:00000000 38:000000F0 3C:1311E000 40:00A00100 44:00000000 48:00186A00 4C:00186A00 50:00001E00 54:0000032B 58:00000088 5C:00034010 60:00300600 64:00000000 68:000FFFFF 6C:000FFFFF 70:00000000 74:00000000 78:15122500 7C:00000500
v4.4.1:
04:00002020 08:00000000 0C:00004113 10:00000000 14:009000AD 18:00001000 1C:6576C000 20:0800001C 24:82006470 28:000FFFFF 2C:000FFFFF 30:00000000 34:00000000 38:000000F0 3C:1311E000 40:00A00100 44:00000000 48:00186A00 4C:00186A00 50:00001E00 54:0000032B 58:00000088 5C:00038010 60:00300610 64:00000000 68:000FFFFF 6C:000FFFFF 70:00000000 74:00000000 78:15122500 7C:00000500
Finally, I instrumented my interrupt handler to dump some information about the number of characters available in the FIFO before and after I read each available character from the FIFO. I tested this operation with single character transfers and noticed that the rd_addr parameter is incrementing by '1' on each transfer when built with v4.3.1, but the value increments by more than '1' when built under v4.4.1.
The number of bytes available in the FIFO is calculated as follows in the interrupt handler:
The instrumented code dumps the calculated u16NumBytesAvail value plus the value of [UART0.mem_cnt_status.rx_cnt << 8] and the value of [UART0.status.rxfifo_cnt] before and after each character is read from the FIFO. The code also dumps the values of the rd_addr and wr_addr parameters before and after the character is read from the FIFO. The test results are as follows:
I am presuming this is something occurring within the silicon, as the UART0 register set refers to the physical peripheral registers, correct?
Can anyone offer any explanation for this strange behavior of the receive FIFO operation?
Note that I had a thought that perhaps some other driver was loaded and attempting to pull a crazy number of characters from the FIFO before and or after my interrupt handler. I attempted to execute the uart_driver_delete() call prior to calling esp_intr_alloc() to map my handler as below...
Adding this driver delete call had no effect on the erroneous operation of the Rx FIFO.
Best Regards,
Mark
I have been developing with ESP-IDF v4.3.2. Under this version, I have UART communications working flawlessly over both UART0 and UART2.
I recently attempted to upgrade the project to utilize the more recent releases of ESP-IDF. I discovered that the UART receive FIFO operation is no longer working as expected. While the transmit function is working well (and allowing me to dump diagnostic information) the receive operations are fouled up. After much testing of the project builds under different versions of the IDF, I discovered that this apparently crept in with v4.4.x.
My testing focused on UART0 operation and included the use of several dumps of the GPIO and UART configuration registers to determine if I could detect any differences in the configuration of the hardware between v4.3.2 and v4.4.1. I am attempting to utilize UART0 with its default connections for TxD and RxD signals (GPIO1 and GPIO3). I noticed the following changes in the GPIO configuration register values between the two builds:
Code: Select all
GPIO_ENABLE_REG: v4.3.1: 0x0E620FB6 v4.4.1: 0x0E620FB4 (Set GPIO1 as output vs. set GPIO1 as input)
GPIO_FUNC14_IN_SEL_CFG_REG: v4.3.1: 0x00000083 v4.4.1: 0x00000030 (bypass GPIO matrix, connect U0RxD to GPIO3)
GPIO_FUNC1_OUT_SEL_CFG_REG: v4.3.1: 0x0000000E v4.4.1: 0x00000100 (routing U0TxD to GPIO1 vs. routing bit 1 of GPIO_OUT_REG to GPIO1)
IO_MUX_GPIO1_REG: v4.3.1: 0x00002A00 v4.4.1: 0x00000A00 (routing TxD0 through the matrix vs. bypassing the matrix)
IO_MUX_GPIO3_REG: v4.3.1: 0x00002B00 v4.4.1: 0x00000B00 (routing RxD0 through the matrix vs. bypassing the matrix)
The comparison of the UART configuration registers did not yield any significant differences, with the exception that the MEM_RX_STATUS register "rd_addr" parameter was non-zero on the nonworking build under v4.4.1 (register offset 0x60). Here are the dumps of the full register values for each version:
v4.3.1:
04:00002020 08:00000000 0C:00004113 10:00000000 14:009000AD 18:00001000 1C:6678C000 20:0800001C 24:82006470 28:000FFFFF 2C:000FFFFF 30:00000000 34:00000000 38:000000F0 3C:1311E000 40:00A00100 44:00000000 48:00186A00 4C:00186A00 50:00001E00 54:0000032B 58:00000088 5C:00034010 60:00300600 64:00000000 68:000FFFFF 6C:000FFFFF 70:00000000 74:00000000 78:15122500 7C:00000500
v4.4.1:
04:00002020 08:00000000 0C:00004113 10:00000000 14:009000AD 18:00001000 1C:6576C000 20:0800001C 24:82006470 28:000FFFFF 2C:000FFFFF 30:00000000 34:00000000 38:000000F0 3C:1311E000 40:00A00100 44:00000000 48:00186A00 4C:00186A00 50:00001E00 54:0000032B 58:00000088 5C:00038010 60:00300610 64:00000000 68:000FFFFF 6C:000FFFFF 70:00000000 74:00000000 78:15122500 7C:00000500
Finally, I instrumented my interrupt handler to dump some information about the number of characters available in the FIFO before and after I read each available character from the FIFO. I tested this operation with single character transfers and noticed that the rd_addr parameter is incrementing by '1' on each transfer when built with v4.3.1, but the value increments by more than '1' when built under v4.4.1.
The number of bytes available in the FIFO is calculated as follows in the interrupt handler:
Code: Select all
uint16_t u16NumBytesAvail = ( UART0.mem_cnt_status.rx_cnt << 8 ) + UART0.status.rxfifo_cnt;
Code: Select all
expected v4.3.1 build: v4.4.1 build:
u16NumBytesAvail: 1 1 1
UART0.mem_cnt_status.rx_cnt << 8: 0 0 0
UART0.status.rxfifo_cnt: 1 1 0*
UART0.mem_rx_status.rd_addr: 384 384 474*
UART0.mem_rx_status.wr_addr: 385 385 385
Hexadecimal value read from the FIFO: 0x31 0x31 (random)*
UART0.mem_cnt_status.rx_cnt << 8: 0 0 0
UART0.status.rxfifo_cnt: 0 0 0
UART0.mem_rx_status.rd_addr: 385 385 501*
UART0.mem_rx_status.wr_addr: 385 385 385
Can anyone offer any explanation for this strange behavior of the receive FIFO operation?
Note that I had a thought that perhaps some other driver was loaded and attempting to pull a crazy number of characters from the FIFO before and or after my interrupt handler. I attempted to execute the uart_driver_delete() call prior to calling esp_intr_alloc() to map my handler as below...
Code: Select all
uart_driver_delete( UART_NUM_0 );
ret_val = esp_intr_alloc( ETS_UART0_INTR_SOURCE, flags, UartInterruptHandler, &Uart0Params, &Uart0Params.intr_handle );
Best Regards,
Mark