This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

UART max 80 bytes on receive is possible

Hi,

got a question about UART and maximum bytes it can receive in one burst or "packet".

Using nRF52382 and SDK16.

Recently I've been developing a new app in which UART baudrate needs to be 576000. Everything is set and Rx/Tx works. Legacy mode is turned off so only easy dma is enabled in the driver.

When nRF needs to receive more than 30 bytes problems occur and APP_UART_COMMUNICATION_ERROR with code 1 keeps turning up. I've enabled hardware control for test and nRF is able to receive exactly 80 bytes correctly. If I send 81 bytes, I loose the last byte, if I send 82 bytes I loose the last 2 bytes and so on. UART FIFO is set at 256 bytes for both Rx and Tx.

 Is 80 bytes some theoretical limit or is it defined somewhere in the sdk? When hardware flow is enabled I don't get APP_UART_COMMUNICATION_ERRORs, but bytes are still missing. Anyone knows why?

And 2 bonus questions.

1.) Is libuarte really only option for faster UART and can it solve the problem above?

2.) Where to start if I wish to implement my own UART driver?

Thanks!

  • Okay~

    I don't think that the bug is the HW/FW bug of SDK16 or SOC. Because I had done UART RX more than 128 bytes before(115200bps). I wonder that the possible case is the RX data format from your side. From your  uart_process()  function in while loop, it get the uart rx data fifo untile the data is zero. 

                if (uartWorker.byteIndex < UART_BUFFER_SIZE)
                {
                    uartWorker.buffer[uartWorker.byteIndex] = uartWorker.byte;
                    uartWorker.byteIndex++;
                }

                if (uartWorker.byte == 0)
                {

    Here. But if the 81th byte is zero and over 82 bytes are valid. Your data fifo will be 80 bytes only. So another way, you may check the TX data from your test pattern.

  • This is COBS, you put N bytes in Encode and get out N+3 bytes, last byte being 0 which marks the end of the packet. You can adapt COBS to your needs but 0 always marks start and/or end of the packet, in my case it marks the end.

    I've checked encoding function, I've checked the data in debug and with the oscilloscope and it's valid. Wasted few days on this actually.

    I will also check apply_old_config, maybe I've missed something!

  • If it's the COBS encode, I think it will never be zero until end of fifo. I agree the suggestion of Edvin.

    You may check the 0x480 (ERRORSRC) in your handle function. Maybe it's the overrun issue (TX signal issue) in this case.

  • "If it's the COBS encode, I think it will never be zero until end of fifo."

    Yes, it will never be zero until end of packet(not fifo!), but packet can be 40 bytes and everything works, go to 60 bytes, everything works, give it 80 bytes, works. Now give it 81 bytes, and 81st is lost!

    Yes, it's a overrun issue but why? I can see all the data in oscilloscope, I'm using FTDI cable to send data, everything is there, valid. FIFO size is 256 bytes for both Rx and Tx.

    Still looking...

  • Hello,

    Please note that we have an "insert" -> "code" for inserting code snippets. It is easier to read if the code snippets are long, because it maintains the formatting.

    My concern is:

            case APP_UART_DATA_READY:
            {
    
            } break;

    which does nothing.In itself, this should be fine as long as your fifo buffer is large enough (larger than 80 bytes), but I don't know how you set up your project. 

    What I believe is confusing you is the app_uart_fifo and the uart peripheral driver. These are not the same thing. The app_uart_fifo is the library that pulls data from the uart peripheral. Do you use app_uart_fifo.c in your project? If so, look at what is generating the APP_UART_DATA_READY event inside app_uart_fifo.c:

    static void uart_event_handler(nrf_drv_uart_event_t * p_event, void* p_context)
    {
        app_uart_evt_t app_uart_event;
        uint32_t err_code;
    
        switch (p_event->type)
        {
            case NRF_DRV_UART_EVT_RX_DONE:
                // If 0, then this is a RXTO event with no new bytes.
                if(p_event->data.rxtx.bytes == 0)
                {
                   // A new start RX is needed to continue to receive data
                   (void)nrf_drv_uart_rx(&app_uart_inst, rx_buffer, 1);
                   break;
                }
    
                // Write received byte to FIFO.
                err_code = app_fifo_put(&m_rx_fifo, p_event->data.rxtx.p_data[0]);
                if (err_code != NRF_SUCCESS)
                {
                    app_uart_event.evt_type          = APP_UART_FIFO_ERROR;
                    app_uart_event.data.error_code   = err_code;
                    m_event_handler(&app_uart_event);
                }
                // Notify that there are data available.
                else if (FIFO_LENGTH(m_rx_fifo) != 0)
                {
                    app_uart_event.evt_type = APP_UART_DATA_READY;
                    m_event_handler(&app_uart_event);
                }
    
                // Start new RX if size in buffer.
                if (FIFO_LENGTH(m_rx_fifo) <= m_rx_fifo.buf_size_mask)
                {
                    (void)nrf_drv_uart_rx(&app_uart_inst, rx_buffer, 1);
                }
                else
                {
                    // Overflow in RX FIFO.
                    m_rx_ovf = true;
                }
    
                break;
    
            case NRF_DRV_UART_EVT_ERROR:
                app_uart_event.evt_type                 = APP_UART_COMMUNICATION_ERROR;
                app_uart_event.data.error_communication = p_event->data.error.error_mask;
                (void)nrf_drv_uart_rx(&app_uart_inst, rx_buffer, 1);
                m_event_handler(&app_uart_event);
                break;
    
            case NRF_DRV_UART_EVT_TX_DONE:
                // Get next byte from FIFO.
                if (app_fifo_get(&m_tx_fifo, tx_buffer) == NRF_SUCCESS)
                {
                    (void)nrf_drv_uart_tx(&app_uart_inst, tx_buffer, 1);
                }
                else
                {
                    // Last byte from FIFO transmitted, notify the application.
                    app_uart_event.evt_type = APP_UART_TX_EMPTY;
                    m_event_handler(&app_uart_event);
                }
                break;
    
            default:
                break;
        }
    }

    Does that function look exactly like this in your case? And is it being used?

    And for context, you say that the 81st byte is missing. Where do you read your bytes? 

    The function process_uart() with the empty APP_UART_DATA_READY: event handler. Where is it called from?

    Just a shot in the dark: Have you tried the ble_app_uart example from the SDK? Do you see the same behavior there if you don't modify anything?

    BR,

    Edvin

Related