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!

  • Is 80 bytes some theoretical limit or is it defined somewhere in the sdk?

     No. It shouldn't be. As you may already have checked, the APP_UART_COMMUNICATION_ERROR with code 1 means OVERRUN:

    (screenshot from infocenter)

    How have you set up your UART? Do you have an event handler that handles the incoming bytes? Do you use the app_uart_fifo.c? If so, do you call nrf_drv_uart_rx() in the NRF_DRV_UART_ET_RX_DONE event?

    Remember that the UART FIFO is a separate buffer, reading from the UART peripheral. 

    Is there some way for me to reproduce this on an nRF52DK? How do you send your data?

    BR,
    Edvin

  • Hi Edvin,

    thanks for replaying.

    This is the uart init function:

    void UART_Initialize(void)
    {
        uint32_t err_code;
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no    = UART_RX_PIN,
            .tx_pin_no    = UART_TX_PIN,
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity   = false,
            .baud_rate    = UART_BAUDRATE_BAUDRATE_Baud250000
        };

        APP_UART_FIFO_INIT(&comm_params, UART_BUFFER_SIZE, UART_BUFFER_SIZE, uart_event_handle, UART_PRIORITY, err_code);
        APP_ERROR_CHECK(err_code);
    }

    UART_BUFFER_SIZE = 256

    UART_PRIORITY = APP_IRQ_PRIORITY_HIGHEST // Tried every possible option

    #define UART_EASY_DMA_SUPPORT 1

    #define UART_LEGACY_SUPPORT 0

    This is how I process Rx data, this function is called in main.c, in the main while(1) loop(UART_BUFFER_SIZE = 512):

    static void process_uart(void)
    {
        if (!uartWorker.enabled)
        {
            return;
        }

        if (uartWorker.bleBufferAvailable)
        {
            if (app_uart_get(&uartWorker.byte) == NRF_SUCCESS)
            {
                BOARD_LedRxOn();
                //NRF_LOG_INFO("Rx: %d", uartWorker.byte);

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

                if (uartWorker.byte == 0)
                {

    #ifdef PRINT_UART_COMM
                    NRF_LOG_INFO("-> BLE(1): %d", uartWorker.byteIndex);
                    NRF_LOG_HEXDUMP_INFO(uartWorker.buffer, uartWorker.byteIndex);
    #endif
                    if (dongleInfo.verified)
                    {
                        uartWorker.bleBufferAvailable = ble_rws_try_to_send(&m_rws, uartWorker.buffer, &uartWorker.byteIndex);
                        if (uartWorker.bleBufferAvailable)
                        {
                            NRF_LOG_INFO("-> BLE(1) SENT");
                            uartWorker.byteIndex = 0;
                        }
                    }
                    else
                    {
                        uartWorker.byteIndex = 0;
                    }
                }
            }
        }

        if (uartWorker.txComplete)
        {

    #ifdef PRINT_UART_COMM
            NRF_LOG_INFO("-> BLE(2)");
            NRF_LOG_HEXDUMP_INFO(uartWorker.buffer, uartWorker.byteIndex);
    #endif

            if (dongleInfo.verified)
            {
                uartWorker.txComplete = 0;
                uartWorker.bleBufferAvailable = ble_rws_try_to_send(&m_rws, uartWorker.buffer, &uartWorker.byteIndex);
                if (uartWorker.bleBufferAvailable)
                {
                    NRF_LOG_INFO("-> BLE(2) SENT");
                    uartWorker.byteIndex = 0;
                }
            }
        }
    }

    I don't use NRF_DRV_UART_ET_RX_DONE. My uart event handling function does not do much:

    void uart_event_handle(app_uart_evt_t * p_event)
    {
        switch (p_event->evt_type)
        {
            case APP_UART_DATA_READY:
            {

            } break;

            case APP_UART_COMMUNICATION_ERROR:
            {
                NRF_LOG_ERROR("APP_UART_COMMUNICATION_ERROR");// | Code: 0x%x", p_event->data.error_code);
                uartWorker.byteIndex = 0;
            } break;

            case APP_UART_FIFO_ERROR:
            {
                NRF_LOG_ERROR("APP_UART_FIFO_ERROR");
                uartWorker.byteIndex = 0;
            } break;
                
            default:
            {
            
            } break;
        }
    }

    Pretty much no matter how I configure the UART it's the same behaviour.

    BAUDRATE: 115200 & 250000 -> Maximum 80 bytes is received correctly and printed in:

    NRF_LOG_INFO("-> BLE(1): %d", uartWorker.byteIndex);

    NRF_LOG_HEXDUMP_INFO(uartWorker.buffer, uartWorker.byteIndex);

    If I send 81 bytes, 81st is lost, send 82, last 2 are lost.

    For baudrate 576000 this is 34. So if I send 36 bytes, I loose last 2.

    Please do take in account I've also implemented libuarte, the only difference is that now I can receive 80 bytes on baudrate of 576000.

    You should be able to get this behavior from default ble_app_uart example since my UART implementation is the same as it is there. I can always send you my entire project.

    This is the code we're using for a looong time, problem occurred when our custom device sent more than 34 bytes on UART and nRF didn't get it. I've developed a small UART app for windows so now we're testing with that.

    Please try with ble_app_uart, if there are no problems I will send you my entire project. I'm still looking for an error in my project and debugging, but I can't find nothing obvious especially since libuarte is also behaving the same.

    Thanks!

  • What's your process_uart() purpose?

    Why don't you receive the data fifo from uart_event_handle()?

    It's must be something wrong, when you get uart data in  process_uart() .

    Normally it's handle in event (interrupt). 

    You may try the following example.

    void uart_event_handle(app_uart_evt_t * p_event)
    {
    static uint8_t data_array[256];
    static uint8_t uartWorker.byteIndex = 0;

    switch (p_event->evt_type)
    {
    /**@snippet [Handling data from UART] */
    case APP_UART_DATA_READY:
    //UNUSED_VARIABLE(app_uart_get(&data_array[uartWorker.byteIndex]));
    app_uart_get(&data_array[uartWorker.byteIndex]);
     uartWorker.byteIndex++;

    if ((data_array[uartWorker.byteIndex - 1] == '\n') || (uartWorker.byteIndex >=UART_BUFFER_SIZE ))
    {
    data_array[uartWorker.byteIndex]=0;
     uartWorker.byteIndex = 0;
    memcpy(uartWorker.buffer,data_array,sizeof(data_array));
    }
    break;
    /**@snippet [Handling data from UART] */
    case APP_UART_COMMUNICATION_ERROR:
    APP_ERROR_HANDLER(p_event->data.error_communication);
    break;

    case APP_UART_FIFO_ERROR:
    APP_ERROR_HANDLER(p_event->data.error_code);
    break;

    default:
    break;
    }
    }

    Good luck!

  • Hi,

    uart_process() function only transfers receiving the data into while loop. According to my testing handling it in while loop makes the receiving data more stable, basically without errors in receiving. At least till now...

    I already tried handling it similar like you mentioned, behaves the same. I will try again, perhaps I missed something the first time I tried.

    I believe there is an error on my side, obviously, but what confuses me that I also get the same behavior using libuarte and with libuarte I'm handling the data in libuarte event handler (uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)) with same results.

    So any way I go I get to this 80 bytes max in a single burst which makes this UART unusable for our use case. I wish I defined 80 somewhere but I didn't. Very weird behavior.

Related