UART PINS REMAPPING AT RUN TIME

Hello,

I have multiple UART devices connected to various pins on my nRF5340, but due to hardware limitations, I can only use two UARTs concurrently alongside interfaces like SPI and I2C. To address this constraint, I need the ability to dynamically switch or manipulate the UART RX/TX pins during runtime. I'm open to temporarily disabling a UART, reconfiguring its pins for a different device, and then re-enabling it. For example, I'd like to switch UART2 pins to accommodate another device when needed. This capability is crucial for my project, as the default Zephyr framework doesn't support it, necessitating the implementation of a custom solution, potentially involving creative workarounds.

  • Hi,

    For this you should disable uart2 in the devicetree and use our nrfx driver api directly. The Zephyr driver uses this api, but has some limitations, as you correctly point out.

    You can find a sample for using uart through this api at <SDK>/modules/hal/nordic/nrfx/samples/src/nrfx_uarte/tx_rx_non_blocking

    You will need to uninit the peripheral, then reinit it to change the pins. You also need to make a nrfx_uarte_config_t for each desired setup and use these when you reinit.

    Here are the header files with the api for uart and uarte(with DMA), I have highlighted the init and uninit functions for you:

    https://github.com/nrfconnect/sdk-hal_nordic/blob/main/nrfx/drivers/include/nrfx_uart.h#L173-L199

    https://github.com/nrfconnect/sdk-hal_nordic/blob/main/nrfx/drivers/include/nrfx_uarte.h#L182-L208

    You can try using this to make a simple application that switches between two setups, and I will assist you if you run into any issues.

  • Hi,

    While using the nrfx driver, what zephyr mechanism I can use to collect the data received inside the below handler ?


    /**
    * @brief Function for handling UARTE driver events.
    *
    * @param[in] p_event Pointer to event structure. Event is allocated on the stack so it is available
    * only within the context of the event handler.
    * @param[in] p_context Context passed to the interrupt handler, set on initialization. In this example
    * p_context is used to pass the address of the UARTE instance that calls this handler.
    */
    static void uarte_handler(nrfx_uarte_event_t const * p_event, void * p_context)
    {
    nrfx_uarte_t * p_inst = p_context;
    if (p_event->type == NRFX_UARTE_EVT_TX_DONE)
    {
    NRFX_LOG_INFO("--> UARTE event: TX done");
    NRFX_LOG_INFO("Content of TX buffer: %s", m_tx_buffer);
    NRFX_LOG_INFO("Content of RX buffer: %s", m_rx_buffer);
    }
    else
    {
    NRFX_LOG_INFO("UARTE event: %d", p_event->type);
    }
    nrfx_uarte_uninit(p_inst);
    }

    Can I push the data to zephyr os fifo?

  • Hi again, we prefer that users create a new ticket for issues which do not fall under the topic of the original ticket.

    That being said, I believe the data for the event would be stored in:

        p_event.data.rx.p_data

    The structure for nrfx_uarte_event_t is:

    /** @brief Structure for the UARTE transfer completion event. */
    typedef struct
    {
        uint8_t * p_data; ///< Pointer to memory used for transfer.
        size_t    bytes;  ///< Number of bytes transfered.
    } nrfx_uarte_xfer_evt_t;
    
    /** @brief Structure for UARTE error event. */
    typedef struct
    {
        nrfx_uarte_xfer_evt_t rx;         ///< Transfer details, including number of bytes received.
        uint32_t              error_mask; ///< Mask of error flags that generated the event.
    } nrfx_uarte_error_evt_t;
    
    /** @brief Structure for UARTE event. */
    typedef struct
    {
        nrfx_uarte_evt_type_t type; ///< Event type.
        union
        {
            nrfx_uarte_xfer_evt_t  rx;    ///< Data provided for RX completion events.
            nrfx_uarte_xfer_evt_t  tx;    ///< Data provided for TX completion events.
            nrfx_uarte_error_evt_t error; ///< Data provided for error event.
        } data;                           ///< Union to store event data.
    } nrfx_uarte_event_t;

    Please make a new ticket if you need further support on how to handle the event data.

  • I know this is an old thread but it might be easiest to just change the  PSEL.TXD, and  PSEL.RXD registers for the specific UART in the HW versus the other suggested methods. You can have your thread change this and wait a certain amount of time for any current TX transactions to finish (assuming you don't need very tightly timed switch over). Or see this about using pin control groups and dynamically selecting at runtime Pin Control — Zephyr Project Documentation

Related