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.

Core.ST.W5 only
PDM capture needs an SAI, and only Core.ST.W5 (STM32WBA55) has one. The L0, L4 and H5 have no SAI, so core_audio.h refuses to compile there. The core_pdm decimator itself is portable C and runs anywhere, if a bitstream reaches it some other way.

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 only the W5 has. There it compiles and captured audio on silicon during bring-up, but has no recorded bench test yet. The decimator is portable integer C and runs anywhere. See the implementation status for the full matrix.

·L0M0+·L4M4●W5M33·H5M33WCH (RISC-V) · Nordic (nRF54) — in development

API reference

Lower-level · Tier 1
hal_status_t core_audio_init(core_audio_t * a, uint32_t kernel_clk_hz, uint32_t pcm_rate_hz, uint8_t data_line, uint8_t clock_line, uint8_t cic_order, uint8_t gain_shift);
Configure the mic: SAI PDM block + decimator (capture not started).
hal_status_t core_audio_start(core_audio_t * a, GPDMA_Channel_TypeDef * ch, uint8_t * pdm_buf, uint32_t pdm_len, int16_t * pcm_buf, core_audio_pcm_cb on_pcm, void * user_ctx);
Start continuous capture; `on_pcm` fires per half-buffer with PCM.
void core_audio_stop(core_audio_t * a);
Stop capture.
void core_audio_irq(core_audio_t * a);
Route the capture channel's GPDMA IRQ here.
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_audio.h, core_pdm.h — tiles@f70bca2.