Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Differences between circular/ring buffer libraries in the SDK

Hi,

I was wondering what are the main differences between the different libraries included in the SDK that are meant to be implementations of ring buffers. I'm talking specifically about the differences between the FIFO library, the queue library and the ringbuf library. I don't know if there are more.

I'm interested in pros and cons of each library, whether they have different purposes and if there are some considerations to take when using one or the other.

The only differences I'm aware of are that the queue library has support for specific data types (objects), the FIFO library is only for "bytes" and the ringbuf library is somehow "more efficient" (?).

  • Hi,

    The libraries have been developed over time for similar use cases. The best is to look at them and find which quits you, but here is a short list of differences:

    • app_fifo does not use atomic operations or critical sections, so it is not thread safe.
    • nrf_queue and nrf_ringbuf handle this, but do it differently.
      • nrf_ringbuf use atomic operations using nrf_atomic, which uses LDREX/STREX. this is probably the best for most use cases. It uses arbitrary sized elements / objects.
      • nrf_queue si a older library, that is extensively used in SDK libraries and examples. It uses critical sections. It uses fixed size elements.
    • Usage:
      • nrf_queue use fixed size elements.
      • nrf_ringbuf on the other hand can handle elements of varying size.
      • app_fifo operate on byte elements, but provides ways to read and write chunks as well.

    Which you want to use depend on your needs.

    (There is also a nrf_fifo, but that is specifically intended to be used in IoT context).

  • Thanks for your answer. It's very helpful :) I still have a couple of questions.

    When is thread safety important? When protecting against interrupts? Or is this an RTOS thing?

    And about the ringbuf library: I don't really get it. I read the documentation but it doesn't appear to work with "elements" as you mentioned. It seems to me that it works more with raw data.

    How does it work for example if I want to get 5 elements and all of them are of different sizes? As far as I can tell the library doesn't support stuff like this.

  • Hi,

    Andy said:
    When is thread safety important? When protecting against interrupts? Or is this an RTOS thing?

    It is important if you are using the library from several interrupt priorities, regardless of it is using an RTOS or not. If it is possible that a fifo operation can be preempted by another fifo operation, then that is a concern.

    Andy said:
    And about the ringbuf library: I don't really get it. I read the documentation but it doesn't appear to work with "elements" as you mentioned. It seems to me that it works more with raw data.

    You are right, I was basing this on my bad memory. The nrf_ringbuf works with raw data, same as app_fifo. But this is preferable, since it uses atomic operations to ensure thread safety.

    Andy said:
    How does it work for example if I want to get 5 elements and all of them are of different sizes? As far as I can tell the library doesn't support stuff like this.

    You need to use your own scheme on top if you need it to handle different objects, for instance a TLV (type-length-value) variant.

  • Ok, so take-aways from this thread:

    The nrf_ringbuf library is a better app_fifo, and the queue library incorporates an abstraction layer that handles things like putting structs and arrays and considers them as single elements.

    From what you said, the fact that the ringbuf library handles elements of arbitrary size just means that you can "put" an arbitrary amount of bytes in the buffer.

    Is that correct?

    I have just one more question: You mentioned a difference between the usage of critical sections and nrf_atomic operations. How do they compare?

  • Andy said:

    From what you said, the fact that the ringbuf library handles elements of arbitrary size just means that you can "put" an arbitrary amount of bytes in the buffer.

    Is that correct?

    Yes, that is correct.

    Andy said:
    I have just one more question: You mentioned a difference between the usage of critical sections and nrf_atomic operations. How do they compare?

    Using critical sections disable all interrupts temporarily and re-enables them again. This is no problem as long at it is for short times, but it has a performance penalty and you block potentially unrelated high priority interrupts.

    The atomic operations module use the LDREX/STREX instructions that are present in the Cortex-M4 core. This is used to make a form of mutex to make sure that buffer is not updated by one "user" while it is being manipulated by another user without the need for critical sections.

Related