A ring buffer optimised for ARM Cortex-M microcontrollers, with lock-free SPSC support and policy-based IRQ protection.
Most Cortex-M ring buffers use word-sized (size_t / uint32_t) indices with std::atomic or plain volatile, and either require power-of-2 sizes or silently call __aeabi_uidivmod on wrap. This one takes a different set of micro-architectural decisions:
- Lock-free SPSC without
std::atomic— head and tail are packed as twouint16_tfields in a 4-byte-aligned struct. The producerSTRHat offset 0 and the consumerSTRHat offset 2 target different bus addresses — they cannot collide. No libatomic calls, no fences. - Single-LDR state snapshot — both indices read in one 32-bit bus transaction (
readHT()). Other libraries do two separate reads or rely on atomic word-sized indices. - Topology-selectable IRQ protection —
None/SPSC/MPSC/SPMC/MPMCchosen per-instance, with producer and consumer guards independent (MPSC pays no guard onpop, SPMC pays none onpush). - No software division on any path — power-of-2 sizes use
AND, non-power-of-2 use compare-and-subtract. No__aeabi_uidivmodever emitted. - Compile-time unit tests —
static_assertin the constructor runs a full test suite at instantiation. A broken build will not compile.
#include "RingBuffer_PackedState/RingBuffer_PackedState.h"
// Basic use — no IRQ protection
RingBuffer_PackedState<uint8_t, 32> rb;
rb.push(42);
uint8_t val;
if (rb.pop(val)) {
// val == 42
}
// ISR-safe — PRIMASK save/restore, multiple producers/consumers
RingBuffer_PackedState<uint8_t, 32, Topology::MPMC> rb_mpmc;
// Lock-free SPSC — e.g. ISR producer + main consumer, or vice versa, no IRQ masking needed
RingBuffer_PackedState<uint8_t, 32, Topology::SPSC<>> rb_spsc;
// Custom lock — e.g. FreeRTOS critical section
RingBuffer_PackedState<uint8_t, 32, Topology::MPMC<FreeRtosLock>> rb_rtos;See RingBuffer_PackedState for the full API including DMA contiguous area access.
ISR-safe, DMA-friendly ring buffer for ARM Cortex-M. Head and tail stored as adjacent uint16_t fields — reads are LDRH, writes are STRH. Each side in SPSC owns one field exclusively, enabling lock-free operation without IRQ masking.
- Topology-based policy —
Topology::None<>/SPSC<>/MPSC<>/SPMC<>/MPMC<>; producer and consumer guards are independent, so MPSC pays no overhead onpopand SPMC pays none onpush; swapPrimaskLockfor any custom lock (e.g. FreeRTOS) viaTopology::MPMC<FreeRtosLock> - Compile-time unit tests — a
static_assertin the constructor verifies correctness at build time - Header-only — single
.hfile per implementation, no dependencies beyond the C++ standard library - C++20 or later required
Copyright (c) 2026 PxQ Technologies — https://pxq.dk
Dual-licensed: GPLv3 + commercial.
Open Source (GPLv3): Free under GPLv3 — note that GPLv3 is strong copyleft, so derivative works and products incorporating this software must also be released under GPLv3.
Commercial: For use in proprietary or closed-source products, a commercial license is available from PxQ Technologies — either as a written agreement, or via direct delivery by Erik Nørskov as part of a paid engagement.
Contact: https://pxq.dk
If you find this library useful, please consider giving it a ⭐ on GitHub — it helps others discover it.