Firmware Overview¶
The BirdNET-STM32 firmware is a standalone bare-metal application for the STM32N6570-DK development board. It reads WAV files from an SD card, applies the selected frontend on-board, runs neural-network inference on the dedicated NPU, and reports bird species detections over UART.
Design principle
The firmware is a self-contained integration test and demo. Everything runs on the board — no host preprocessing, no streaming, no RTOS. This makes it easy to validate the full pipeline (audio → spectrogram → NPU → classification) in isolation.
At a Glance¶
| Property | Value |
|---|---|
| Language | C11 (ARM GCC 13+) |
| RTOS | None (bare-metal, single-threaded while(1) loop) |
| Board | STM32N6570-DK |
| CPU | Arm Cortex-M55 @ 600 MHz by default (800 MHz overdrive) |
| NPU | ST Neural-ART @ 800 MHz by default (1 GHz overdrive) |
| Build system | Overlay on ST's NPU_Validation Makefile |
| Flash method | GDB via n6_loader.py (part of X-CUBE-AI) |
Processing Pipeline¶
flowchart LR
SD["SD card<br/>WAV files"] --> WAV["wav_reader.c<br/>PCM16 → float32"]
WAV --> |Hybrid / Precomputed| STFT["audio_stft.c<br/>Hann + 512-pt FFT"]
WAV --> |Raw| NORM["Peak normalize"] --> NPU
STFT --> |Precomputed| Mel["audio_mel.c<br/>Mel Filterbank"]
STFT --> |Hybrid| NPU["NPU (LL_ATON)<br/>DS-CNN inference"]
Mel --> NPU
NPU --> UART["UART output<br/>top-K predictions"]
For each .wav file on the SD card:
- Read — parse RIFF/WAVE header, load the first chunk (2-3 seconds) as float32.
- Audio Frontend — depends on
APP_AUDIO_FRONTEND: - Hybrid: 512-point STFT with centred frames and a periodic Hann window, as
librosa.stft→[256, frames]magnitude spectrogram (Nyquist omitted), min-max normalized to [0, 1] like the host. - Precomputed: STFT followed by an explicitly mapped Mel filterbank →
[64, frames]. - Raw: Peak-normalize the PCM waveform, then pass it to the in-model Gabor frontend.
- NPU inference — copy features to NPU input, run the full DS-CNN (handling mel/PWL mappings intrinsically if required), read class scores.
- Output — print top-K species and timing over UART for host-side parsing.
Typical Performance¶
| Stage | Hybrid (24 kHz, 3.0 s) | Raw (24 kHz, 2.5 s) | Notes |
|---|---|---|---|
| SD read | ~86 ms | ~71 ms | Depends on card and chunk length |
| STFT | ~58 ms | 0 ms | Raw skips the FFT path |
| NPU inference | ~15 ms | ~12–13 ms | Model-dependent |
| Total | ~159 ms | ~84 ms | Both comfortably faster than real time |
Source Layout¶
firmware/
├── Src/
│ ├── main.c # Board init + processing loop
│ ├── wav_reader.c # RIFF/WAVE parser, PCM16→float32
│ ├── audio_stft.c # Hann-windowed STFT
│ ├── fft.c # 512-pt real FFT (radix-2 DIT)
│ └── sd_handler.c # BSP SD + FatFs mount/scan/write
├── Inc/
│ ├── app_config.h # Audio params (patched at deploy time)
│ ├── app_labels.h # Class names (auto-generated)
│ ├── wav_reader.h
│ ├── audio_stft.h
│ ├── fft.h
│ └── sd_handler.h
├── Drivers/
│ ├── HAL_SD/ # HAL SD card driver sources
│ ├── FatFs/ # FatFs R0.15 filesystem
│ └── stm32n6570_discovery_sd.* # BSP SD driver
└── README.md # Standalone firmware reference
Next Steps¶
-
Learn about the STM32N6570-DK board, Cortex-M55, NPU, memory map.
-
How to build the firmware and flash it to the board.
-
Adapt the firmware to your model and audio parameters.
-
Detailed reference for every C source file.
-
Serial output format and host-side parsing.
-
Common pitfalls, debugging hints, and known issues.