This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How to configure a second UART (UART1) in nRF52840-DK using nRF5_SDK_17.1.0

Hello,

I'm using the UART0 in nRF52840-DK for debugging purposes and using the ble_app_uart_c example as a basis.

Now, I need to activate and configure the second UART (UART1) in this central device for communicating to a second MCU.

Should I use UART1 or UARTE1? What are the functions involved in defining new RX-TX pins and to setup this second UART? What is the sequence of configuration? If it's any other case specific it would help, although I must admit that I'm a bit confused in what I have seen in other cases.

Thank you in advance.

Best Regards,

Joel

Parents
  • Hello,

    Should I use UART1 or UARTE1?

    Did you try to initlize a second instance of the UART you are already using? (but change from instance 0 to instance 1)

    What is the sequence of configuration? If it's any other case specific it would help

    That would be the same as you are already doing for your first UART.

    although I must admit that I'm a bit confused in what I have seen in other cases.

    Yes, it may be confusing if you see a lot of different UART libraries being discussed in different cases. Try to stick to one library.

    Best regards,

    Edvin

Reply
  • Hello,

    Should I use UART1 or UARTE1?

    Did you try to initlize a second instance of the UART you are already using? (but change from instance 0 to instance 1)

    What is the sequence of configuration? If it's any other case specific it would help

    That would be the same as you are already doing for your first UART.

    although I must admit that I'm a bit confused in what I have seen in other cases.

    Yes, it may be confusing if you see a lot of different UART libraries being discussed in different cases. Try to stick to one library.

    Best regards,

    Edvin

Children
  • Hi Edvin,

    To focus the question, please consider the ble_app_uart example.

    It's also possible to change the RX and TX pin numbers and enable the UART1 in the sdk_config file.

    #ifndef UART1_ENABLED
    #define UART1_ENABLED 1
    #endif

    However, the initialization of the uart is done by the function uart_init.

    static void uart_init(void)
    {
        uint32_t                     err_code;
        app_uart_comm_params_t const comm_params =
        {
            .rx_pin_no    = RX_PIN_NUMBER,
            .tx_pin_no    = TX_PIN_NUMBER,
            .rts_pin_no   = RTS_PIN_NUMBER,
            .cts_pin_no   = CTS_PIN_NUMBER,
            .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
            .use_parity   = false,
    #if defined (UART_PRESENT)
            .baud_rate    = NRF_UART_BAUDRATE_115200
    #else
            .baud_rate    = NRF_UARTE_BAUDRATE_115200
    #endif
        };

        APP_UART_FIFO_INIT(&comm_params,
                           UART_RX_BUF_SIZE,
                           UART_TX_BUF_SIZE,
                           uart_event_handle,
                           APP_IRQ_PRIORITY_LOWEST,
                           err_code);
        APP_ERROR_CHECK(err_code);
    }

    How to create a second instance? Just creat a secind uart_init1 with another APP_UART_FIFO macro would do that?

    In the uart_event_handle it's called the function app_uart_get, and when I have to send some information the function to be called is app_uart_put. But in any of these two functions it's possible to select any instance. It's like something fixed to just UART0. What other functions should be used to access UART1?

    Regards,

    Joel

  • Hello,

    I wish it was that simple, but it isn't actually. 

    The app_uart libraries were developed when there only existed one UART on the nRF5 series. Now we have two, so it is pretty hardcoded to only use one. 

    If you look at uart_init() -> APP_UART_FIFO_INIT() -> app_uart_init() -> nrf_drv_uart_init(), you can see that the first input parameter in nrf_drv_uart_init() is the uart instance. 

    Depending on how you want your application to work, I suggest that you (either way) add an input parameter from APP_UART_FIFO_INIT() containing the instance, so that you can call it twice, once with each instance. Then, in addition, you may want to add another instance of the fifo buffers, m_rx_fifo and m_tx_fifo in app_uart_fifo.c.

    Whether you want a separate uart_event_handler() in app_uart_fifo.c is up to you. It may be easier to use two different handlers for each of the UART instances. The callback itself doesn't contain information on what UART instance that triggered. Another option is to add a custom pointer with a parameter in the context pointer used in nrf_drv_uart_init():

    uint32_t app_uart_init(const app_uart_comm_params_t * p_comm_params,
                                 app_uart_buffers_t *     p_buffers,
                                 app_uart_event_handler_t event_handler,
                                 app_irq_priority_t       irq_priority)
    {
        uint32_t err_code;
    
        m_event_handler = event_handler;
    
        if (p_buffers == NULL)
        {
            return NRF_ERROR_INVALID_PARAM;
        }
    
        // Configure buffer RX buffer.
        err_code = app_fifo_init(&m_rx_fifo, p_buffers->rx_buf, p_buffers->rx_buf_size);
        VERIFY_SUCCESS(err_code);
    
        // Configure buffer TX buffer.
        err_code = app_fifo_init(&m_tx_fifo, p_buffers->tx_buf, p_buffers->tx_buf_size);
        VERIFY_SUCCESS(err_code);
    
        nrf_drv_uart_config_t config = NRF_DRV_UART_DEFAULT_CONFIG;
        config.baudrate = (nrf_uart_baudrate_t)p_comm_params->baud_rate;
        config.hwfc = (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_DISABLED) ?
                NRF_UART_HWFC_DISABLED : NRF_UART_HWFC_ENABLED;
        config.interrupt_priority = irq_priority;
        config.parity = p_comm_params->use_parity ? NRF_UART_PARITY_INCLUDED : NRF_UART_PARITY_EXCLUDED;
        config.pselcts = p_comm_params->cts_pin_no;
        config.pselrts = p_comm_params->rts_pin_no;
        config.pselrxd = p_comm_params->rx_pin_no;
        config.pseltxd = p_comm_params->tx_pin_no;
        config.p_context = custom_pointer;              // THIS ONE
    
        err_code = nrf_drv_uart_init(&app_uart_inst, &config, uart_event_handler);
        VERIFY_SUCCESS(err_code);

    Whatever you pass into this p_context pointer will be present in the callback (p_context)

    static void uart_event_handler(nrf_drv_uart_event_t * p_event, void* p_context)

    Alternatively, you can use the nrf_drv_uart_init directly from your application, and skip the app_uart_fifo library.

    Best regards,

    Edvin

  • Hi Edvin,

    I see it's not an easy solution.

    I agree that it will be necessary to have two separate uart_event_handler functions, one for each UART.

    I understand your proposal, but I see that the definition of the app_uart_inst is only one (#define APP_UART_DRIVER_INSTANCE 0) in sdk_config.h. But, what is the relation to the UART1_ENABLED setting in sdk_config.h?

    Perhaps it should be better to consider the use of libuarte for this UART1 and let what is done for the UART0 for debugging. I mean setup UART1 for communicate to the MCU and what is done by debugging. Considering this, I see there's an example for SDK_17.1.0 in peripheral\libuarte. For porting this example from UART0 to UART1 I understand that I should setup NRF_LIBUARTE_DRV_UARTE1 to 1 in sdk_config.h.  Considering the main.c file, a way of setting this UART1 may be the next, changing what is on bold?

       nrf_libuarte_async_config_t nrf_libuarte_async_config1 = {
                .tx_pin     = TX_PIN_NUMBER_UART1,
                .rx_pin     = RX_PIN_NUMBER_UART1,
                .baudrate   = NRF_UARTE_BAUDRATE_115200,
                .parity     = NRF_UARTE_PARITY_EXCLUDED,
                .hwfc       = NRF_UARTE_HWFC_DISABLED,
                .timeout_us = 100,
                .int_prio   = APP_IRQ_PRIORITY_LOW
        };

        err_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config1, uart_event_handler1, (void *)&libuarte);

    A new uart_evant_handler1 may be used separately. What about libuarte? In the example I see a MACRO on main.c

    NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);

    Considering the definition of the macro, may I assume than for UARTE1 I sould define a new libuarte1 with id , like this?

    NRF_LIBUARTE_ASYNC_DEFINE(libuarte1, 1, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);

    What other points should I consider?

    Regards,

    Joel

  • jinvers said:
    I understand your proposal, but I see that the definition of the app_uart_inst is only one (#define APP_UART_DRIVER_INSTANCE 0) in sdk_config.h. But, what is the relation to the UART1_ENABLED setting in sdk_config.h?

    Yes. You can just duplicate the APP_UART_DRIVER_INSTANCE in sdk_config. Create one called APP_UART0_DRIVER_INSTANCE and one APP_UART1_DRIVER_INSTANCE.

    jinvers said:
    Perhaps it should be better to consider the use of libuarte for this UART1 and let what is done for the UART0 for debugging. I mean setup UART1 for communicate to the MCU and what is done by debugging. Considering this, I see there's an example for SDK_17.1.0 in peripheral\libuarte. For porting this example from UART0 to UART1 I understand that I should setup NRF_LIBUARTE_DRV_UARTE1 to 1 in sdk_config.h.  Considering the main.c file, a way of setting this UART1 may be the next, changing what is on bold?

    That is one option, but please be aware that the libuarte (while good for it's needs) will require one TIMER instance for each peripheral, in addition to at least the app_timer. While it may be easier to set up two of them, they are more resource demanding. In that case, I would maybe consider using the nrf_drv_uart_init() directly instead first. 

    jinvers said:

    NRF_LIBUARTE_ASYNC_DEFINE(libuarte1, 1, 0, 0, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 255, 3);

    What other points should I consider?

    The rest of these would be the timers. If you look at the NRF_LIBUARTE_ASYNC_DEFINE() macro definition, you will see that these are instances of UART, TIMER, another TIMER, the RTC, and some other stuff. As a test, I think the nrf_drv_uart is simpler to test two instances of.

    Best regards,

    Edvin

Related