Async UART API in Zephyr timeout to slow

Hello all,

We are working on an nRF52832 and use the UART peripheral in the latests Zephyr release. As we have a lot of data to send from the nRF to the linux host we are using the async uart interface (DMA) and this works flawlessly. Sometimes the Linux host needs to send some small packets to the nRF side and thus we use the `uart_rx_enable` function. In our protocol timings are very strict and this is where the problem arises.

The DMA receive buffer is 128B long but many messages coming from the linux host are much smaller. We therefore need to rely on the timeout to get an interrupt before the receive buffer is full. We enable receiving as follows:

uart_rx_enable(uart_dev, rx_bufs[0], RX_BUF_SIZE, USEC_PER_MSEC);

We would thus expect an interrupt every millisecond, as soon as at least one byte was received by the DMA. The problem is that the timeout that we are measuring is much, much longer and we have determined a minimum of about 16ms. 

We suspect it may have something to do with the clock source of the interrupt but we need some pointers on how to fix this. 

Kind regards,
Daan

  • Hello Daan, 

    We would thus expect an interrupt every millisecond, as soon as at least one byte was received by the DMA.

    First of all, I would like to clarify that when using the Asynchronous API, there is no interrupt function. The triggered events are handled by a callback function instead.  

    The problem is that the timeout that we are measuring is much, much longer and we have determined a minimum of about 16ms. 

    That being said, the timeout of the uart_rx_enable() function defines an inactivity period. I assume that you might want to do some modifications there. 

    We suspect it may have something to do with the clock source of the interrupt but we need some pointers on how to fix this. 

    Otherwise, the uart_event_type gives quite a decent description of how this API is supposed to work. 

    Cheers, 

    Markus 

  • Hello,

    I understand that the callback is thus purely software and not caused by a hardware interrupt of the DMA controller, therefore you call it a callback function. 

    I totally understand that the uart_rx_enable function defines the inactivity period. We expect this to call the callback after x amount of time after the last byte was received. We are therefore convinced that we should receive the callback after a timeout of 1ms when we pass `USEC_PER_MSEC` as the timeout parameter. However we see a minimum timeout of 16ms. You suggest to do some modifications, but please let me know what kind of modifications are possible. In my opinion we can only pass the parameter.

    Otherwise, the uart_event_type gives quite a decent description of how this API is supposed to work. 

    I think we have quite good understanding of how this API works. In our opinion it doesn't work according to the documentation or the documentation lacks some details about timing. Please elaborate.

  • Thanks a lot for your feedback, Daan! 

    dpape said:
    I think we have quite good understanding of how this API works. In our opinion it doesn't work according to the documentation or the documentation lacks some details about timing. Please elaborate.

    I have two questions here: 

    1. Documentation states that “Inactivity period after receiving at least a byte which triggers uart_event_type::UART_RX_RDY event.” & “If some data was received and timeout occurred uart_event_type::UART_RX_RDY event will be generated. It can happen multiples times for the same buffer. RX timeout is counted from last byte received i.e. if no data was received, there won’t be any timeout event.” Can you confirm that at least one byte was sent in this particular case?
    2. As already mentioned, if you change the timeout to a different value, how long will the offset be then? I asked this because it would be interesting to know if you can see any pattern.

    Regards,

    Markus

    1. Documentation states that “Inactivity period after receiving at least a byte which triggers uart_event_type::UART_RX_RDY event.” & “If some data was received and timeout occurred uart_event_type::UART_RX_RDY event will be generated. It can happen multiples times for the same buffer. RX timeout is counted from last byte received i.e. if no data was received, there won’t be any timeout event.” Can you confirm that at least one byte was sent in this particular case?

    Yes this is the case

    1. As already mentioned, if you change the timeout to a different value, how long will the offset be then? I asked this because it would be interesting to know if you can see any pattern.

     Anything below 16ms gets unstable and gives timeouts around 16ms. Above 16ms it works as expected.

  • dpape said:

    Yes this is the case

    1. As already mentioned, if you change the timeout to a different value, how long will the offset be then? I asked this because it would be interesting to know if you can see any pattern.

     Anything below 16ms gets unstable and gives timeouts around 16ms. Above 16ms it works as expected.

    Ok thanks, Daan! 

    Have you tried the API on other nRF devices and if so, do you see any difference in behaviour? Do you have the possibility to share a log demonstrating the issue?  

    Regards, 

    Markus 

Related