0
0
Embedded Cprogramming~10 mins

Ring buffer for UART receive in Embedded C - Step-by-Step Execution

Choose your learning style9 modes available
Concept Flow - Ring buffer for UART receive
UART receives byte
next = (write_index + 1) % 4
if (next != read_index)
Discard byte
write_index = next
Read & process when ready
Repeat
This flow shows how bytes received from UART are stored in a ring buffer only if space available (next != read_index), handling wrap-around and overflow by discarding.
Execution Sample
Embedded C
volatile uint8_t buffer[4];
volatile uint8_t write_index = 0;
volatile uint8_t read_index = 0;

void uart_receive_byte(uint8_t byte) {
  uint8_t next = (write_index + 1) % 4;
  if (next != read_index) {
    buffer[write_index] = byte;
    write_index = next;
  } // else buffer full, byte lost
}
This code stores incoming UART bytes into a 4-byte ring buffer (effective capacity 3), advancing write_index and avoiding overwrite if next == read_index (full).
Execution Table
StepActionwrite_indexread_indexnextBuffer StateOverflow?
1Start: write_index=0, read_index=000-[_, _, _, _]No
2Receive byte 'A' (65)001[65, _, _, _]No
3Update write_index to 110-[65, _, _, _]No
4Receive byte 'B' (66)102[65, 66, _, _]No
5Update write_index to 220-[65, 66, _, _]No
6Receive byte 'C' (67)203[65, 66, 67, _]No
7Update write_index to 330-[65, 66, 67, _]No
8Receive byte 'D' (68)300[65, 66, 67, _]Yes (buffer full, byte lost)
9Read byte at read_index=0 ('A')30-[65, 66, 67, _]No
10Increment read_index to 131-[65, 66, 67, _]No
11Receive byte 'D' (68) retry310[65, 66, 67, 68]No
12Update write_index to 0 (wrap)01-[65, 66, 67, 68]No
13End
💡 Execution demonstrates filling to capacity (3/4 slots), overflow discard, read to free space, then store with wrap-around.
Variable Tracker
VariableStartAfter Step 3After Step 5After Step 7After Step 8After Step 10After Step 11After Step 12Final
write_index012333300
read_index000001111
buffer[_, _, _, _][65, _, _, _][65, 66, _, _][65, 66, 67, _][65, 66, 67, _][65, 66, 67, _][65, 66, 67, 68][65, 66, 67, 68][65, 66, 67, 68]
Key Moments - 3 Insights
Why does the buffer reject the byte 'D' at step 8 even though there is space in the array?
At step 8, next = (3 + 1) % 4 = 0 equals read_index = 0, indicating the buffer is logically full (3 bytes stored). The check prevents overwrite of unread data by discarding when next == read_index.
How does the buffer handle wrapping around when write_index reaches the end?
At step 12, after storing 'D' at index 3, write_index = (3 + 1) % 4 = 0, wrapping around to reuse the buffer circularly.
What happens when read_index is incremented at step 10?
Incrementing read_index from 0 to 1 frees logical space. Now next = 0 != read_index = 1, allowing storage of 'D' at step 11 without overflow.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution table at step 8. Why is the byte 'D' not stored in the buffer?
ABecause the byte 'D' is invalid
BBecause next equals read_index, indicating buffer full
CBecause the buffer array is physically full of zeros
DBecause read_index is ahead of write_index
💡 Hint
Check the 'Overflow?' column at step 8 and the condition comparing 'next' and 'read_index'.
At which step does write_index wrap back to 0?
AStep 12
BStep 8
CStep 10
DStep 11
💡 Hint
Look at the 'write_index' column and see when it changes from 3 to 0.
If read_index was not incremented at step 10, what would happen when byte 'D' arrives again?
AThe byte 'D' would be stored successfully
BThe buffer would overflow and overwrite unread data
CThe byte 'D' would be rejected again due to full buffer
DThe write_index would move forward anyway
💡 Hint
Refer to the buffer full check condition and the variable_tracker values for read_index remaining 0.
Concept Snapshot
Ring buffer stores UART bytes in a fixed-size array.
Use write_index and read_index to track positions.
Increment indices with modulo to wrap around.
Check if next = (write_index + 1) % SIZE == read_index to detect full.
If full, discard new bytes until read advances.
Read bytes by advancing read_index similarly (separate logic).
Full Transcript
This example shows a ring buffer for UART receive in embedded C. Incoming bytes compute next = (write_index + 1) % 4. If next != read_index, store at write_index and advance. This leaves one slot empty to distinguish empty (write==read) from full (next==read). After 3 bytes, full detected on 4th (next wraps to read pos), discarded. Reading advances read_index, freeing space for more writes with wrap-around. Efficient for streams without data copies.