BERGSONNE

Audio (PDM mic)

A PDM digital microphone emits a 1-bit sigma-delta bitstream clocked at a few megahertz. The SAI drives that clock and DMAs the raw bitstream into RAM (hal_sai); a software CIC decimator (core_pdm) then low-pass-filters and downsamples it to signed-16 PCM. Use the Core / HAL / LL toggle at the top of the sidebar to switch layers.

Overview

The PDM interface on the SAI clocks one or more microphone pairs and de-interleaves their bitstreams. On the WBA there is a single SAI and no hardware decimator, so the path is: SAI in PDM master-RX mode generates the bit clock and captures the raw 1-bit stream over GPDMA, then the application decimates in software. There is no Studio DSL block for audio — capture is escape-to-C; the Core layer here is the core_pdm decimator helper, with core_audio as a thin convenience wrapper that ties the SAI and the decimator together.

SAI availability
The SAI (and therefore PDM capture) is present on Core.ST.W5, Core.ST.L4, and Core.ST.H5. Core.ST.L0 has no SAI.

Capturing the bitstream

core_audio wraps the whole pipeline: it configures the SAI for the microphone’s data/clock lines, starts a circular GPDMA capture, and runs the decimator on each half-buffer, handing you finished PCM through a callback.

#include "core_audio.h"

static uint8_t  pdm[4096] __attribute__((aligned(4)));  // raw bitstream
static int16_t  pcm[256];                                // decimated output
static core_audio_t mic;

static void on_pcm(const int16_t *samples, uint32_t n, void *ctx) {
    // n PCM samples ready (per DMA half-buffer)
}

// kernel clock, PCM rate, data line (SAI_D2), clock line (CK2),
// CIC order, extra gain shift:
core_audio_init(&mic, 16000000, 16000, 2, 2, 4, 0);
core_audio_start(&mic, GPDMA1_CH0, pdm, sizeof pdm, pcm, on_pcm, NULL);
// route GPDMA1_Channel0_IRQHandler -> core_audio_irq(&mic)

Decimating to PCM

core_pdm is an integer CIC decimator (N integrator stages at the bit rate, a /R downsample, N comb stages) followed by a one-pole DC blocker. Feed it successive DMA half-buffers — filter state carries across calls, so block boundaries are seamless. The decimation factor is the PDM clock divided by the output rate (e.g. 2.048 MHz / 128 = 16 kHz).

#include "core_pdm.h"

static int16_t pcm[256];
static core_pdm_cic_t cic;

core_pdm_init(&cic, 4, 128, 0, 0);   // order 4, /128, unity gain, MSB-first

// in the SAI DMA half/complete callback:
uint32_t n = core_pdm_process(&cic, pdm_half, half_bytes, pcm);
//   gain_shift (arg 4) is an extra left shift on the output — lift it to
//   pull up a quiet mic; a single-mic capture takes the first slot byte.

Cross-architecture support

PDM capture rides on the SAI, which is present on the W5, L4, and H5 Cores (not L0). The decimator is portable integer C and runs anywhere. See the implementation status for the full matrix.

API reference

Lower-level · Tier 1
void core_pdm_init(core_pdm_cic_t * st, uint8_t order, uint16_t decimation, uint8_t gain_shift, uint8_t lsb_first);
Initialise a CIC decimator.
uint32_t core_pdm_process(core_pdm_cic_t * st, const uint8_t * pdm, uint32_t nbytes, int16_t * out);
Decimate a block of packed PDM bits into PCM samples.

Generated from core_pdm.htiles@1f69849.