Issue with UART RX data transmission at high baud rates

I am facing an issue with UART communication at high baud rates. The transmission of data from the transmitting device (TX) to the receiving device (RX) works fine, but when the baud rate is increased beyond a certain threshold, I observe that the RX data transmission is not working as expected. Specifically, I am seeing that the received data is incorrect, and there are missing bytes in the received data stream.

Code: Here is the initialization code for the UART communication:

ret_code_t uartInit(nrf_uarte_baudrate_t baud_rate)
{
        nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;
        config.pseltxd = BG_TX_PIN;
        config.pselrxd = BG_RX_PIN;
        config.hwfc = NRF_UART_HWFC_DISABLED;
        config.parity = NRF_UART_PARITY_EXCLUDED;
        config.baudrate = baud_rate;
        config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
        uint32_t err_code = nrf_drv_uart_init(&uart_nrf, &config, uart_event_handle);

    }
}

Reproduction steps:

  1. Initialize UART communication as shown above.
  2. Transmit data from the TX device at high baud rates (e.g. 921600 bps).
  3. Observe that the RX data transmission is incorrect and missing bytes.

SDK: 17.1 
IDE : Segger Embedded Studio

I am using an NRF52840 microcontroller and a BG95 modem for UART communication. The issue is observed when the baud rate is increased beyond 921600 bps. The TX data transmission is working fine, but the RX data transmission is not reliable.

I would appreciate any insights or suggestions on how to resolve this issue. Thank you.

Parents
  • Hi,

    It is more interesting to see how you start the UART RX than how you initialized the driver. If you call nrf_drv_uart_rx() with a low value in the length parameter, you will struggle to handle the interrupts fast enough to provide a new buffer to store the received data, when HW flow control is disabled. The UARTE HW has a RX FIFO, but this can only hold 4 bytes. 

    If your connected device cannot support HW flow control pins, I would recommend you to consider using the libUARTE library in your application. This handles multiple RX buffers for you at a configurable length, along with RX timeouts for notifying application of received data before the whole buffer have been filled. The nRF52840 can support up to 65535 byte receptions directly to RAM when using the UARTE peripheral with EasyDMA.

    Best regards,
    Jørgen

  • See the Libuarte Example. I also created an example showing how it can be used in a BLE example in this post.

  • Hi after Implementing this lib still facing the same Issue

  • Please post more details about how you configured libUARTE, and what exact issues you are currently experiencing.

  • Issue facing in Reading data from BG95 at all baud rates

    1. At 115200 baud rate, Tx is fine but at Rx 15+ packets found corrupted out of 140 packets
    2. At 460800 baud rate, Tx is fine but at Rx 56+ packets corrupted out of 140 Packets
    3. At 921600 baud rate, Tx is fine but at Rx corruption of data is higher, command response’s are getting corrupted

    libUARTE Integartion:

    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        ret_code_t ret;
    
        switch (p_evt->type)
        {
            case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                uart_rx_done = true;
                if (p_evt->data.rxtx.length <= sizeof(data_array)) {
                    memset(data_array, 0x00, sizeof(data_array));
                    memcpy(data_array, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                    data_len = p_evt->data.rxtx.length;
                }
                //print(LL_INFO, "len:%d - data: %s\n", p_evt->data.rxtx.length, data_array);
                break;
            case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                //NRF_LOG_RAW_INFO("Tx!\n");
                    /*nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                    if (!nrf_queue_is_empty(&m_buf_queue))
                    {
                        buffer_t buf;
                        ret = nrf_queue_pop(&m_buf_queue, &buf);
                        APP_ERROR_CHECK(ret);
                        UNUSED_RETURN_VALUE(nrf_libuarte_async_tx(p_libuarte, buf.p_data, buf.length));
                    }*/
                break;
             default:
                print(LL_INFO, "\nUE:%d\n\n", (int)p_evt->type);
                break;
        }
    }

Reply
  • Issue facing in Reading data from BG95 at all baud rates

    1. At 115200 baud rate, Tx is fine but at Rx 15+ packets found corrupted out of 140 packets
    2. At 460800 baud rate, Tx is fine but at Rx 56+ packets corrupted out of 140 Packets
    3. At 921600 baud rate, Tx is fine but at Rx corruption of data is higher, command response’s are getting corrupted

    libUARTE Integartion:

    void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
    {
        nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
        ret_code_t ret;
    
        switch (p_evt->type)
        {
            case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
                uart_rx_done = true;
                if (p_evt->data.rxtx.length <= sizeof(data_array)) {
                    memset(data_array, 0x00, sizeof(data_array));
                    memcpy(data_array, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                    data_len = p_evt->data.rxtx.length;
                }
                //print(LL_INFO, "len:%d - data: %s\n", p_evt->data.rxtx.length, data_array);
                break;
            case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
                //NRF_LOG_RAW_INFO("Tx!\n");
                    /*nrf_libuarte_async_rx_free(p_libuarte, p_evt->data.rxtx.p_data, p_evt->data.rxtx.length);
                    if (!nrf_queue_is_empty(&m_buf_queue))
                    {
                        buffer_t buf;
                        ret = nrf_queue_pop(&m_buf_queue, &buf);
                        APP_ERROR_CHECK(ret);
                        UNUSED_RETURN_VALUE(nrf_libuarte_async_tx(p_libuarte, buf.p_data, buf.length));
                    }*/
                break;
             default:
                print(LL_INFO, "\nUE:%d\n\n", (int)p_evt->type);
                break;
        }
    }

Children
  • ret_code_t uartInit(nrf_uarte_baudrate_t baud_rate)
    {
    ret_code_t err_code = NRF_SUCCESS;
    
    if (uartAlreadyInit == 0) {
    nrf_libuarte_async_config_t config;
    config.tx_pin = BG_TX_PIN;
    config.rx_pin = BG_RX_PIN;
    config.baudrate = baud_rate;
    config.parity = NRF_UARTE_PARITY_EXCLUDED;
    config.hwfc = NRF_UARTE_HWFC_DISABLED;
    config.timeout_us = 100000;
    config.int_prio = APP_IRQ_PRIORITY_LOW;
    
    err_code = nrf_libuarte_async_init(&libuarte, &config, uart_event_handler, (void *)&libuarte);
    nrf_libuarte_async_enable(&libuarte);
    uartAlreadyInit = 1;
    }
    
    return err_code;
    }

  • Where are you freeing the RX buffer? If you do not free the RX buffers fast enough, libUARTE will eventually not have any new buffers to assign to the UARTE peripheral, preventing it from receiving more data. If you have a very high baudrate and do lots of processing on the incoming data before the buffer can be freed, you should consider increasing the number of or size of buffers for libUARTE (see NRF_LIBUARTE_ASYNC_DEFINE()).

Related