Software circular buffers are data structures used to pass data from one section of code to another, where the code sections usually have no other interaction with each other. One situation that dictates that a “buffer” be used is when it is possible that a burst of data to occur that exceeds the “processing” codes ability to keep up on an item by item basis. Then a separate section of code to buffer (accept from the external source and insert it into a circular buffer) is necessary.
On average, the processing must keep up, or no amount of buffering will prevent an eventual overrun and loss of data. Another situation where you might use a “buffer” is to compartmentalize the functions of your code. For example, if you are using a keypad on a project, you may choose to write one section of code that detects that a key has been pressed, determines what it is, and places the ASCII code for it in a circular buffer.
A completely separate section of code could then process the “stream” of key-presses for the purpose at hand, say a combination lock code. Partitioning the code in this fashion not only makes each section easier to write (each is smaller and you get to focus on a simpler task), but also makes each section more reusable. The combination decoding could easily be used virtually unchanged with the code sequence coming from the SCI instead. The proper view of data in a circular buffer is a “stream” of sequential data items, often characters.
The section of code that sends data to another section inserts each new datum item into the buffer. In general, that code inserts data as fast as it becomes available. The section of code that receives the data removes each item from the buffer. The receiver almost always has some processing task to perform on the received data items, and often processes at a slower instantaneous rate than the insertion code. It is often the case that several circular buffers will exist within a program. It is also often the case that the sending and/or receiving code sections are in interrupt handler routines. A possible point of confusion is that any receiving ISR routine (say an SCI receive ISR) will probably play the role of sender via the circular buffer. Virtually the only SCI receiver ISR I have ever written was to have it read the incoming characters and place them in a circular buffer, and nothing more.
How Do Circular Buffers Work?
A circular buffer is really a linear sequential buffer that is used from beginning to end, over and over. Unlike a STACK which operates as a first-in-last-out (FILO) buffer and naturally keeps reusing memory as items are popped on and later pulled off of the stack, with a circular buffer one must work at reusing memory. This is accomplished by having code to wrap around to the beginning of the buffer whenever the next location gets past the end of the buffer. Picture the buffer as a consecutive set of memory locations that has its last location adjacent to its first location (in effect a circle). Continue reading “Circular Buffers”