Resilient Audio on Modular SoMs: Architecture Lessons from Integrating the PCM1862

Resilient Audio on Modular SoMs: Architecture Lessons from Integrating the PCM1862

A deep dive into architectural failures, race conditions, timing drift, and buffer inconsistencies, and how we fixed them.

When we began integrating the PCM1862 across our modular SoM platforms, the expectation was straightforward: configure clocks, bring up I2S, wire DMA, and start capturing clean audio frames. Instead we ran into a series of subtle problems that never showed up in basic testing: audio frames drifting out of alignment, buffers filling faster than expected under load, jitter appearing only when certain system services ran, false ML triggers caused by inconsistent framing, DMA ghost frames showing up only in long runs, and time-domain features fluctuating despite identical input.

None of these were hardware failures. They were timing, concurrency, and synchronization bugs inside the software pipeline. What made debugging hard is that audio almost worked, and the problems only revealed themselves after minutes, hours, or under very specific system conditions.

Why it matters

In a modular SoM ecosystem like ours, Tracker runs lightweight sensing logic, EverBowl records sound events, and EverHub performs local edge audio analytics. All three depend on predictable audio timing and consistent sample framing. If the software pipeline drifts, desyncs, overruns, or jitters, the downstream ML stack loses reliability. Even small defects, one missed DMA interrupt, one wrong clock assumption, one buffer boundary error, produce noisy results that cascade.

Architecture overview

Across multiple debugging cycles, the hard problems consistently came from five software pillars: clock configuration and timing assumptions, I2S framing logic and LRCLK synchrony, DMA pacing, priority, and starvation, buffering strategy and memory ownership rules, and feature extraction timing and frame boundary correctness. Everything that broke lived inside these layers, and everything we fixed came from rethinking them.

Clock configuration. Even though the SoM-generated clock and the PCM1862-generated clock looked aligned on paper, the software's assumptions about their relationship were wrong. We saw LRCLK interrupts drifting over long periods, DMA firing slightly off-boundary after extended runtime, periodic distortion visible only in the ML feature vector, and stereo channels occasionally swapping. The fix was enforcing strict timing discipline in code rather than hardware: derive internal timing from I2S edge events instead of the system tick, reset frame counters on known LRCLK boundaries, add microsecond-resolution jitter detection, and enforce monotonic timestamps that reject out-of-order callbacks. These changes stabilized the entire framing pipeline without touching the PCB.

I2S framing and edge synchronization. One of the biggest early issues was incorrect framing logic. Different SoMs delivered I2S interrupts or DMA callbacks slightly differently, and the PCM1862's TDM and I2S modes behave differently under various clocking ratios. This led to frames shifted by half a sample, occasional collapsed samples, half-filled frames reaching the ML pipeline, and unexpected sample ordering under unusual load. We restructured the pipeline to treat LRCLK edges as absolute truth, validate that each DMA buffer aligns to a complete frame, run a state machine ensuring frame completeness before publishing, and detect and auto-recover from frame stitching errors. This was entirely a software fix and resolved misalignment across every SoM.

DMA starvation and interrupt pressure. The most deceptive issue was DMA starvation, not complete failure, not dropped buffers, just tiny delays from competing ISR load, cache pressure, memory bus contention, high-frequency timers, and background radio operations. That produced frames arriving slightly late, subtle jitter in sample timestamps, and ML models seeing inconsistent temporal windows. We redesigned the DMA and ISR behavior: elevated priority for audio DMA, ultra-light ISR handling that only pushes pointers, heavy work moved to a lock-free ring buffer in a worker thread, timestamp consistency checks, and starvation detection with automatic resync. This removed over 90 percent of timing artifacts with zero hardware modifications.

Buffering strategy and memory ownership. Early on we used a simple double-buffer strategy that worked fine idle but under load produced buffers overwritten before consumption, incomplete frames reaching the ML layer, occasional duplicate-frame anomalies, and silent degradation over long periods. That wasn't hardware stress, it was a buffer ownership problem. We replaced the double buffer with a multi-buffer ring with explicit ownership, atomic flags for producer and consumer transitions, strict frame lifecycle management, backpressure rules when downstream processing lags, and statistical buffer delay monitoring. Once buffering became deterministic and self-validating, audio stability held even under extreme system load.

Where this mattered across devices

For EverBowl's sound-event detection, ML accuracy improved once jitter-free, LRCLK-anchored timing was enforced. For EverHub's edge analytics, stable multi-buffer capture dramatically improved FFT and feature stability. For Tracker's lightweight sensing, this confirmed the resilience of our buffer ownership model under concurrency.

Takeaways

The major insight from integrating the PCM1862 across modular SoMs: audio instability in modern embedded systems is overwhelmingly a software design issue, not a hardware one. The fixes that mattered were all architectural decisions, LRCLK-anchored timing, deterministic DMA pacing, proper buffer ownership, priority-based ISR design, timestamp integrity, and validated frame boundaries. Once these were in place, all three Hoomanely devices achieved consistent, stable, drift-free audio behavior despite running on different SoM internal designs.