Repository navigation
Description
Symptom
FastLED's Ports/PJRCSpectrumAnalyzer example fails to link on Teensy 3.x under fbuild:
.lto-tmp/.../AudioAnalyzeFFT1024::update():
undefined reference to `arm_cfft_radix4_q15'
.lto-tmp/...:
undefined reference to `arm_cfft_radix4_init_q15'
collect2: error: ld returned 1 exit status
These symbols come from CMSIS-DSP (libarm_cortexM4lf_math.a for Teensy 3.5/3.6, similarly for 3.0/3.1/3.2; libarm_cortexM7lfsp_math.a for Teensy 4.x).
Reproducible: every FastLED teensy36 run on master (e.g. https://github.com/FastLED/FastLED/actions/runs/26684937829).
Root cause / delta
Under PlatformIO + Teensyduino, the framework's SCons builder script (teensy.py in the platform package) auto-appends the correct CMSIS-DSP library to the link command based on the MCU. The user doesn't have to list it in lib_deps.
Under fbuild, that SCons logic doesn't run. fbuild builds the project using its own link command, and CMSIS-DSP is not added — so any Teensy library that uses CMSIS-DSP (notably Audio.h's FFT classes) fails at link.
Since FastLED switched to fbuild as the default backend (f215b56b8), this regressed.
CI workflows blocked
teensy36— fails onPorts/PJRCSpectrumAnalyzer(FFT)teensy30— generic link failure; likely the same underlying class but a different example (verify separately)- Any Teensy build that uses
Audio.hFFT will share this failure.
Proposed shape
In fbuild-build (or wherever per-MCU link flags are assembled), add CMSIS-DSP auto-link for Teensy MCUs mirroring Teensyduino's matrix:
| MCU | Library |
|---|---|
| ATSAMD21 | libarm_cortexM0l_math.a |
| MK20DX128/256 | libarm_cortexM4l_math.a |
| MK64FX512 (3.5) | libarm_cortexM4lf_math.a |
| MK66FX1M0 (3.6) | libarm_cortexM4lf_math.a |
| MKL26Z64 (LC) | libarm_cortexM0l_math.a |
| IMXRT1062 (4.x) | libarm_cortexM7lfsp_math.a |
Either resolve via BoardConfig.mcu and hardcode the table, or expose a board JSON field (e.g. build.lib_ldflags or build.cmsis_dsp_lib) that the bundled JSONs can populate from the upstream Teensy boards.txt (build.fpu + recipe.c.combine.pattern carry the info).
The library ships inside the Teensyduino toolchain (framework-arduinoteensy@.../cores/teensy*/), already on disk via the fbuild toolchain cache — no extra download needed.
Immediate FastLED unblock
I'm not adding a FastLED-side workaround for Ports/PJRCSpectrumAnalyzer here — the example is meant to work on Teensy 3.5/3.6/4.x per its own comment block. Filter syntax can't cleanly distinguish 3.x from 4.x on a single memory tier, and gutting the example with #ifdefs to compile to a no-op is worse than leaving the workflow red while this is in flight.
PR-3 in my coordinated sweep is being deferred to teensy36 greening up once this lands.
Test plan
- Unit: extend the board JSON test to assert teensy36's
BoardConfig.cmsis_dsp_lib(or whatever the field is called) resolves tolibarm_cortexM4lf_math.a. - Integration: re-run FastLED
teensy36workflow, confirmPorts/PJRCSpectrumAnalyzerlinks.
Filed during a coordinated CI-green sweep; blocking PR-3 in that sweep.
Activity
fix(teensy): auto-link Teensyduino CMSIS-DSP per-MCU (#300) (#313)
ci: add enrich_extra_flags.py for re-runnable PIO extra_flags sweep
ci: add enrich_extra_flags.py for re-runnable PIO extra_flags sweep (#…