This *might* be related to my previous post about data corruption / byte ordering in the UART buffer, but I wanted to keep this as a separate, focused question.
I am working on a Modbus RTU slave that communicates with the host via RS485. When I receive a command from the host, I process it and then send back an arbirtrary number of bytes (depending upon the command, according to the Modbus spec). After sending the response to the host, I am currently under the impression that the data is essentially "echoed" back and ends up in the RX FIFO.
I currently flush the RX FIFO immediately after sending the response back to the host to clear any data. The problem is that if my response is larger than the size of the FIFO (8 bytes since I am using UART0), the data in the FIFO is incorrect (extra byte that is not the 9th byte of the sent response packet) and this screws up the next incoming command, as the first byte should be the modbus slave ID.
I used to flush the RX FIFO like this:
while( kStatus_UART_Success == UART_DRV_ReceiveDataBlocking( instance, &rxbuff, 1, 100));
but thought that this was causing the problem. I then went to the following code:
UART_Type *base = g_uartBase[instance]; UART_HAL_DisableReceiver( base); assert( kStatus_UART_Success == UART_HAL_FlushRxFifo( base)); UART_HAL_EnableReceiver( base);
To try to handle the case where the response > 8 bytes, I tried to call this function twice, which did not work. I then modified the above code to loop until the FIFO was empty:
UART_Type *base = g_uartBase[instance]; while( kStatus_UART_Success == (count = UART_HAL_GetRxDatawordCountInFifo( base)) { UART_HAL_DisableReceiver( base); assert( kStatus_UART_Success == UART_HAL_FlushRxFifo( base)); UART_HAL_EnableReceiver( base); }
This didn't help.
How do you all clear the RX FIFO?
Solved! Go to Solution.
Hi,
Please refer UART FIFO validation code below:
/********************************************************************/
/* UART FIFO flush test.
* Tests TXFLUSH and RXFLUSH operation. The TXFLUSH test will load
* bytes into the TxFIFO, then flush the FIFO. Once the FIFO is flushed
* the TCFIFO value is checked to make sure it is zero. Then the FIFO
* is reloaded with new values that are transmitted.
*
* The RXFLUSH test will receive bytes, then flush the FIFO. Once the FIFO
* is flushed the RCFIFO value is check to make sure it is zero. Then a
* new set of data values will be received. Data values are checked to make
* sure they match the second data set and the first data set that was
* flushed is completely gone.
*
* If all receive data values match expected values and TCFIFO and RCFIFO
* checks also match the expected values, then the test returns 0 (pass).
* Otherwise the function returns the number of errors.
*/
int uart_fifo_flush_test()
{
UART_MemMapPtr tx_module, rx_module;
char ch;
int error = 0;
uint32 i;
uint8 temp;
printf("\n\nStarting setup for UART FIFO flush tests.\n");
/* Test always uses UART0 as the transmitter since it needs a
* UART with a FIFO. A variable is still being used so that this
* code can be ported to other devices that might support FIFOs
* on more or other UARTs more easily.
*/
tx_module = UART0_BASE_PTR;
/* Test always uses UART1 as the receiver since it needs a
* UART with a FIFO. A variable is still being used so that this
* code can be ported to other devices that might support FIFOs
* on more or other UARTs more easily.
*/
rx_module = UART1_BASE_PTR;
/* Give directions on the connections that need to be made for the test */
printf("\n\nMake the following connections on a MARCONI-144 CPU card:\n\n");
printf("Connect J29 pin 8 (UART0_TX) to J24 pin 11 (UART1_RX)\n");
printf("\nPress any key when ready.\n");
ch = in_char();
printf("Setup complete. Starting UART FIFO flush tests...\n");
/* Enable the FIFOs */
UART_PFIFO_REG(tx_module) |= UART_PFIFO_TXFE_MASK;
UART_PFIFO_REG(rx_module) |= UART_PFIFO_RXFE_MASK;
/* Temporarily disable the transmitter so that the TxFIFO can be
* filled without sending any of the data out yet.
*/
UART_C2_REG(tx_module) &= ~UART_C2_TE_MASK;
/* Loop to fill the entire TxFIFO */
for( i=1; i < 9; i++)
{
/* Write data into the FIFO */
UART_D_REG(tx_module) = i;
}
/* Test to make sure TCFIFO is 8 (FIFO full) */
if ( UART_TCFIFO_REG(tx_module) != 8)
{
error++;
printf("\nERR! TCFIFO value is incorrect. Expected: 0x8 Read: 0x%02X", UART_TCFIFO_REG(tx_module));
}
/* Flush the TxFIFO */
UART_CFIFO_REG(tx_module) |= UART_CFIFO_TXFLUSH_MASK;
/* Test to make sure TCFIFO is 0 now (FIFO flushed) */
if ( UART_TCFIFO_REG(tx_module) != 0)
{
error++;
printf("\nERR! TCFIFO value is incorrect. Expected: 0x0 Read: 0x%02X", UART_TCFIFO_REG(tx_module));
}
/* Loop to fill the entire TxFIFO with a new data set */
for( i=0x11; i < 0x19; i++)
{
/* Write data into the FIFO */
UART_D_REG(tx_module) = i;
}
/* Set the Rx watermark to 8 so that we can detect when the transmit is complete */
UART_RWFIFO_REG(rx_module) = 8;
/* Now re-enable the transmitter. This should cause all 8 bytes to transmit
* back to back.
*/
UART_C2_REG(tx_module) |= UART_C2_TE_MASK;
/* Wait for RDRF flag to set indicating transmit is complete */
while( !(UART_S1_REG(rx_module) & UART_S1_RDRF_MASK));
/* Test to make sure RCFIFO is 8 (FIFO full) */
if ( UART_RCFIFO_REG(rx_module) != 8)
{
error++;
printf("\nERR! RCFIFO value is incorrect. Expected: 0x8 Read: 0x%02X", UART_RCFIFO_REG(rx_module));
}
/* Flush the RxFIFO */
UART_CFIFO_REG(rx_module) |= UART_CFIFO_RXFLUSH_MASK;
/* Test to make sure RCFIFO is 0 now (FIFO flushed) */
if ( UART_RCFIFO_REG(rx_module) != 0)
{
error++;
printf("\nERR! RCFIFO value is incorrect. Expected: 0x0 Read: 0x%02X", UART_RCFIFO_REG(rx_module));
}
/* Clear the RDRF flag - flushing the FIFO won't cause the flag to clear */
temp = UART_S1_REG(rx_module);
ch = UART_D_REG(rx_module);
/* Flush the FIFO again to reset the RxFIFO pointers */
UART_CFIFO_REG(rx_module) |= UART_CFIFO_RXFLUSH_MASK;
/* Temporarily disable the transmitter so that the TxFIFO can be
* filled without sending any of the data out yet.
*/
UART_C2_REG(tx_module) &= ~UART_C2_TE_MASK;
/* Loop to fill the entire TxFIFO with a new data set (third set) */
for( i=0x21; i < 0x29; i++)
{
/* Write data into the FIFO */
UART_D_REG(tx_module) = i;
}
/* Re-enable the transmitter so data will be sent out. */
UART_C2_REG(tx_module) |= UART_C2_TE_MASK;
/* Wait for RDRF flag to set indicating transmit is complete */
while( !(UART_S1_REG(rx_module) & UART_S1_RDRF_MASK));
/* Loop to empty the entire RxFIFO and make sure the FIFO flush hasn't
* had any permanent effect.
*/
for( i=1; i < 9; i++)
{
/* Read data from the FIFO */
ch = UART_D_REG(rx_module);
/* Test the data value to make sure it matches the expected value */
if (ch != (i+0x20))
{
error++;
printf("\nERR! Incorrect data value received. Expected: 0x%02X Read: 0x%02X", (i+0x20), ch);
}
/* Test RCFIFO value to make sure it decremented */
if (UART_RCFIFO_REG(rx_module) != (8 - i))
{
error++;
printf("\nERR! RCFIFO value is incorrect. Expected: 0x%02X Read: 0x%02X", (8-i), UART_RCFIFO_REG(rx_module));
}
}
/* Disable the FIFOs */
UART_PFIFO_REG(tx_module) &= ~UART_PFIFO_TXFE_MASK;
UART_PFIFO_REG(rx_module) &= ~UART_PFIFO_RXFE_MASK;
/* Clear the Rx watermark */
UART_RWFIFO_REG(rx_module) = 0;
return error;
}
It is a bare-metal project without using any driver and only with register level operation.
Flush the RxFIFO doesn't clear the UART0_S1[RDRF] flag, it need clear the RDRF flag manually.
Then it need flush the RxFIFO again to reset the RxFIFO pointer.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
Please refer UART FIFO validation code below:
/********************************************************************/
/* UART FIFO flush test.
* Tests TXFLUSH and RXFLUSH operation. The TXFLUSH test will load
* bytes into the TxFIFO, then flush the FIFO. Once the FIFO is flushed
* the TCFIFO value is checked to make sure it is zero. Then the FIFO
* is reloaded with new values that are transmitted.
*
* The RXFLUSH test will receive bytes, then flush the FIFO. Once the FIFO
* is flushed the RCFIFO value is check to make sure it is zero. Then a
* new set of data values will be received. Data values are checked to make
* sure they match the second data set and the first data set that was
* flushed is completely gone.
*
* If all receive data values match expected values and TCFIFO and RCFIFO
* checks also match the expected values, then the test returns 0 (pass).
* Otherwise the function returns the number of errors.
*/
int uart_fifo_flush_test()
{
UART_MemMapPtr tx_module, rx_module;
char ch;
int error = 0;
uint32 i;
uint8 temp;
printf("\n\nStarting setup for UART FIFO flush tests.\n");
/* Test always uses UART0 as the transmitter since it needs a
* UART with a FIFO. A variable is still being used so that this
* code can be ported to other devices that might support FIFOs
* on more or other UARTs more easily.
*/
tx_module = UART0_BASE_PTR;
/* Test always uses UART1 as the receiver since it needs a
* UART with a FIFO. A variable is still being used so that this
* code can be ported to other devices that might support FIFOs
* on more or other UARTs more easily.
*/
rx_module = UART1_BASE_PTR;
/* Give directions on the connections that need to be made for the test */
printf("\n\nMake the following connections on a MARCONI-144 CPU card:\n\n");
printf("Connect J29 pin 8 (UART0_TX) to J24 pin 11 (UART1_RX)\n");
printf("\nPress any key when ready.\n");
ch = in_char();
printf("Setup complete. Starting UART FIFO flush tests...\n");
/* Enable the FIFOs */
UART_PFIFO_REG(tx_module) |= UART_PFIFO_TXFE_MASK;
UART_PFIFO_REG(rx_module) |= UART_PFIFO_RXFE_MASK;
/* Temporarily disable the transmitter so that the TxFIFO can be
* filled without sending any of the data out yet.
*/
UART_C2_REG(tx_module) &= ~UART_C2_TE_MASK;
/* Loop to fill the entire TxFIFO */
for( i=1; i < 9; i++)
{
/* Write data into the FIFO */
UART_D_REG(tx_module) = i;
}
/* Test to make sure TCFIFO is 8 (FIFO full) */
if ( UART_TCFIFO_REG(tx_module) != 8)
{
error++;
printf("\nERR! TCFIFO value is incorrect. Expected: 0x8 Read: 0x%02X", UART_TCFIFO_REG(tx_module));
}
/* Flush the TxFIFO */
UART_CFIFO_REG(tx_module) |= UART_CFIFO_TXFLUSH_MASK;
/* Test to make sure TCFIFO is 0 now (FIFO flushed) */
if ( UART_TCFIFO_REG(tx_module) != 0)
{
error++;
printf("\nERR! TCFIFO value is incorrect. Expected: 0x0 Read: 0x%02X", UART_TCFIFO_REG(tx_module));
}
/* Loop to fill the entire TxFIFO with a new data set */
for( i=0x11; i < 0x19; i++)
{
/* Write data into the FIFO */
UART_D_REG(tx_module) = i;
}
/* Set the Rx watermark to 8 so that we can detect when the transmit is complete */
UART_RWFIFO_REG(rx_module) = 8;
/* Now re-enable the transmitter. This should cause all 8 bytes to transmit
* back to back.
*/
UART_C2_REG(tx_module) |= UART_C2_TE_MASK;
/* Wait for RDRF flag to set indicating transmit is complete */
while( !(UART_S1_REG(rx_module) & UART_S1_RDRF_MASK));
/* Test to make sure RCFIFO is 8 (FIFO full) */
if ( UART_RCFIFO_REG(rx_module) != 8)
{
error++;
printf("\nERR! RCFIFO value is incorrect. Expected: 0x8 Read: 0x%02X", UART_RCFIFO_REG(rx_module));
}
/* Flush the RxFIFO */
UART_CFIFO_REG(rx_module) |= UART_CFIFO_RXFLUSH_MASK;
/* Test to make sure RCFIFO is 0 now (FIFO flushed) */
if ( UART_RCFIFO_REG(rx_module) != 0)
{
error++;
printf("\nERR! RCFIFO value is incorrect. Expected: 0x0 Read: 0x%02X", UART_RCFIFO_REG(rx_module));
}
/* Clear the RDRF flag - flushing the FIFO won't cause the flag to clear */
temp = UART_S1_REG(rx_module);
ch = UART_D_REG(rx_module);
/* Flush the FIFO again to reset the RxFIFO pointers */
UART_CFIFO_REG(rx_module) |= UART_CFIFO_RXFLUSH_MASK;
/* Temporarily disable the transmitter so that the TxFIFO can be
* filled without sending any of the data out yet.
*/
UART_C2_REG(tx_module) &= ~UART_C2_TE_MASK;
/* Loop to fill the entire TxFIFO with a new data set (third set) */
for( i=0x21; i < 0x29; i++)
{
/* Write data into the FIFO */
UART_D_REG(tx_module) = i;
}
/* Re-enable the transmitter so data will be sent out. */
UART_C2_REG(tx_module) |= UART_C2_TE_MASK;
/* Wait for RDRF flag to set indicating transmit is complete */
while( !(UART_S1_REG(rx_module) & UART_S1_RDRF_MASK));
/* Loop to empty the entire RxFIFO and make sure the FIFO flush hasn't
* had any permanent effect.
*/
for( i=1; i < 9; i++)
{
/* Read data from the FIFO */
ch = UART_D_REG(rx_module);
/* Test the data value to make sure it matches the expected value */
if (ch != (i+0x20))
{
error++;
printf("\nERR! Incorrect data value received. Expected: 0x%02X Read: 0x%02X", (i+0x20), ch);
}
/* Test RCFIFO value to make sure it decremented */
if (UART_RCFIFO_REG(rx_module) != (8 - i))
{
error++;
printf("\nERR! RCFIFO value is incorrect. Expected: 0x%02X Read: 0x%02X", (8-i), UART_RCFIFO_REG(rx_module));
}
}
/* Disable the FIFOs */
UART_PFIFO_REG(tx_module) &= ~UART_PFIFO_TXFE_MASK;
UART_PFIFO_REG(rx_module) &= ~UART_PFIFO_RXFE_MASK;
/* Clear the Rx watermark */
UART_RWFIFO_REG(rx_module) = 0;
return error;
}
It is a bare-metal project without using any driver and only with register level operation.
Flush the RxFIFO doesn't clear the UART0_S1[RDRF] flag, it need clear the RDRF flag manually.
Then it need flush the RxFIFO again to reset the RxFIFO pointer.
Wish it helps.
Have a great day,
Ma Hui
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
So far, this is the only approach I have tested that actually properly clears the FIFO.
bmwhui could you please take a look at my other post UART_DRV_ReadDataBlocking seems to allow FIFO data to be lost ? I am experiencing weird behavior with the UART SDK function. Thank you!
bmwhui thanks for your reply. I'm going to give this a try because I seem to be having issues with my approach.
Hi Dave
I won't attempt to answer the question about FIFOs and the other data corruption issue but instead suggest that you disable the Rx when transmitting data, since this will supress any echos, which looks to be the trigger of the other complications.
Regards
Mark
Yeah, I have already done that, but was thinking it's kind of an unfortunate hack. However, if you're saying this, it must be a complicated problem to fix. :smileyhappy: