Asynchronous UART and circular buffer?

Hi,

I am making an application based on the peripheral-nus example.
The checking for CR is removed and all characters are just sent further when available.

The problem is that even short messages might be split in parts when close to buffer ends.
For example, the message "John" might be cut in parts.
First  "Joh" and, typically 50ms later, "n" because a new buffer was then in use for "n".

With a circular buffer short messages would not be cut apart.

Of course it is possible in the application to wait 50ms and then put it together but a circular buffer would be better.

Are there some way to have the bytes from async uart delivered to a circular buffer instead of supplying new buffers?

  • This is something your application needs to handle. Even though your firmware sends a message in one chunk it is not good practice to assume that this chunk will end up as one chunk also in your application. That is why a separator, such as CR, is typically used so that some part of your application can read bytes up to the CR and then forward the received line to an upper layer for further processing.

    Buffering also on sender side before transmission is sometimes a good idea and sometimes not needed. It depends on how the bytes are actually sent over the air/wire.

  • I agree with answer above. The only way I see to avoid this is if the length of the received data always matches the length of the DMA buffer. If you have to wait for the timeout to expire on the last chunk of data, it is because the last chunk did not fill the DMA buffer.

  • The application have not possibility do this as good as the driver could because the application
    has not access to the same information. The application can not know if data is still arriving.

    I transfer random binary data that I do not control so CR/STX/ETX will not solve the problem.
    Of course if the data do not fill the buffer I have to wait for a timeout. That is all fine.

    I want to avoid short messages being delivered to the application in two parts.
    The application could handle this by checking if last message filled the buffer and
    if so wait a delay time and if a second part comes join the two parts.

    I think it is not ideal to first split the message in the driver and then combine it again in the application. That is a waste of resources. Better would be not to split it in the first place.


    Easier would be if the driver had a ring buffer with a maximum number of bytes for each delivery to application. This way the driver would always be able to deliver short timeout messages in one piece.
    The same could be achieved if the driver only used each buffer one time. Then the application would arrange the ring buffer handling and the driver always have a new empty buffer to fill.

    -----------------

    As an example. We receive "John" in two different situations:
    Baudrate 1200. Buffer length 250. Timeout 50 ms.

    1a)
    Application combine.

    End of first buffer: "Joh"     
    Beginning of second buffer: "n"

    The application can handle this nice and get a combine "John" 50 ms after "n" arrived.

    1b)
    Application combine.

    End of first buffer: "John"
    Beginning of second buffer: nothing, not used yet

    The application do not know if more characters is coming and has to wait
    50 ms + (249 x 8,33ms) = 2,13 s before having "John" finished.
    This is to long time, it will give time out in other parts of the system.


    2a)
    Driver with ring buffer or single use buffer.

    Driver deliver "John" 50 ms after "n" arrived. Nice.

    2b)
    Driver with ring buffer or single use buffers.

    We get one message to the application with "John" 50 ms after "n" arrived.
    A good solution.

    Of course we can try and reduce the buffer length and make the timeout different for different baud-rates.
    But I think driver have better possibilities to handle this.

    ------------------


    Are there any uart driver available that can do ring buffer or single use of buffers?
    How complex is it to make an modified driver?



    I am almost new to this RTOS programming and is used to minimalistic bare metal programming. It surprises me that it is so difficult to get a simple ring buffer for received uart data.
    (I wrote a TCP/IP-stack without OS already in the end of previous century and used Intel iRMX RTOS in the 1980´s).

  • It looks like we may have what you need. This commit https://github.com/zephyrproject-rtos/zephyr/commit/399a235653518bc9b65c083f2e70cefa943aa4d9 introduced a new receive mode (CONFIG_UART_NRFX_UARTE_ENHANCED_RX) that always releases the buffer after UART_RX_RDY. This means the buffer offset will always be 0. It is the default mode in SDK v2.9.0.

Related