0
0
Embedded Cprogramming~7 mins

Ring buffer implementation in Embedded C

Choose your learning style9 modes available
Introduction

A ring buffer helps store data in a fixed-size space that wraps around when full. It is useful to keep data flowing smoothly without losing old data.

When reading data from a sensor continuously and processing it later.
When sending or receiving data over a communication line like UART.
When you want to store recent events or messages in a limited memory area.
When you need a simple queue that reuses memory efficiently.
Syntax
Embedded C
typedef struct {
    int buffer[SIZE];
    int head;
    int tail;
    int max_size;
    bool full;
} RingBuffer;

void ring_buffer_init(RingBuffer *rb, int size);
bool ring_buffer_put(RingBuffer *rb, int data);
bool ring_buffer_get(RingBuffer *rb, int *data);

The head points to where new data is added.

The tail points to where data is read from.

Examples
Create a ring buffer of size 5 and initialize it.
Embedded C
RingBuffer rb;
ring_buffer_init(&rb, 5);
Add two numbers to the ring buffer.
Embedded C
ring_buffer_put(&rb, 10);
ring_buffer_put(&rb, 20);
Read a number from the ring buffer if available.
Embedded C
int value;
if (ring_buffer_get(&rb, &value)) {
    // use value
}
Sample Program

This program creates a ring buffer of size 5. It adds numbers 1 to 5, tries to add a 6th number but fails because the buffer is full. Then it reads all numbers and tries to read once more but finds the buffer empty.

Embedded C
#include <stdio.h>
#include <stdbool.h>

#define SIZE 5

typedef struct {
    int buffer[SIZE];
    int head;
    int tail;
    int max_size;
    bool full;
} RingBuffer;

void ring_buffer_init(RingBuffer *rb, int size) {
    rb->head = 0;
    rb->tail = 0;
    rb->max_size = size;
    rb->full = false;
}

bool ring_buffer_put(RingBuffer *rb, int data) {
    if (rb->full) {
        return false; // buffer full
    }
    rb->buffer[rb->head] = data;
    rb->head = (rb->head + 1) % rb->max_size;
    if (rb->head == rb->tail) {
        rb->full = true;
    }
    return true;
}

bool ring_buffer_get(RingBuffer *rb, int *data) {
    if (rb->head == rb->tail && !rb->full) {
        return false; // buffer empty
    }
    *data = rb->buffer[rb->tail];
    rb->tail = (rb->tail + 1) % rb->max_size;
    rb->full = false;
    return true;
}

int main() {
    RingBuffer rb;
    ring_buffer_init(&rb, SIZE);

    // Add numbers 1 to 5
    for (int i = 1; i <= 5; i++) {
        if (ring_buffer_put(&rb, i)) {
            printf("Added %d\n", i);
        } else {
            printf("Buffer full, cannot add %d\n", i);
        }
    }

    // Try to add one more
    if (!ring_buffer_put(&rb, 6)) {
        printf("Buffer full, cannot add 6\n");
    }

    // Read all values
    int val;
    while (ring_buffer_get(&rb, &val)) {
        printf("Read %d\n", val);
    }

    // Try to read from empty buffer
    if (!ring_buffer_get(&rb, &val)) {
        printf("Buffer empty, no data to read\n");
    }

    return 0;
}
OutputSuccess
Important Notes

Remember that the buffer is full when head catches tail after adding data.

When reading, if head equals tail and buffer is not full, it means empty.

Ring buffers are great for fixed memory and continuous data streams.

Summary

A ring buffer stores data in a fixed-size circle.

It uses head and tail pointers to track where to add and read data.

It helps manage data efficiently without moving memory.