Simultaneous communication on 2 sync libUARTe

Hi.

We are using nRF52833 (on BL653 module) where UART0 and UART1 are used for communication purposes (one with STM MUC and the other with quectel modem). Current solution uses SDK 17.0.2, softdevice and freeRTOS, where async libuarte support is used for uart communication. The main problem is that, from time to time (every couple of minutes), we get a HardFault. But only when both are active. If we disable on of them, the code looks to work as expected.

Currently, the UARTs are defined as (using app_timer):

NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 1, 4, NRF_LIBUARTE_PERIPHERAL_NOT_USED, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 1024, 3);

NRF_LIBUARTE_ASYNC_DEFINE(quectel_libuarte, 0, 3, NRF_LIBUARTE_PERIPHERAL_NOT_USED, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 1024, 3);

We found out that using exact TIMER (TIMER2) works worse as before we used:
NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 1, 4, 2, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 1024, 3);
NRF_LIBUARTE_ASYNC_DEFINE(quectel_libuarte, 0, 3, NRF_LIBUARTE_PERIPHERAL_NOT_USED, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 1024, 3);
So, the first question is which TIMER is preferred to be used for UART when softdevice is present?
And while changing to app_timer made things better, HardFault still occurs. In the docs you can find: "If the TXD.PTR and the RXD.PTR are not pointing to the Data RAM region, an EasyDMA transfer may result in a HardFault or RAM corruption.". What is the best scenario to check whether this is the cause in our case?
Also, do both interfaces share any common shared source (besides easyDMA, which should work with both of them)? For example, should UART1 wait for UART0 to finish anything it does (writing and/or reading)? We are aware that UART can not read and write at the same time. Are we missing something else?
Best regards,
Vojko
  • To elaborate further here is our uarte handler:

    void uarte_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt){
    switch (p_evt->type){
    case NRF_LIBUARTE_ASYNC_EVT_RX_DATA:
    {
    NRF_LOG_ERROR("uarte: EVT_RX - data received");
    BaseType_t yield = pdFALSE;
    BaseType_t sent = errQUEUE_FULL;
    uart_queue_data_t data;
    data.length = p_evt->data.rxtx.length;
    data.p_data = p_evt->data.rxtx.p_data;
    sent = xQueueSendFromISR(stm_uart_rx_queue, &data, &yield);
    if(sent != pdTRUE){
    NRF_LOG_ERROR("uarte: queue full");
    }
    portYIELD_FROM_ISR(yield);
    } break;

    case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
    {
    BaseType_t yield = pdFALSE;
    xEventGroupSetBitsFromISR(stm_uart_tx_event_h, 0x01, &yield);
    portYIELD_FROM_ISR(yield);
    } break;
    case NRF_LIBUARTE_ASYNC_EVT_ERROR:
    NRF_LOG_ERROR("uarte: error %d", p_evt->data.errorsrc);
    break;
    case NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR:
    NRF_LOG_ERROR("uarte: overrun: lost %d", p_evt->data.overrun_err.overrun_length);
    break;
    default:
    NRF_LOG_ERROR("uarte: wrong state");
    break;
    }
    }
    nrf_libuarte_async_rx_free is called in the task fetching data from the queue. UART baudrate is 115200 with hardware flow control disabled:
    nrf_libuarte_async_config_t nrf_libuarte_async_config = {
    .tx_pin = UARTE_TX_PIN,
    .rx_pin = UARTE_RX_PIN,
    .baudrate = NRF_UARTE_BAUDRATE_115200,
    .parity = NRF_UARTE_PARITY_INCLUDED,
    .hwfc = NRF_UARTE_HWFC_DISABLED,
    .timeout_us = 100,
    .int_prio = APP_IRQ_PRIORITY_LOW
    };
  • Just thinking out loud here. Async UART lib is a bit of resource hungry in the sense that it uses TIMER and RTC if inactivity timeout is used. If you are using tw libuarte then you aer using atleast two high resolution timers and maybe two additional RTCs if you are using inactivity timeout for receiver.  Also note that FreeRTOS needs RTC1 (instance is configurable). So it looks like it might be very easy to get into a resource conflict using two libuarte on FreeRTOS. My suggestions are

    1. Disable receiver timeout functionality and make sure RTC is not used in libUARTE. This will avoid any RTC resource conflicts I think might be happening with FreeRTOS RTC instance and your libuarte.
    2. Debug your hardfault first. Get the exact hardfaulting instruction. Maybe what you are seeing is just a stack overflow error caused by under defining the task stack size. 
Related