This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

zephyr-rtos and the nRF UART driver

I have observed two issues with using the UART in an ncs project and I'm not sure exactly where the issue lies (Nordic or Zephyr).

Firstly, and most importantly, according to the Zephyr docs, as soon as the UART starts receiving, a `UART_RX_BUF_REQUEST` event is supposed to be raised:
https://docs.zephyrproject.org/latest/reference/peripherals/uart.html#c.uart_event_type

This allows the app to provide a second buffer for the driver so that once the first one fills, it can continue receiving.

However, this isn't the case and, in fact, the event isn't raised until `UART_RX_RDY` is raised first because a complete RX has been detected (timeout on the RX line).
This means that if data larger than the buffer comes in, it immediately hits the end of the buffer, no swap is performed, and I get overrun errors instead.

The second issue is that it should, or could, receive several messages in the same buffer but as above, on each `UART_RX_RDY` event, the buffer is immediately swapped out at that point.
This means I am quickly using up my buffers (3) if many small messages come through, before I have had a chance to deal with the data.

Can somebody verify that I have understood the Zephyr docs correctly or not, or confirm if there is indeed a difference in behaviour using Nordic's UART driver for some reason?

Parents
  • If you're using the nRF9160 DK, the driver zephyr/serial/uart_nrfx_uarte.c will be used (which connects the top Zephyr UART API with the Nordic specific UART HAL).

    Firstly, and most importantly, according to the Zephyr docs, as soon as the UART starts receiving, a `UART_RX_BUF_REQUEST` event is supposed to be raised:
    https://docs.zephyrproject.org/latest/reference/peripherals/uart.html#c.uart_event_type

    This allows the app to provide a second buffer for the driver so that once the first one fills, it can continue receiving.

    However, this isn't the case and, in fact, the event isn't raised until `UART_RX_RDY` is raised first because a complete RX has been detected (timeout on the RX line).
    This means that if data larger than the buffer comes in, it immediately hits the end of the buffer, no swap is performed, and I get overrun errors instead.

    If you take a look at uart_nrfx_uarte.c, you'll see that UART_RX_BUF_REQUEST is generated inside rxstarted_isr(), and rxstarted_isr() is invoked when receiving the event NRF_UARTE_EVENT_RXSTARTED. In your applications user callback, you should handle the UART_RX_BUF_REQUEST event by setting up a new buffer. Check out nrf/samples/peripheral_uart to see how to go about this. I'm not sure where you read that it's not raised until UART_RX_RDY is raised.

    The second issue is that it should, or could, receive several messages in the same buffer but as above, on each `UART_RX_RDY` event, the buffer is immediately swapped out at that point.
    This means I am quickly using up my buffers (3) if many small messages come through, before I have had a chance to deal with the data.

     In the application you should handle UART_RX_RDY, by immediately reading out the received data. If you do that I don't think you will have any problems of loosing data. Check out nrf/samples/peripheral_uart how it's done.

    Best regards,

    Simon

  • Your reply confirms my understanding of how it _should_ work and what I was expecting.

    But in practice, this isn’t the case. I haven’t “read” it anywhere, I have observed it firsthand. The Nordic driver will not raise the UART_RX_BUF_REQUEST event unless the RX has completed. It _should_ raise it as soon as the first byte is received.

    And in my second point, you have missed what I was discussing.
    I am aware of how to read the buffers and capture the data. The problem is that these small messages are _always_ swapping the buffers instead of continuing to use one that isn’t yet full. Which isn’t what the Zephyr docs suggests

  • Okay, sorry for being too quick. I will try to do some testing myself and see if I can reproduce the behaviour you're explaining.

  • jongor said:
    But in practice, this isn’t the case. I haven’t “read” it anywhere, I have observed it firsthand. The Nordic driver will not raise the UART_RX_BUF_REQUEST event unless the RX has completed. It _should_ raise it as soon as the first byte is received.

    I'm not able to reproduce this. I tried to run the LPUART sample (which uses the uart_nrfx_uarte.c driver underneith) and triggered a GPIO when the RX_BUF_REQUEST event happened (here), and it did happen right before the first byte was received. I also triggered a GPIO when UART_RX_RDY happened (here and here):

    If I have misunderstood the issue, please tell me. If you could provide a sample and a step-by-step guide to reproduce the problem, that would be nice.

    jongor said:
    And in my second point, you have missed what I was discussing.
    I am aware of how to read the buffers and capture the data. The problem is that these small messages are _always_ swapping the buffers instead of continuing to use one that isn’t yet full. Which isn’t what the Zephyr docs suggests

     I'll look into this later on this week.

Reply
  • jongor said:
    But in practice, this isn’t the case. I haven’t “read” it anywhere, I have observed it firsthand. The Nordic driver will not raise the UART_RX_BUF_REQUEST event unless the RX has completed. It _should_ raise it as soon as the first byte is received.

    I'm not able to reproduce this. I tried to run the LPUART sample (which uses the uart_nrfx_uarte.c driver underneith) and triggered a GPIO when the RX_BUF_REQUEST event happened (here), and it did happen right before the first byte was received. I also triggered a GPIO when UART_RX_RDY happened (here and here):

    If I have misunderstood the issue, please tell me. If you could provide a sample and a step-by-step guide to reproduce the problem, that would be nice.

    jongor said:
    And in my second point, you have missed what I was discussing.
    I am aware of how to read the buffers and capture the data. The problem is that these small messages are _always_ swapping the buffers instead of continuing to use one that isn’t yet full. Which isn’t what the Zephyr docs suggests

     I'll look into this later on this week.

Children
Related