Clock Drift Compensation

Clock Drift Compensation (CDC) is mechanism used to handle situations when the audio clocks on both the record and playback devices are not exactly matched. A relevant example is when streaming audio through a SPARK RF link. One board will record the samples and the other one will play them back. The audio clock is asynchronous between both boards. This means that even if both audio master clocks are theoretically the same frequency and a sampling rate of 48 kHz is configured, the effective sampling rate on both boards could be slightly different due to crystal tolerances. This could lead to a device having a sampling rate of 47.980 kHz while the other has 48.030 kHz for example. In such situations, the clock drift needs to be compensated or some audio glitches will happen.

The CDC is done in two stages: drift detection and drift correction. The detection mechanism is basic and tailored around the use of a SPARK wireless link. For correction, the Audio Core provides two different approaches; one is software-based and the other is hardware-based.

Drift Detection Mechanism

The default detection mechanism provided by the Audio Core is the monitoring of the audio buffer (consumer queue) on the receiving end and averaging its load over time (sliding window). If the average is below a certain threshold (depleting) or over a certain threshold (filling), the audio clock will be considered “drifting” and a corrective action will be triggered. The audio header contains a bit called “TX queue level”. If that bit is set, the receiver/playback device will conclude that the audio buffer load variation is caused by bad RF link conditions (and not clock drifting), and therefore no corrective actions will be triggered in that case.

The average length should be decided based on the maximum amount of drift to be compensated. For example, if the maximum drift to be compensated is 100 ppm, the difference in number of samples generated between the two systems would be ((100 / 1000000)) * 48000) = 4.8. The consumer queue size averaging must thus be fast enough to measure every (1 / 4.8) = 0.2083 seconds and also have time to apply the drift correction mechanism.

Drift Correction Mechanisms

The Audio Core provides two different approaches to drift correction: software resampling and hardware Phase-Locked Loop (PLL) clock adjustment. Software resampling can be used on any hardware whereas PLL clock adjustment requires specific hardware features.

Software Resampling

Software resampling requires an interpolation method. By default, linear interpolation is used.

The SPARK resampling library uses a fixed block size (e.g., 1440 samples) to define the resampling period. The resampling period is thus block_size / sampling_rate (ex: 1440 / 48000 = 30 ms).

At the end of the resampling period, a new sample is either added or dropped. A sample is dropped when the audio clock on the playback device is slower than the one on the recording device, and a sample is added when the audio clock on the playback device is faster than the one on the recording device. CDC must be enabled only on the playback device and not on the recording device.

Impact on the audio signal

Adding or dropping one sample per resampling period is equivalent to a small, transient change of the effective sample rate. Because linear interpolation is applied between neighboring samples, the correction step behaves like a weak low-pass filter: content close to the Nyquist frequency is attenuated while the correction is in progress. In practice this appears as a very small amplitude drop on the highest audible frequencies whenever the resampler is actively adding or dropping samples. Correction accuracy is limited to \(\pm 1\) sample per resampling period.

Phase-Locked Loop (PLL) Adjustment

This mechanism leverages the hardware’s ability to precisely adjust its internal audio PLL. When a drift is detected through buffer load variations, a small adjustment is applied to the PLL’s fractional divider (FRACN) to bring the local audio clock closer to the remote one. The correction is continuous and fine-grained, resulting in minimal clock jitter.

Impact on the audio signal

PLL adjustment does not touch the audio samples: no interpolation, no add/drop, no amplitude change. Only the timing at which samples are clocked in or out of the codec is altered. The trade-off is a very small amount of jitter in the frequency spectrum of the played-back signal (the effective sample rate tracks the FRACN adjustments), which is inaudible for typical drift levels.

Hardware requirements. PLL-based CDC requires:

  • An audio PLL with a runtime-tunable fractional divider (FRACN) exposed by the device HAL through set_fracn/get_fracn callbacks. On the SPARK EVKs, this is provided by PLL2 of the Quasar STM32U5 MCU.

  • Direct control of the codec clock by the MCU. This means the MCU must drive either:

    • the I2S bit clock as master, or

    • the codec MCLK (as on Quasar, where the codec is I2S slave and derives its internal clocks from the MCU-provided MCLK).

Boards where the codec is the clock master and the MCU has no way to steer the audio clock (e.g., EVK1.4 with a fixed audio crystal driving the codec) cannot use PLL-based CDC and must fall back to software resampling.

Choosing Between Resampling and PLL

Aspect

Software Resampling

PLL Adjustment

Effect on audio samples

Modifies samples (add/drop with linear interpolation)

No modification of samples

Audible signature

Small high-frequency attenuation while correcting

Very small spectral jitter, typically inaudible

Correction resolution

\(\pm 1\) sample per resampling period

Sub-sample (limited by FRACN step)

Hardware requirement

None

Tunable FRACN + MCU control of codec clock (I2S master or MCLK output)

Portability

Works on any board

Works only when hardware supports it

Constraint When Multiple Streams Share a Clock Domain

A single MCU has one audio PLL that clocks both its I2S input and its I2S output. As a result, PLL-based CDC can only be applied to one direction at a time on a given device. If PLL is used to track the incoming stream, any outgoing stream on the same codec is tied to the same (now adjusted) clock and cannot be independently steered.

In a bidirectional setup, the recommended configuration is:

  • Use PLL adjustment on the primary stream that must remain sample-accurate (e.g., the high-quality music stream on the receiver).

  • Use software resampling on the secondary stream on the same device.

In practice, the remote device applies its own drift compensation on the secondary stream as well, so once both ends have converged the secondary resampler on the local device rarely needs to act. Its main role becomes initial latency alignment at startup (see next section), not continuous drift correction.

Drift Compensation vs. Latency Compensation

The CDC block performs two distinct jobs that are easy to confuse:

  • Drift compensation. Continuously matches the average consumption rate of the playback device to the production rate of the recording device, so that the receive queue neither empties nor overflows over long timescales. This is the ppm-level correction described above (resampling or PLL). Once the two clocks are aligned, no further corrective action is required until measurable drift reappears.

  • Latency compensation. Adjusts the steady-state fill level of the receive queue to hit a target playback latency. The CDC does this by driving corrections until the averaged queue level reaches its target queue size. If the current queue level is above the target, the CDC accelerates consumption (drops samples or speeds up the PLL) until the queue drains to the target. If it is below the target, it slows consumption until the queue fills up.

Latency compensation is what allows the target latency to be changed at runtime without stopping the pipeline: the application updates the CDC target queue size and the CDC steers the queue to the new operating point.

Variable Latency at Runtime

Because the CDC drives the queue to a configurable target, the pipeline latency can be switched on the fly by calling sac_cdc_ctrl (software resampling) or sac_cdc_pll_ctrl (PLL) with SAC_CDC_SET_TARGET_QUEUE_SIZE (or SAC_CDC_PLL_CMD_SET_TARGET_QUEUE_SIZE). The user picks a new target expressed in number of packets, and the CDC steers the queue toward that new operating point.

Hint

A target latency expressed in milliseconds can be converted to the equivalent queue depth in packets with the SAC_CALCULATE_LATENCY_QUEUE_SIZE macro from sac_utils.h. See Suggested RX Queue Depth for the underlying formula.

This is used by the puretone example applications to couple audio latency with the fallback mode:

  • The puretone_unidirectional and puretone_headset examples define one target latency per fallback mode (for example 5 ms, 7 ms, 10 ms, 15 ms). More aggressive fallback modes correspond to longer target latencies because their larger accumulated packets and lower over-the-air throughput increase jitter and demand more receive-side buffering.

  • Each fallback latency is converted to a queue depth at compile time with the SAC_CALCULATE_LATENCY_QUEUE_SIZE macro. The resulting values are stored in a small table indexed by fallback mode.

  • Whenever the pipeline consumes a packet, the application reads the current fallback mode and calls the CDC control API with the corresponding target queue size. The CDC then transparently drains or fills the queue until the new target is reached.

The receive queue itself must be sized for the largest target latency the application intends to use (it is a hard buffer capacity), but the CDC allows the effective latency to be reduced below that ceiling by keeping the queue only partially filled during normal operation. This is why the puretone applications only need one physical queue sized for the worst-case fallback mode, yet can operate at a much lower latency in normal mode.

Bidirectional Interaction During Latency Changes

Runtime latency changes on the PLL side of a bidirectional link have a side effect on the return path that must be accounted for when sizing the software resampling CDC on the remote device.

When the application lowers the PLL target queue size (for example, from 15 ms down to 5 ms), the PLL CDC accelerates the local audio clock to drain the queue faster than the incoming sample rate. This is intentional and works as designed for the primary stream. But because the PLL steers the shared audio clock of the device, the outgoing secondary stream is now clocked out at the same accelerated rate. From the perspective of the peer device, its incoming secondary stream suddenly exhibits a large apparent drift for the duration of the latency transition.

The software resampling CDC on the peer must be fast enough to absorb this transient drift without letting its own receive queue overflow. Two parameters matter:

  • Resampling period (cdc_resampling_length / sample_rate). This sets the minimum time between successive \(\pm 1\) sample corrections. A shorter period means the resampler can react to larger apparent drifts. A period that is too long compared to the PLL slew rate will lead to the peer’s queue drifting away from its target (potentially overflowing or underflowing) during the latency transition.

  • Detection averaging window (cdc_queue_avg_size). A shorter window makes drift detection more responsive but noisier. During PLL slew events, a shorter window helps the resampler engage quickly.

As a rule of thumb, the peer’s resampling CDC must be able to add or drop samples at least as fast as the PLL side is slewing its clock. If the PLL is configured to move from a 15 ms target down to a 5 ms target over N seconds, the peer must be able to consume the extra (15 - 5) ms of samples over the same N seconds, which requires the resampling period to be short enough that N times the correction rate exceeds (latency_delta / sample_period) samples.

In practice, applications that use variable latency on the PLL side should:

  1. Rate-limit the PLL target changes so the induced apparent drift on the return path stays within what the peer’s resampling CDC can absorb.

  2. Shorten the peer’s resampling period (reduce cdc_resampling_length) if the return path shows queue-level excursions during latency transitions.

  3. Keep in mind that latency transitions on the PLL side are typically triggered by fallback events, which also change the return-path packet size and jitter profile; both effects add up during the transition.

Warning

The CDC detection mechanism provided by the Audio Core does not support use cases with a single producer providing the same data to multiple consumers on the same device (e.g., codec as source (producer) and 4 different wireless connections as consumers).