High Speed 1 MBaud Async UART with Zephyr

Hello everyone,

I am working with nrf connect sdk toolchain v2.6.1.

My project requirements are as follows:

  • 1 MBaud UART Async API
  • Two Modes for UART RX
    • fill buffer rx buffer with fix len
    • timeout after 200 µs after last byte received (then read out of buffer)
  • I will have BLE activated in later version, but as of now all testing was without BLE.

I read through some dev zone posts and my understanding so far is as follows:

  • max baud rate is 1 MBaud for nRF52840 (specification)
  • high baud rate can be critical with BLE active due to interrupts of BLE and time required. However, with nRF52 SDK v17.1.0 I had no problems with both.
  • when going to 1MBaud I found information in dev zone that HW counting of incoming bytes might be necessary instead of SW counting as it is done by default

Samples I checked:

  • lpuart - uses different API, so not applicable for me
  • ble peripheral uart - does not have 1 MBaud UART

So far I have tested the following with zephyr async uart api:

  • up to 460800 Baud
    • RX with timeout works perfectely
    • RX with fix buffer len, works perfectely
  • > 460800 Baud
    • RX with timeout, less bytes than visible on RX line are being received
    • RX with fix buffer len, incoming bytes are not correct

My questions:

  • there are zephyr guides on how to use UART APIs and some advice, but there seem to be some special requirements for nordic devices. Is there an offical NordicGuide for pushing UART with ASYNC API to 1 MBaud reliably?
  • when going through dev zone I found several posts addressing the issue with different KConfigs to use. However, none of them seem to work for me so I guess as most posts are already a little older, that some of them are outdated. Do you have a list of KConfigs which clearly outline the usage of each? During build process I often get error messages or warnings about KConfigs not being used corretly, but the referenced webpages often do not have any useful information linking to almost empty pages.
  • Is it recommended by Nordic to use nordic uart driver instead of zephyr for 1 MBaud? The few posts discussing zephyr API or nrfx driver suggested to stick to zephyr API.

If needed I can share details about my project setup and error messages. But as of now I would first like to know if there are any resources out there already.

Thanks for any help!

Markus

Parents
  • I normally do not have a good feeling about using that high baudrate on UART where the CPU has other tasks to do. 

    To answer your questions

    Nordic doesn’t have a dedicated guide specifically for pushing the UART Async API to 1 MBaud on the nRF52840. The closest resources are the general UART documentation in Zephyr and Nordic’s guidance around high-throughput UART applications, but these mostly assume lower rates and may not cover high-baud scenarios thoroughly. Achieving reliable UART at 1 MBaud on Nordic devices is possible, though it may require some adjustments for the interrupt handling and DMA settings to handle data at this speed reliably. Developers typically rely on insights shared in forums and DevZone posts, though these tend to vary in accuracy and applicability as SDK versions evolve.

    For your second question, I agree that KConfig options for high-speed UART setups on Nordic devices can be frustratingly inconsistent, especially in the context of Zephyr configurations. The KConfig settings most relevant here would include CONFIG_UART_ASYNC_API, CONFIG_UART_0_ASYNC, CONFIG_UART_0_NRF_HW_ASYNC, and potentially CONFIG_UART_0_BAUDRATE for setting 1 MBaud directly. CONFIG_UART_0_NRF_FLOW_CONTROL can also be essential if you’re using hardware flow control. Settings like CONFIG_SERIAL_SUPPORT_INTERRUPT and CONFIG_UART_RX_TIMEOUT play a role in configuring the data-handling responsiveness and flow. That said, DevZone posts do become outdated, and Nordic’s nRF Connect SDK release notes are sometimes the only reliable way to confirm current, valid KConfig options.

    On whether to use the Zephyr UART API versus the Nordic nrfx driver at 1 MBaud, I generally leans towards recommending the Zephyr API, especially if you’re working within Zephyr’s async context. The Zephyr UART API aligns better with the broader system, making it more adaptable for projects with expanding features like BLE. However, for specific high-performance needs—particularly when you’re seeing throughput issues with the Async API—using nrfx directly can sometimes give more control over the hardware specifics (like DMA and interrupt prioritization). But, this does come at the cost of some portability and integration simplicity within Zephyr. Nordic generally suggests sticking with Zephyr’s API where possible, especially for maintainability

    Few things to keep in mind

    • With high-speed UART, even small delays in handling incoming data can lead to buffer overruns or missed bytes. When you add BLE later, the BLE and UART interrupts will compete, so you’ll need to carefully prioritize them. For now, ensure UART has high priority in handling interrupts.
    • At 1 MBaud, it’s best to offload some of the work to the hardware. EasyDMA in Nordic’s chips allows for efficient data transfer without bogging down the CPU. This reduces software overhead by using hardware to manage the byte counting and buffer filling, which is critical at these speeds.
    • High-speed communication works best with buffers big enough to handle the data burst and a properly set timeout that triggers processing right after data stops flowing. You’re aiming for a balance here—large enough to avoid overflows, but small enough to ensure timely data processing.

    The changes to prj.conf can be something like below

    CONFIG_UART_ASYNC_API=y               
    CONFIG_UART_0_ASYNC=y                 
    CONFIG_UART_0_NRF_HW_ASYNC=y          
    CONFIG_UART_0_NRF_HW_ASYNC_TIMEOUT=200
    CONFIG_UART_0_NRF_HW_ASYNC_RX_BUFFER_SIZE=256 
    CONFIG_UART_LINE_CTRL=y               
    CONFIG_SERIAL=y                        
    CONFIG_SERIAL_SUPPORT_INTERRUPT=y      
    CONFIG_UART_RX_TIMEOUT=1               
    CONFIG_UART_0_BAUDRATE=1000000        
    CONFIG_UART_0_NRF_FLOW_CONTROL=y      
    

    You need to make sure that you add hardware flow control to the uart instance, the example below shows adding hardware flow control to uart instance number 0

    &uart0 {
        ...
        ...  // other settings you have
        hw-flow-control;
    };
    

Reply
  • I normally do not have a good feeling about using that high baudrate on UART where the CPU has other tasks to do. 

    To answer your questions

    Nordic doesn’t have a dedicated guide specifically for pushing the UART Async API to 1 MBaud on the nRF52840. The closest resources are the general UART documentation in Zephyr and Nordic’s guidance around high-throughput UART applications, but these mostly assume lower rates and may not cover high-baud scenarios thoroughly. Achieving reliable UART at 1 MBaud on Nordic devices is possible, though it may require some adjustments for the interrupt handling and DMA settings to handle data at this speed reliably. Developers typically rely on insights shared in forums and DevZone posts, though these tend to vary in accuracy and applicability as SDK versions evolve.

    For your second question, I agree that KConfig options for high-speed UART setups on Nordic devices can be frustratingly inconsistent, especially in the context of Zephyr configurations. The KConfig settings most relevant here would include CONFIG_UART_ASYNC_API, CONFIG_UART_0_ASYNC, CONFIG_UART_0_NRF_HW_ASYNC, and potentially CONFIG_UART_0_BAUDRATE for setting 1 MBaud directly. CONFIG_UART_0_NRF_FLOW_CONTROL can also be essential if you’re using hardware flow control. Settings like CONFIG_SERIAL_SUPPORT_INTERRUPT and CONFIG_UART_RX_TIMEOUT play a role in configuring the data-handling responsiveness and flow. That said, DevZone posts do become outdated, and Nordic’s nRF Connect SDK release notes are sometimes the only reliable way to confirm current, valid KConfig options.

    On whether to use the Zephyr UART API versus the Nordic nrfx driver at 1 MBaud, I generally leans towards recommending the Zephyr API, especially if you’re working within Zephyr’s async context. The Zephyr UART API aligns better with the broader system, making it more adaptable for projects with expanding features like BLE. However, for specific high-performance needs—particularly when you’re seeing throughput issues with the Async API—using nrfx directly can sometimes give more control over the hardware specifics (like DMA and interrupt prioritization). But, this does come at the cost of some portability and integration simplicity within Zephyr. Nordic generally suggests sticking with Zephyr’s API where possible, especially for maintainability

    Few things to keep in mind

    • With high-speed UART, even small delays in handling incoming data can lead to buffer overruns or missed bytes. When you add BLE later, the BLE and UART interrupts will compete, so you’ll need to carefully prioritize them. For now, ensure UART has high priority in handling interrupts.
    • At 1 MBaud, it’s best to offload some of the work to the hardware. EasyDMA in Nordic’s chips allows for efficient data transfer without bogging down the CPU. This reduces software overhead by using hardware to manage the byte counting and buffer filling, which is critical at these speeds.
    • High-speed communication works best with buffers big enough to handle the data burst and a properly set timeout that triggers processing right after data stops flowing. You’re aiming for a balance here—large enough to avoid overflows, but small enough to ensure timely data processing.

    The changes to prj.conf can be something like below

    CONFIG_UART_ASYNC_API=y               
    CONFIG_UART_0_ASYNC=y                 
    CONFIG_UART_0_NRF_HW_ASYNC=y          
    CONFIG_UART_0_NRF_HW_ASYNC_TIMEOUT=200
    CONFIG_UART_0_NRF_HW_ASYNC_RX_BUFFER_SIZE=256 
    CONFIG_UART_LINE_CTRL=y               
    CONFIG_SERIAL=y                        
    CONFIG_SERIAL_SUPPORT_INTERRUPT=y      
    CONFIG_UART_RX_TIMEOUT=1               
    CONFIG_UART_0_BAUDRATE=1000000        
    CONFIG_UART_0_NRF_FLOW_CONTROL=y      
    

    You need to make sure that you add hardware flow control to the uart instance, the example below shows adding hardware flow control to uart instance number 0

    &uart0 {
        ...
        ...  // other settings you have
        hw-flow-control;
    };
    

Children
Related