nRF51822 uart flow control


I am using nrf starter kit and nRF51822 DK modules atached. I'm using external usb-com uart modules (based on FT232 chips) for communication with PC (Win7) and hyper terminal clients for data send/receive. Currently I'm experimenting with modified gazell example project to include data received from uart and to transfer between modules as in com cable replacement setup. If I connect usb-com modules directly with each other (thus error free communication) and set baudrate 921600bps, I can transfer data at aproximately 890kpbs transfer rate (using zmodem file transfer). Now i'm trying to include radio transfer in data path. Uart is configured with hardware flow control, uart module on nrf51 is configured on high priority with extended buffering (fifo like size of 1kB) and aditional checking for receive buffer usage to stop and start RX transfers. Uart Error interrupt is enabled and i'm getting several errors representing Buffer overflow during large data chunk receive (3-15kB in size). I'm guessing that hardware flow control is not quick enough to prevent RX register overwriting. Another issue is stopping RX transfer without data loss. I'm thinking that it could be possible to use aditional I/O for RTS/CTS manual control together with uart hardware to pause Rx transfers correctly. What solutions could be usable to correct flow control not lowering baudrate? as this is the basis of transportation layer for later tasks.

  • Beware that there is a bug in the nrf51_bitfields.h file, in that the value for 921600 baud rate is incorrect. It should therefore not be used, and if you do, the actual baud rate might be different from expected. See this question for information on baud rate calculation. Does using a somewhat different baud rate help on this problem?

    If not, this could also be due to the peer device not reacting quick enough when RTS is deasserted, and by that overflowing the buffer. This is a problem that I believe has been seen internally. The upcoming, new chip revision therefore features a six-byte buffer to alleviate this. It could therefore also be worth it to try getting hold of this revision and test whether you see different behavior. Please contact the sales manager for your area for more information on this. If you don't have his contact information, please send me a private message with your location.

  • The latest app_uart_fifo file (included in the SDK 9) contains a bug. 3 bytes where systematically lost (even with HFC) because of a bug in the UART0_IRQHandler function.

    Be sure that the in the UART0_IRQHandler function you check that the RX FIFO is not full before reading the RXD register or some bytes will be lost !

    if (FIFO_LENGTH(m_rx_fifo) <= m_rx_fifo.buf_size_mask)
        err_code = app_fifo_put(&m_rx_fifo, (uint8_t) NRF_UART0->RXD);
        // ...

    I successfully transferred a 2MB file over a UART link (115'200 bauds) without any error, using the new chip revision with the six-byte buffer.

  • I have tested your fix and it worked for me too. I have to include this in the known bugs of SDK 9.0

  • FYI, the RXD register is not any more read each time the UART0 ISR occurs. To avoid deadlock and to resume to UART stream (to active the CTS again), the app_uart_get function must also be updated: the RXD register must be read if an overflow occurs.

    I am not sure if my patch is the best solution, but now you are aware of this bug. Thank you @Aryan to add it on the list.

  • yes, i see that it is not the best solution and has opened up ways to deadlock the reads. I think the best solution is along with your fix, we should add below

    whenever app_fifo_get is called, if the fifo was full, empty one slot to user byte address. Then read the EVENTS_RXDRDY status, and if set, new read on RXD and clear RXRDY event. This will make sure that the last ignored read will be done here.

    Also the clearing of event should be done like this inside UART0_IRQHandler

    if (FIFO_LENGTH(m_rx_fifo) <= m_rx_fifo.buf_size_mask)
        err_code = app_fifo_put(&m_rx_fifo, (uint8_t) NRF_UART0->RXD);
        // Clear UART RX event flag
        NRF_UART0->EVENTS_RXDRDY = 0;