semf
BufferAndAverage

General

For Embedded system projects one of the most used data structure is the ring semf::Buffer (also called circular buffer). This semf::Buffer is fixed in size and operates in a contiguous or circular manner. Adding (putting) or fetching (getting) data from the semf::Buffer doesn’t reorder the data it only manipulates the pointers and pointees of the „head“ and „tail“ of the data in the ring buffer — in fact it operates as a queue. When adding data to the ring buffer the data is written to where the head pointer is pointing and the head pointer is incremented by one. When fetching data, the data is read from where the tail pointer is pointing and the tail pointer is advanced. If a pointer reaches the end of the buffer the pointers simply wrap around to the beginning.

There are three different types of buffers available:

Buffer implementations are thread save by using semf::CriticalSection. For using a semf::Buffer you need one object of semf::CriticalSection in your project, which will automaticly be used by all buffer objects. In the following examples we use the STM32F4 HAL implementation.

Furthermore in many applications it is necessary to determine the average value of the content of the buffer. The average of the data inside a buffer can easily be determined by semf::Average.

RingBuffer Example

A semf::RingBuffer synchronously handles the incoming and outgoing data. The incoming data can only be written to the semf::RingBuffer if the semf::Buffer has a free spot in its queue. Freeing up a spot is done by reading the FiFo buffer with a call to get().

Create a semf::RingBuffer object by first creating a data array of the desired size. Then create the semf::RingBuffer object by passing the pointer to the data array and the size of the data array to the constructor.

semf::Stm32F4CritialSection critialSection;
const size_t bufferArraySize = 8;
uint8_t bufferArray[bufferArraySize] = { 0 };
semf::RingBuffer buffer(bufferArray, bufferArraySize);
The RingBuffer class implements a classic circular buffer.
Definition: ringbuffer.h:40

Writing and reading data can be accomplished by the methods put() and get(). Every call to get() pops an element from the semf::Buffer and frees the position in the buffer for a future put().

// ...
buffer.put(0x01);
buffer.put(0x02);
buffer.put(0x03);
buffer.put(0x04);
buffer.put(0x05);
uint8_t temp = buffer.get(); // temp is 0x01

In the following picture you can see the semf::RingBuffer object containing 4 valid elements (5 written elements minus 1 read element):

Ringbuffer

Be careful: If the Buffer is full of valid elements the new data you put() will be ignored. Checking if the Buffer is full can be done by a call to full(). Similarly if the buffer is empty a call to get() will return 0. Checking if the buffer is empty can be done by a call to empty().

Average

The semf::Average class builds an average of all valid elements (the ones that have not been read yet). The read position will not be changed.

// avg is (2+3+4+5) / 4 = 3
uint8_t avg = semf::Average::value(buffer);
static T value(const T data[], size_t dataSize)
Calculates an average out of an array.
Definition: average.cpp:15

LastInBuffer Example

A semf::LastInBuffer is a semf::Buffer for handling asynchronous data. By for example cyclicly sampling an AnalogIn you can asynchronously get the latest measurements available when you need it in the application. By putting new data the oldest data will be overwritten. You have access to the latest number of values according to the size of the data array.

Create a semf::LastInBuffer object by first creating a data array of the desired size. Then create the LastInBuffer object by passing the pointer and the size of the data array to the constructor.

semf::Stm32F4CritialSection critialSection;
const size_t bufferArraySize = 8;
uint8_t bufferArray[bufferArraySize] = { 0 };
semf::LastInBuffer buffer(bufferArray, bufferArraySize);
The LastInBuffer class implements a kind of circular buffer.
Definition: lastinbuffer.h:40

Writing is accomplished by calling put(). In order to get the newest entry, you can use a combination of at() and pos().

for (uint8_t i = 1; i <= 10; i++)
{
buffer.put(i);
}
uint8_t temp1 = buffer.at(0); // temp is 0x0A
uint8_t temp2 = buffer.at(2); // temp is 0x08

In the following picture you can see our semf::LastInBuffer :

LastInBuffer

Average

The semf::Average class builds an average from the whole data array.

// avg is (9+10+3+4+5+6+7+8) / 8 = 6
uint8_t avg = semf::Average::value(buffer);

LastInDmaBuffer Example

A semf::LastInDmaBuffer is a semf::Buffer for handling asynchronous data from multiple inputs and outputs in one data array. By using an semf::AnalogInDma with multiple inputs sampling cyclicly you can asynchronously get the latest measurements when you need it in the application. Create a semf::LastInDmaBuffer object by first creating a data array of the desired size. Then create the semf::LastInDmaBuffer object by passing the pointer and the size of the data array to the constructor.

semf::Stm32F4CritialSection critialSection;
const size_t bufferArraySize = 9;
uint8_t bufferArray[bufferArraySize] = { 0 };
semf::LastInDmaBuffer bufferSens1(bufferArray, bufferArraySize);
semf::LastInDmaBuffer bufferSens2(bufferArray, bufferArraySize);
semf::LastInDmaBuffer bufferSens3(bufferArray, bufferArraySize);
// Setting for three LastInDmaBuffer in one data array
bufferSens1.setStride(3);
bufferSens2.setStride(3);
bufferSens3.setStride(3);
// Setting bufferSens1 first element to array index 0,
bufferSens1.setPos(0);
// bufferSens2 first element to array index 1 and
bufferSens2.setPos(1);
// bufferSens3 first element to array index 2
bufferSens3.setPos(2);
The LastInDmaBuffer class implements a kind of circular buffer.

Writing to the semf::LastInDmaBuffer occurs as usual in the semf::Buffer .

For getting the newest entry you can use a combination of at() and pos().

bufferSens1.put(0x01); // Data input 1
bufferSens1.put(0x02);
bufferSens1.put(0x03);
bufferSens2.put(0x11); // Data input 2
bufferSens2.put(0x12);
bufferSens2.put(0x13);
bufferSens3.put(0x21); // Data input 3
bufferSens3.put(0x22);
bufferSens3.put(0x23);
// Read data
uint8_t tempSens1 = bufferSens1.at(0); // temp is 0x03
uint8_t tempSens2 = bufferSens2.at(1); // temp is 0x12

In the following picture you can see how the semf::LastInDmaBuffer handles the incoming and outgoing data:

LastInDmaBuffer

Average

The semf::Average class determines the average value from the part of the array associated with the semf::LastInDmaBuffer.

// avg is (0x21+0x22) / 2 = 33
uint8_t avg = semf::Average::value(bufferSens3);