Circular buffers are a critical component to have in the embedded software engineers’ toolbox. Over the years there have been many different implementations and examples of circular buffers that have littered the internet. I’ve grown particularly fond of the open source CBUF.h module that can be found at https://github.com/barraq/BRBrain/blob/master/firmware/CBUF.h
The CBUF.h module implements a circular buffer using macros. Now in general I don’t like to use macros in this way but the implementation has proven to fast, efficient and work relatively well and that is difficult to argue with. The circular buffer is pretty simple to setup. First, the size of the circular buffer needs to be defined. This is done by defining the macro myQ_SIZE while keeping in mind that the buffer size needs to be a power of 2.
The circular buffer is then declared by creating a variable of type myQ. For example, if myQ_SIZE was defined to be 64 bytes, a transmit and receive buffer for a UART could be defined as seen in Figure 1 below.
In this example myQ is defined as static in order to limit the scope of the buffers and declared volatile because they are modified inside of an interrupt. Defining the circular buffer though is only the first step. In order to allocate the buffer these variables must be then passed to the CBUF_INIT macro as seen below in Figure 2.
Beyond this initial setup the buffer is fairly straight forward and easy to use. For example, characters being received through a serial interface receive UART can be pushed onto the circular buffer using CBUF_PUSH as seen in Figure 3.
Figure 3 – Pushing onto the buffer
A developer would want to not only push data on the circular buffer but also pop or get data from the buffer. An easy example to see this in would be for a serial transmitter that needs to get a character and transmit it over the UART. An example transmit function can be seen in Figure 4.
Figure 4 – Popping data from the buffer
In a robust application the circular buffer length and overflow status should also be checked. The CBUF module does provide macros to be able to check for these important indicators. An important concern to keep in mind is that if any debugging of CBUF itself needs to be performed it is not possible. Breakpoints can’t be set for macros so if a problem arises the module would need to be functionized in order to step through and debug. Over the years of using this module though I have not found this to be an issue.
Circular buffers are an important aspect of communicating with serial devices within an embedded system. Circular buffers are also well understood and should be created so that they can be modular and reused from one application to the next. The CBUF module has so far proven to be such a module and I encourage developers to download it and experiment with it themselves.