Troubleshooting¶
Common pitfalls, debugging hints, and known issues when working with the STM32N6570-DK firmware.
Cache Coherency¶
The #1 source of subtle bugs on the STM32N6.
The CPU DCache and the NPU see different views of SRAM. When you write data from the CPU that the NPU needs to read (or vice versa), you must explicitly manage the cache:
| Direction | Required Call | What It Does |
|---|---|---|
| CPU → NPU | SCB_CleanDCache_by_Addr(ptr, size) |
Flushes dirty cache lines to SRAM so the NPU sees fresh data |
| NPU → CPU | SCB_InvalidateDCache_by_Addr(ptr, size) |
Discards stale cache lines so the CPU reads the NPU's output |
Requirements:
- Buffers must be 32-byte aligned (one DCache line). Use
__attribute__((aligned(32))). - The
sizeparameter must be a multiple of 32 bytes (round up).
Symptoms of missing cache ops:
- NPU reads stale input → wrong predictions (often all zeros or identical scores for every file).
- CPU reads stale output → garbage scores, NaN values.
- Intermittent failures (cache sometimes coincidentally coherent).
// Correct pattern — from run_inference() in main.c
memcpy(input_ptr, spect, input_bytes);
SCB_CleanDCache_by_Addr((uint32_t *)input_ptr, (int32_t)input_bytes); // (1)
LL_ATON_RT_Main(&NN_Instance_Default);
SCB_InvalidateDCache_by_Addr((uint32_t *)output_ptr, (int32_t)output_bytes); // (2)
memcpy(output, output_ptr, output_bytes);
- Flush CPU writes to SRAM before NPU reads.
- Discard CPU cache after NPU writes.
XSPI Initialization Order¶
External memory init must happen before NPU_Config().
The NPU weights are stored in external NOR flash (memory-mapped at
0x7200_0000). If the NOR is not initialized and memory-mapped when the NPU
tries to read weights during LL_ATON_EC_Network_Init_Default(), you get a
bus fault (HardFault).
Correct order:
BSP_XSPI_RAM_Init(0)
BSP_XSPI_RAM_EnableMemoryMappedMode(0)
↓
BSP_XSPI_NOR_Init(0, &Flash)
BSP_XSPI_NOR_EnableMemoryMappedMode(0)
↓
NPU_Config()
RISAF_Config()
Symptom: HardFault immediately after LL_ATON_EC_Network_Init_Default(),
or the board appears to hang right after the [INIT] Configuring NPU... line.
TrustZone and RISAF¶
The STM32N6 boots in secure mode. The RISAF (Region Isolation and Security Access Filter) must be configured to allow the NPU to access its SRAM banks.
RISAF_Config() from misc_toolbox.c handles this. It opens the npuRAM
regions for NPU access.
Symptom: If RISAF is not configured before LL_ATON_EC_Network_Init_Default():
[ERROR] NPU network init failedon UART- Or a silent HardFault (no UART output at all if the fault happens before UART is fully initialized)
GDB Breakpoint: aiValidationInit()¶
The n6_loader.py flashing process depends on this function:
- GDB loads the
.elfinto SRAM. - GDB sets a hardware breakpoint at
aiValidationInit(). - GDB starts execution.
- Firmware runs init sequence (clocks, XSPI, NOR memory-mapping).
- Firmware hits the breakpoint.
- GDB flashes model weights into NOR via
STM32_Programmer_CLI. - GDB continues execution.
Do not rename or remove this function
The function body is just __asm volatile("nop"). It exists solely as a
breakpoint target. If it's missing, the flash process hangs indefinitely
waiting for the breakpoint to be hit.
Symptom: n6_loader.py hangs with "Waiting for breakpoint..." or similar.
SD Card Issues¶
8.3 Filename Limitation¶
FatFs with _USE_LFN=0 (default in NPU_Validation's ffconf.h) only supports
8.3 filenames. Longer names are truncated to ~1 form:
| Original Name | 8.3 Name |
|---|---|
Biodiversity_Recording_001.wav |
BIODIV~1.WAV |
forest_dawn_chorus.wav |
FOREST~1.WAV |
If you need long filenames, set _USE_LFN=1 in ffconf.h. This requires
extra heap memory for the LFN working buffer.
Card Not Detected¶
The BSP SD driver uses polling, not GPIO card-detect. You must:
- Insert the SD card before powering the board.
- Use a FAT32-formatted card (not exFAT).
- Use a quality card — Class 10 or UHS-I recommended.
Symptom: [ERROR] SD card mount failed on UART.
Slow Card Timeouts¶
Very slow cards can cause FatFs read timeouts. The BSP driver has a default timeout of ~1 second for each read operation.
Symptom: Random [SKIP] Cannot open file errors, especially on large files.
Fix: Use a faster card, or increase the timeout in the BSP SD driver configuration.
Sample Rate Mismatch¶
The firmware rejects WAV files whose sample rate doesn't match
APP_SAMPLE_RATE:
This is intentional. Resampling on the Cortex-M55 is possible but adds code complexity and processing time. The correct solution is to ensure test audio matches the model's training sample rate.
Tip
The board-test Python command resamples files automatically when
preparing the SD card. If you prepare the card manually, use a tool like
sox or ffmpeg:
FFT Size¶
The fft.c implementation is hardcoded for N=512 (256 complex points).
The twiddle tables, bit-reversal tables, and stack buffers are all sized for 512.
If you need a different FFT size:
- 1024-point: Would require doubling all tables and adding a 9th butterfly stage. Possible but requires code changes.
- 256-point: Would require halving tables and removing a butterfly stage.
- Arbitrary size: Would require a fully general FFT implementation (e.g., mixed-radix or split-radix).
For now, the model and firmware are locked to 512-point FFT. This provides 257 frequency bins and works well for the 24 kHz → 64-mel hybrid frontend.
assert_failed() and Error_Handler()¶
The HAL calls assert_failed() when an assert_param() check fails, and
Error_Handler() for general errors. Both are infinite loops in our firmware.
Debugging approach:
- Connect a debugger (ST-LINK + GDB or STM32CubeIDE).
- Set breakpoints in
assert_failed()andError_Handler(). - Trigger the failure.
- Inspect the call stack and the
file/lineparameters inassert_failed().
If you don't have a debugger, the symptoms are that UART output stops abruptly
(no === DONE === marker, the board appears to hang).
Common Error Messages¶
| UART Output | Cause | Fix |
|---|---|---|
[ERROR] xSPI NOR init failed |
External NOR flash not responding | Check board hardware, power cycle |
[ERROR] NPU network init failed |
NPU can't load model, or RISAF not configured | Check XSPI init order, RISAF config |
[ERROR] SD card mount failed |
SD card not inserted, not FAT32, or hardware issue | Re-insert card, reformat as FAT32 |
[SKIP] Sample rate X != Y |
WAV sample rate doesn't match model | Resample audio to correct rate |
[SKIP] Invalid WAV format |
Not a valid RIFF/WAVE PCM file | Convert to 16-bit PCM WAV |
[SKIP] Cannot open file |
FatFs can't open the file | Check 8.3 filename, card speed |
[ERROR] Inference failed |
NPU runtime error | Check model compatibility with stedgeai analyze |
| No output at all | Board not running, wrong serial port, wrong baud rate | Check USB connection, use 921600 baud |
Debugging with GDB¶
For deeper investigation, connect via GDB:
arm-none-eabi-gdb build/NPU_Validation.elf
(gdb) target remote :3333 # ST-LINK GDB server
(gdb) monitor reset halt
(gdb) break main
(gdb) continue
Useful breakpoints:
Error_Handler— catches HAL errorsassert_failed— catches HAL assertion failuresHardFault_Handler— catches memory access violationsrun_inference— inspect spectrogram and scores
Third-Party Components¶
| Component | License | Source |
|---|---|---|
| FatFs R0.15 | BSD-1-Clause | elm-chan.org |
| STM32N6xx HAL | BSD-3-Clause | STM32CubeN6 |
| BSP STM32N6570-DK | BSD-3-Clause | STM32CubeN6 |
| LL_ATON NPU Runtime | ST Proprietary | X-CUBE-AI 10.2.0 |
| sd_diskio driver | ST Proprietary | STM32CubeN6 FatFs middleware |