UART Driver with a Ring Buffer
Move bytes between an interrupt and the main loop without locks, using a single-producer/single-consumer circular buffer.
Serial bytes arrive whenever the other side sends them. The UART receive interrupt has only microseconds before the next byte overwrites the data register, but the main loop may be busy for milliseconds. A ring buffer decouples the two.
Choosing the size
typedef struct { uint8_t buf[N]; uint8_t head, tail; } Rb; // shared with an ISR volatile uint8_t head, tail;
Without volatile the main loop may never see the ISR's new head value.
rb->head = (rb->head + 1) % N; rb->data[rb->head] = byte;
Write the data first, then publish the new head If the reader runs between the two lines it reads a slot that has not been written yet.
A ring buffer of size 64 — how many bytes can it hold with the 'one empty slot' scheme?
Why must head be written only by the producer and tail only by the consumer?
Then each index has a single writer, so updates cannot conflict and no lock or critical section is needed.