0
0
Power-electronicsHow-ToBeginner · 3 min read

How to Implement FIFO Buffer in Embedded C: Simple Guide

To implement a FIFO buffer in embedded C, create a circular buffer using an array with two pointers: head for writing and tail for reading. Increment pointers modulo buffer size to wrap around, ensuring data is read in the order it was written.
📐

Syntax

A FIFO buffer in embedded C typically uses an array and two index variables:

  • buffer[]: stores data
  • head: index where new data is written
  • tail: index where data is read
  • size: total buffer capacity

Use modulo operation to wrap head and tail when they reach the end.

c
typedef struct {
    uint8_t buffer[SIZE];
    uint16_t head;
    uint16_t tail;
    uint16_t size;
} FIFO_Buffer;

// Write data: buffer[head] = data; head = (head + 1) % size;
// Read data: data = buffer[tail]; tail = (tail + 1) % size;
💻

Example

This example shows a simple FIFO buffer storing bytes, with functions to add and remove data safely.

c
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>

#define SIZE 5

typedef struct {
    uint8_t buffer[SIZE];
    uint16_t head;
    uint16_t tail;
    uint16_t size;
} FIFO_Buffer;

void fifo_init(FIFO_Buffer *fifo) {
    fifo->head = 0;
    fifo->tail = 0;
    fifo->size = SIZE;
}

bool fifo_is_full(FIFO_Buffer *fifo) {
    return ((fifo->head + 1) % fifo->size) == fifo->tail;
}

bool fifo_is_empty(FIFO_Buffer *fifo) {
    return fifo->head == fifo->tail;
}

bool fifo_enqueue(FIFO_Buffer *fifo, uint8_t data) {
    if (fifo_is_full(fifo)) {
        return false; // Buffer full
    }
    fifo->buffer[fifo->head] = data;
    fifo->head = (fifo->head + 1) % fifo->size;
    return true;
}

bool fifo_dequeue(FIFO_Buffer *fifo, uint8_t *data) {
    if (fifo_is_empty(fifo)) {
        return false; // Buffer empty
    }
    *data = fifo->buffer[fifo->tail];
    fifo->tail = (fifo->tail + 1) % fifo->size;
    return true;
}

int main() {
    FIFO_Buffer fifo;
    fifo_init(&fifo);

    // Add data 1,2,3
    fifo_enqueue(&fifo, 1);
    fifo_enqueue(&fifo, 2);
    fifo_enqueue(&fifo, 3);

    uint8_t val;
    while (fifo_dequeue(&fifo, &val)) {
        printf("%d ", val);
    }
    return 0;
}
Output
1 2 3
⚠️

Common Pitfalls

Common mistakes when implementing FIFO buffers include:

  • Not handling buffer full condition, causing data overwrite.
  • Confusing head and tail pointers leading to incorrect reads or writes.
  • Forgetting to use modulo operation, causing index overflow.
  • Not checking if buffer is empty before reading, causing invalid data access.
c
/* Wrong: No check for full buffer, overwrites data */
buffer[head] = data;
head++;

/* Right: Check full and wrap index */
if (!fifo_is_full(&fifo)) {
    buffer[head] = data;
    head = (head + 1) % size;
}
📊

Quick Reference

  • Initialize: Set head = tail = 0.
  • Enqueue: Write at head, then head = (head + 1) % size.
  • Dequeue: Read at tail, then tail = (tail + 1) % size.
  • Full: When next head equals tail.
  • Empty: When head == tail.

Key Takeaways

Use a circular array with head and tail indexes to implement FIFO buffer.
Always check for full and empty conditions to avoid data loss or invalid reads.
Increment indexes using modulo to wrap around the buffer size.
Keep head as the write position and tail as the read position.
Test your buffer with edge cases like full and empty states.