Skip to content

WIP: teensy41: add PJRC Teensy 4.1 platform support, Audio PLL scheduling, S/PDIF loopback, and ARM Cortex-M7 SIMD optimizations - #11197

Draft
lgirdwood wants to merge 4 commits into
thesofproject:mainfrom
lgirdwood:feature/teensy41-sof-port
Draft

lgirdwood wants to merge 4 commits into
thesofproject:mainfrom
lgirdwood:feature/teensy41-sof-port

Conversation

@lgirdwood

@lgirdwood lgirdwood commented Sep 13, 2026 •

Copy link
Copy Markdown
Member

Summary

WIP: patches need split/squashed, contains commit from other PRs too.

Work in progress: Adds support for the PJRC Teensy 4.1 development board (NXP i.MX RT1062 Cortex-M7 @ 600 MHz with single-precision FPU, Audio PLL4, and eDMA) running Sound Open Firmware (SOF) with Zephyr USB Audio Class 2.0 (UAC2), and introduces Phase 1 & Phase 2 of ARM Cortex-M7 SIMD & DSP optimizations across hot-path audio processing modules.

All changes have been validated on a dual-board physical hardware test fixture (Board A Master Tx $\to$ Board B Slave Rx) over S/PDIF hardware loopback, achieving 140.81 dB SNR with 0 dropped frames.


Key Changes

1. Platform Support (platform/teensy41 & app/boards/teensy41)

  • NXP i.MX RT1062 Architecture:
    • Configures on-chip Audio PLL (PLL4) generating 688.128 MHz ($24\text{ MHz} \times (28 + 6720/10000)$).
    • Derived audio clocks:
      • SAI1 Clock: PreDiv /4, Podf /14 $\implies$ exact $12.288\text{ MHz}$ SAI1 MCLK ($256 \times 48\text{ kHz}$) and $1.536\text{ MHz}$ BCLK.
      • S/PDIF Clock: Root divided by 4 and 7 $\implies$ exact $24.576000\text{ MHz}$ clock root. S/PDIF internal divider divides by 8 $\implies$ exact $3.072000\text{ MHz}$ BMC bit clock ($64 \times 48.000\text{ kHz}$).
  • Hardware S/PDIF Transceiver & eDMA:
    • Pin 14 (SPDIF_OUT) and Pin 15 (SPDIF_IN) configured with fast slew rate (0x10B1).
    • Zephyr eDMA driver configured for stereo ping-pong with atomic 8-byte transfers.
    • Idle state BMC carrier transmission (SPDIF_SCR_TXFIFO_CTRL(0)) maintaining receiver PLL lock when idle.
  • Audio PLL-Driven Low-Latency (LL) Scheduling:
    • Period completion callbacks (dai_zephyr_dma_period_cb) from cyclic eDMA wake the LL scheduling thread every 48 audio frames (1.000 ms).
    • Automatically suppresses SysTick k_timer scheduling ticks while audio is active.
  • UAC2 Double Buffer Replenishment:
    • Instant double buffer replenishment on USB buffer release preventing capture underflow/overflow.

2. ARM Cortex-M7 SIMD & DSP Acceleration Framework (include/sof/audio/arm_simd.h)

Provides Cortex-M DSP intrinsics and inline assembly primitives with generic portable fallbacks:

  • Dual 16-bit packed multiply and multiply-accumulate: arm_smulbb, arm_smultt, arm_smlad, arm_smlald.
  • Single-cycle 32x32 $\to$ 64-bit accumulate: arm_smlal, arm_smull.
  • Dual 16-bit saturating addition: arm_qadd16.
  • 32-bit saturating addition: arm_qadd.
  • Branchless bit-accurate saturation: arm_sat_s16, arm_sat_s24.
  • Most-significant 32x32 multiply with rounding: arm_smmulr.
  • Halfword packing and extraction: arm_pkhbt, arm_pkhtb, arm_sxth.
  • Leading zero count normalization: arm_clz.

3. Audio Module Optimizations (Phase 1 & Phase 2)

  • volume & volume_with_peakvol:
    • S16 packed SIMD halfword processing, branchless S24/S32 math, and unrolled hardware float scaling (vmul.f32).
    • Branchless peak detection and volume metering.
  • math/iir_df1 & math/iir_df2t:
    • 5-term MAC throughput in single-cycle operations via SMLAL (32x32 $\to$ 64-bit accumulate) and branchless saturation.
  • eq_iir:
    • 64-sample block-accelerated IIR filtering maintaining filter state registers in ARM core registers.
  • drc & drc_math:
    • Fast single-cycle CLZ leading-zero normalization, Horner polynomial evaluation with SMMULR, and unrolled compressor loop.
  • math/fir & audio/eq_fir:
    • 4-tap unrolled FIR inner loops utilizing single-cycle SMLAL 64-bit MAC (fir_32x16).
    • Dual-sample fir_32x16_2x computing 2 consecutive samples per step, halving delay-line load operations.
    • S16, S24, and S32 2x streaming loops in eq_fir_arm.c.
  • audio/mixer:
    • Dual 16-bit saturating add in 1 cycle via arm_qadd16.
    • 32-bit saturating add via arm_qadd, 24-bit saturation via arm_sat_s24, and unrolled single-precision vector addition (vadd.f32).
  • audio/mixin_mixout:
    • IPC4 channel mixing accelerated with saturating SIMD adds and hardware gain multipliers (arm_smulbb, arm_smmulr, vfma.f32).
  • audio/dcblock:
    • Single-pole highpass filter accelerated with 64-bit signed MAC (arm_smlal / SMULL) and hardware float (vfma.f32).
  • audio/level_multiplier:
    • S16 dual-halfword processing (arm_smulbb/arm_smultt + arm_pkhbt), fast S24/S32 scaling (arm_smmulr), and dual-issue float scaling.
  • audio/pcm_converter:
    • S16 $\leftrightarrow$ S24 / S32 / Float format transformations with S24 sign-extension handling for S/PDIF SOF_IPC_FRAME_S24_4LE.
    • Direct dispatch tables for IPC3 (pcm_func_map) and IPC4 (pcm_func_vc_map).

4. Diagnostic & Automated Pre-Commit Verification Tools (scripts/)

  • scripts/test_teensy_loopback.py: Automated pre-commit verification tool supporting S/PDIF (--interface spdif) and SAI1 I2S (--interface i2s) loopback testing with FFT spectrum analysis, SNR calculation, and frame drop detection.
  • scripts/teensy_diag.py: Diagnostic tool decoding RT1062 S/PDIF (SCR, SRPC, STC, SRFM, SIS, SIE) and SAI1 registers.
  • scripts/teensy_flash.py: HalfKay USB HID bootloader flashing tool with auto-detect and USB port targeting.

Hardware Verification & Results

Verified on physical Teensy 4.1 hardware (Board A Master Tx $\to$ Board B Slave Rx over S/PDIF hardware transceiver):

================================================================================
 TEENSY 4.1 PRE-COMMIT HARDWARE LOOPBACK VERIFICATION REPORT
================================================================================
 Interface Mode:   S/PDIF Hardware Transceiver (Pin 14 ALT3 Tx -> Pin 15 ALT3 Rx)
 Playback Card:    hw:10,0 (Audio A / Master Tx)
 Capture Card:     hw:11,0 (Audio B / Slave Rx)
 Audio Parameters: 1000.0 Hz sine @ 48000 Hz, 16-bit Stereo, 4.0s duration
 SNR Acceptance:   >= 70.0 dB
--------------------------------------------------------------------------------
 Channel 0 (Left):  Peak=1000.0 Hz, Amplitude=28000, SNR=140.81 dB [PASS]
 Channel 1 (Right): Peak=1000.0 Hz, Amplitude=28000, SNR=140.81 dB [PASS]
 Dropped Frames:   0 (Continuous streaming verified)
--------------------------------------------------------------------------------
 OVERALL RESULT:    PASS (Achieved 140.81 dB >= 70.0 dB threshold)
================================================================================

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of lines (20,000). Try reducing the number of changed lines and requesting a review from Copilot again.

@lgirdwood

Copy link
Copy Markdown
Member Author

@dbaluta ARM SIMD in here.

@dbaluta

dbaluta commented Sep 15, 2026

Copy link
Copy Markdown
Collaborator

Thanks @lgirdwood will have a look!

@dbaluta

dbaluta commented Sep 17, 2026 •

Copy link
Copy Markdown
Collaborator

@lgirdwood this looks very promising tested the ARM SIMD instructions on imx8mp with M7 core, looks like the load for simple volume pipeline decreased by at least 30%. Also, looking to borrow an RT to do some more testing.

Extend IPC4 DAI gateway configuration to handle NXP i.MX digital audio interfaces:
- dai_config_dma_channel: return channel 0 for SOF_DAI_IMX_* instead of
  failing with SOF_DMA_CHAN_INVALID (-EINVAL).
- ipc_dai_data_config: set burst_elems = 2 for 32-bit stereo word transfers.
- dai_init_llp_info: skip Intel mailbox linear link position (LLP) slot allocation
  for SOF_DAI_IMX_* interfaces.
- include/ipc: define SOF_DAI_IMX_SPDIF and SOF_DAI_FMT_SPDIF with params struct.
- lib/dai: map SOF_DAI_IMX_SPDIF and SOF_DAI_IMX_SAI to Zephyr DAI devices and DMA channels.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
… publishing

- sof_static_topology_prepare_comps: skip components without attached buffer
  sources or sinks in bypass mode, and treat -ENOTCONN gracefully during prepare.
- sof_static_topology_init: publish s_active_topo before Stage 7 (init_controls)
  so that kcontrol setter operations during default value initialization can
  reference the active topology instead of failing with -ENODEV (-19).
- Reset s_active_topo to NULL on initialization failure unwinding.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…LL scheduling and UAC2

Add comprehensive platform support for PJRC Teensy 4.1 (NXP i.MX RT1062 Cortex-M7):
- platform/teensy41: Audio PLL4 configuration (688.128 MHz), SAI1 MCLK (12.288 MHz),
  on-chip S/PDIF transceiver clock root (/4, /7 => 24.576 MHz), fast slew rate pinmux,
  static pipeline topology, and memory heap allocation.
- app/boards/teensy41: add board overlay, Kconfig settings, and devicetree definitions
  for SAI1, S/PDIF transceiver (Pins 14 and 15 ALT3), and eDMA.
- dai-zephyr: drive Low-Latency (LL) scheduling domain from Audio PLL via cyclic eDMA
  period completion interrupts (dai_zephyr_dma_period_cb).
- zephyr_domain: suppress SysTick k_timer scheduling ticks when audio stream is actively
  driven by hardware audio domain clock.
- usb_audio: replenish UAC2 capture double buffer on packet completion and handle
  burst multi-packet reads to prevent endpoint underflow/overflow.
- syscalls: guard Zephyr syscall includes with CONFIG_USERSPACE for non-MMU architectures.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
…agnostic tools

- test_teensy_loopback.py: automated pre-commit hardware loopback test suite
  verifying SNR (>= 70.0 dB S/PDIF, >= 80.0 dB I2S), frequency accuracy, and
  zero dropped frames; includes two-pass ALSA device resolution and transient trimming.
- teensy_diag.py: inspect real-time S/PDIF registers (SCR, SRPC, STC, SRFM, SIS, SIE),
  SAI1 registers, eDMA TCD descriptors, and SOF component states via USB request 0xFC.
- teensy_flash.py: PJRC HalfKay USB HID flasher supporting automatic soft-reboot,
  multi-board targeting by USB port or serial, and direct hex programming.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
@lgirdwood
lgirdwood force-pushed the feature/teensy41-sof-port branch from 7ce7441 to 8e00e42 Compare October 15, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants