Best aproach to share/switch a UART?

Hi there, right now I'm working with an application that allows me to collect data via UART from several sensors (two), and I also I have a SIM module that allows me to communicate via UART.
But I'm facing the problem that I'm just using a single UART to achieve all of these tasks.
But in some cases, I can't use the UART when I need it at a specific moment because it has been acquired for another task.
Then, what could be the best approach to sharing or switching a single UART beyond more a timeout?
Whatever advice you leave, it'll be received.
Thanks.
  • Hello,

    Do you plan to use a multiplexer or update the PSEL registers to update the UART pinout before accessing each device? Also, is the communication always initiated by the nRF?

    Best regards,

    Vidar

  • Hi,

    Actually no, it was my bad, let me explain more in deep my case.

    I have two tasks, and one of them I need to help me to ask via UART the current displayed window of an HMI, then into the task, call the Tx to send the command, and after that, call the RX with a timeout to wait for the response of that command from the HMI (inside of DISPLAY_MODULE_UART_getCurrentDisplayedWindow there is the call of Tx and Rx).

    I'll let down the snippet code:

    static void rx_tx_function(void *pvParameter){
    while(1){
    DISPLAY_MODULE_UART_getCurrentDisplayedWindow(pCurrentWindow, pNumberCurrentWindow, pAll_OK);
    if(all_OK){
    SEGGER_RTT_printf(0, "[INFO] - from->[%s()]->Current_Window = [%s]\n", __FUNCTION__, currentWindow);
    if(numberCurrentWindow != SKIPPED_WINDOW){
    SEGGER_RTT_printf(0, "[INFO] - from->[%s()]->NumberCurrentWindow = [%d]\n", __FUNCTION__, numberCurrentWindow);
    }
    else{
    SEGGER_RTT_printf(0, "[INFO] - from->[%s()]->Skipped: [%s]\n", currentWindow);
    }
    }
    else{
    SEGGER_RTT_printf(0, "[INFO] - from->[%s()]->Handle timeoutTicks OR Failed to extract Current Window.\n", __FUNCTION__);
    }
    vTaskDelay(pdMS_TO_TICKS(10));
    }
    }

    The other task helps me to switch from one window to another, sending a command through UART Tx, and put the Rx to wait if I press a button.
    from the HMI.
    I'll let down the snippet code:

    static void rx_task_function(void *pvParameter){
    DISPLAY_MODULE_UART_printCurrentState(currentState.currentState);
    if(currentState.currentState == STATE_WHICH_BUTTON_WAS_PRESS){
    DISPLAY_MODULE_UART_processSTATE_WHICH_BUTTON_WAS_PRESS(ptrCurrentState, ptrCountWindows);
    if(countWindows.countTimeWait_WIN_8 == 3 || countWindows.countTimeWait_WIN_10 == 3){
    SEGGER_RTT_printf(0, "[INFO] - from->[%s()]->countWindows.countTimeWait_WIN_8 = [%d]\n", __FUNCTION__, countWindows.countTimeWait_WIN_8);
    SEGGER_RTT_printf(0, "[INFO] - from->[%s()]->countWindows.countTimeWait_WIN_10 = [%d]\n", __FUNCTION__, countWindows.countTimeWait_WIN_10);
    currentState.currentState = STATE_GOTO_HOME_PAGE;

    countWindows.countTimeWait_WIN_8 = 0;
    countWindows.countTimeWait_WIN_10 = 0;
    }
    }
    else{
    DISPLAY_MODULE_UART_callFSM(ptrCurrentState);
    }
    SEGGER_RTT_printf(0, ">>>>>>>>>> [INFO] - from->[%s()]->EXIT\n", __FUNCTION__);
    vTaskDelay(pdMS_TO_TICKS(10));
    }

    The main problem of this, is that I can't find a good way to share between these two task the single UART.
    Then, I'd appreciate it if you could help me to understand a possible solution to my issue.
    Thanks in advance,
    Fer Mercado.

  • I assumed you were using the nRF Connect SDK, but from the snippet you posted it appears you are using Freertos. Please confirm your setup (SDK version, RTOS, etc).

  • Let me write down my thoughts. A simple solution is to introduce a mutex for UART access. This allows only one task to control UART at any given time, ensuring smoother task coordination without blocking or interrupting each other’s communication.

     

    Start by setting up a FreeRTOS mutex around the UART. Whenever a task needs to access UART, it locks the mutex, completes its operation, then releases it. This ensures only one task is using UART at any time, which keeps things from clashing.

    If one task has tighter timing needs, consider adjusting its priority or giving it a shorter wait on the mutex. This way, urgent UART access isn’t held up unnecessarily.

    Adding a timeout to the mutex acquisition is also a good idea. If a task can’t get access to UART within the set time, you can log the issue or handle it some other way to avoid blocking everything else.

    If there are frequent UART requests from multiple tasks, you might also think about using a queue. With a queue, tasks can queue up their UART requests, and a single handler can take these one by one. This setup simplifies retries and error handling, making the overall code a bit easier to manage.

Related