Skip to content

WIP: esp32c6: add ESP32-C6 platform support and loopback test suite - #11200

Draft
lgirdwood wants to merge 42 commits into
thesofproject:mainfrom
lgirdwood:feature/esp32c6-sof-port
Draft

lgirdwood wants to merge 42 commits into
thesofproject:mainfrom
lgirdwood:feature/esp32c6-sof-port

Conversation

@lgirdwood

Copy link
Copy Markdown
Member

Summary

This draft PR introduces Sound Open Firmware (SOF) platform support for Espressif ESP32-C6 (Single-core RISC-V @ 160 MHz) development boards:

  • Seeed Studio XIAO ESP32-C6 (Default Master Tx)
  • Waveshare ESP32-C6-Zero (Default Slave Rx)

Companion Zephyr DAI driver changes are pushed to lgirdwood/zephyr on branch feature/esp32c6-dai-port.


Key Changes

  1. ESP32-C6 Platform Support:
    • Added platform initialization, mailbox stubs, memory maps, and clocks in src/platform/esp32c6/.
    • Added board configurations and devicetree overlays for xiao_esp32c6/esp32c6/hpcore and esp32c6_devkitc/esp32c6/hpcore.
  2. Static Pipeline Architecture:
    • Implemented esp32c6_pipeline_def.c with S16_LE stereo playback and capture pipelines, intermediate buffers, and static volume kcontrols.
    • Guarded UAC2-specific macros and routed direct volume/pipeline triggers when USB Audio Class stack is not present.
  3. Dynamic DAI Discovery:
    • Replaced hardcoded component IDs in sof_static_pipeline_set_clock_mode() with dynamic topology iteration matching SOF_STATIC_COMP_DAI, preventing invalid pointer casting across topologies with different component layouts.
  4. Shell & Diagnostics:
    • Added sof cap dump <count> in esp32_shell.c to inspect captured PCM stereo waveforms directly from the console.
  5. Automated Verification:
    • Added scripts/test_c6_loopback.py to automate bidirectional hardware I2S loopback testing between XIAO and Waveshare with frame synchronization, RMS/pk-pk checks, and channel symmetry verification.

Hardware Loopback Verification

Executed bidirectional loopback between Seeed XIAO and Waveshare C6-Zero connected via GPIO 18 (BCLK), GPIO 19 (WS), GPIO 20 (DOUT), and GPIO 21 (DIN):

  • Forward Loopback (XIAO Master Tx -> Waveshare Slave Rx): PASS (max|L - R| = 0, RMS 5297, pk-pk 64632).
  • Reverse Loopback (Waveshare Master Tx -> XIAO Slave Rx): PASS (max|L - R| = 0, 1000 Hz, RMS 1414, pk-pk 4000).
  • Overall test suite returned exit code 0.

… PRE_START

- Update pipeline trigger from COMP_TRIGGER_START to COMP_TRIGGER_PRE_START
  so pipeline task is properly registered with the LL scheduler timer domain.
- Implement platform IPC initialization for ESP32-P4 to handle pipeline task replies.
- Configure LL scheduler stats logging every 1s (1024ms) window and adjust log levels.
- Set CONFIG_LOG_MODE_DEFERRED=y with 8KB buffer and overflow drop mode
  so real-time and LL scheduler threads never block synchronously on UART I/O.
- Set CONFIG_SYS_CLOCK_TICKS_PER_SEC=10000 for exact integer cycle division
  against the 16MHz SYSTIMER hardware clock and 1ms LL scheduler intervals.
- Retain LL thread priority at -16 (cooperative, non-preemptible) and ensure
  logging and shell threads run at lowest preemptible priority.
- Set CONFIG_TICKLESS_KERNEL=n and CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000
  for exact 1ms timer ticks matching the 16MHz hardware SYSTIMER.
- Set CONFIG_BUILD_OUTPUT_BIN=y to automatically trigger elf2image
  with --ram-only-header on west build.
…al buffer handling

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

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement RISC-V SIMD/DSP math routines mirroring Xtensa HiFi hotspots:
  * DRC: Horner's polynomial evaluations for log10_fixed, drc_lin2db_fixed,
    drc_log_fixed, drc_asin_fixed, drc_inv_fixed; fast knee_curveK, volume_gain,
    envelope tracking, and unrolled 4-sample output compression stage.
  * EQ: 4th-order cascaded biquad IIR DF1 (iir_df1_4th) and transposed DF2T
    (iir_df2t) with 64-bit MAC accumulators.
- Add CONFIG_FILTER_RISCV_SIMD and CONFIG_DRC_RISCV_SIMD Kconfig options.
- Add sof play <start|stop> shell command to control playback pipeline streaming.
- Update esp32p4 README with Generic C vs RISC-V SIMD MCPS benchmark comparison
  showing a 57.2% reduction in DRC computational overhead (18.93 vs 44.22 MCPS).

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

- Implement block processing in eq_iir_riscv.c with in-register biquad state
  variables, eliminating 98% of RAM load/store operations per block.
- Remove per-sample external C function call overhead in EQ IIR filtering.
- Implement branchless / predicted sat_clamp_q31 saturation across EQ & IIR math.
- Add CONFIG_EQ_IIR_RISCV_SIMD Kconfig option.
- Update esp32p4 README with updated MCPS benchmarks (Total Active DSP reduced
  to 73.27 MCPS / 22.2% reduction) and add TODO section for single-precision
  fast mode and Espressif RISC-V DSP SIMD extensions.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement contiguous interleaved stereo vector streaming in volume_riscv.c
  and volume_riscv_with_peakvol.c, replacing strided per-channel loops.
- Add branchless saturation and rounding for S16, S24, and S32 formats.
- Add CONFIG_VOLUME_RISCV_SIMD Kconfig choice option.
- Add sof vol <pb|cap> <dB> shell command for runtime volume attenuation.
- Update esp32p4 README with Volume SIMD architecture details.

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

- Enable native float execution (SOF_IPC_FRAME_FLOAT) across Volume, EQ IIR, and DRC modules.
- Implement pcm_converter float <-> integer conversions accelerated by ESP32-P4 RISC-V FPU (fmadd.s, fcvt.s.w, fcvt.w.s).
- Add float DF1 biquad math in iir_df1_float.h and coefficient conversion in iir_df1_float.c.
- Configure static pipeline intermediate stream buffers to 2048-byte float buffers with entry/exit conversion boundaries.
- Benchmark MCPS performance on target hardware: total full DSP chain reduced from 73.27 MCPS to 41.20 MCPS (43.8% reduction), utilizing only 10.3% of 400 MHz HP core.
- Update esp32p4 README with floating-point pipeline architecture and benchmark results.

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

- Add SOF_IPC_FRAME_FLOAT handling under CONFIG_FORMAT_FLOAT in TDFB.
- Implement sof_static_pipeline_set_capture_active() and sof_static_pipeline_set_tdfb_bypass().
- Add 'sof cap <start|stop>' command to ESP32 shell.
- Measure and document Capture MCPS performance and simultaneous Full-Duplex Playback + Capture load in esp32p4 README.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Add declarative static topology structures and builder macros in
  include/sof/audio/pipeline/static_pipeline.h.
- Implement generic topology loader engine in static_pipeline_loader.c
  to parse and instantiate static pipelines, components, routes, PCMs,
  and kcontrols.
- Migrate ESP32-P4 dual float playback & capture pipeline definition
  to src/platform/esp32p4/esp32p4_pipeline_def.c.
- Refactor sof_static_pipeline.c to delegate topology setup and control
  dispatch to the static topology loader.
- Add 'sof ctl <list|get|set>' commands to the debug shell to inspect
  and control static pipeline kcontrols at runtime.
- Update CMake build files and board Kconfig.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Add fir_float.h and fir_float.c providing fir_float() and dual-sample
  fir_float_2x() kernels with single-cycle fmadd.s FPU instructions.
- Fold Q1.15/Q2.30 normalization and out_shift directly into the float
  coefficients during initialization, eliminating runtime shifts.
- Optimize integer fir_generic.c with 2-way unrolled loops and 32-bit
  packed coefficient loads.

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

- Unroll integer conversion loops (s16_to_s24, s24_to_s16, s16_to_s32,
  s32_to_s16, s24_to_s32, s32_to_s24) by 4x and 8x for dual-issue RISC-V ILP.
- Add SOF_IPC_FRAME_FLOAT attenuation path in copier_generic.c.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement dcblock_generic_float() with single-cycle fmadd.s instructions.
- Add dcblock_float_default() to dcblock_fnmap supporting SOF_IPC_FRAME_FLOAT.
- Pre-scale fixed-point Q2.30 coefficients into float during setup.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement eq_fir_float() and dual-sample eq_fir_2x_float() kernels.
- Add eq_fir_setup_float() to convert and normalize coefficient blobs.
- Add SOF_IPC_FRAME_FLOAT support in set_fir_func() and IPC3 handlers.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Add crossover_state_float and crossover_split_float supporting 2-way,
  3-way, and 4-way Linkwitz-Riley 4th-order (LR4) band splitting.
- Leverage iir_df1_float biquads with single-cycle fmadd.s instructions.
- Add crossover_float_default() and register in crossover_proc_fnmap.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement float crossover band splitting and emphasis/deemphasis filters.
- Add multiband_drc_float_process_drc() with native float delay buffering.
- Register multiband_drc_float_default() in multiband_drc_proc_fnmap.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement mix_n_float() with 4-way loop unrolling for stereo streams.
- Add mix_float() and mix_float_gain() in mixin_mixout_generic.c.
- Add SOF_IPC_FRAME_FLOAT mappings to mixer, mux, and mixin/mixout tables.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement tdfb_core_float() leveraging dual-sample fir_float_2x().
- Add tdfb_fir_float() with interleaved frame beamforming and direction updates.
- Convert fixed-point filter bank coefficients to float during tdfb_init_coef().

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement fir_filter_generic_float() with float FPU MAC operations.
- Implement src_polyphase_stage_cir_float() for polyphase filtering stages.
- Register SOF_IPC_FRAME_FLOAT in src_prepare_general() and src_copy_sxx().

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement tone_float_default() using native FPU normalized scaling.
- Add SOF_IPC_FRAME_FLOAT support in tone-ipc3.c and tone-ipc4.c.
- Enable dynamic channel and rate query from sink buffer stream.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement asrc_fir_filter_float() with 4-way unrolled native FPU MACs.
- Optimize integer asrc_fir_filter16() and asrc_fir_filter32() with 4-way
  unrolled loops targeting the dual-issue RISC-V pipeline.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Replace all 29 non-HiFi sof_panic(0) stubs with complete generic ANSI C
  and RISC-V upmix, downmix, and shift-copy implementations across all
  surround channel geometries (1, 2.0, 3.0, 4.0, 5.0, 5.1, and 7.1).

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement level_multiplier_float() with 4-way unrolled FPU gain scaling.
- Optimize integer paths (s16, s24, s32) with 4-way loop unrolling.
- Add float gain tracking in level_multiplier_comp_data for runtime control.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Implement sel_float() and process_frame_float() with matrix coefficients.
- Provide safe fallback default configuration in selector_new().
- Support SOF_CTRL_CMD_ENUM in COMP_CMD_SET_VALUE and COMP_CMD_GET_VALUE.

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

- Add default configuration generator for selector components.
- Support SOF_STATIC_CTRL_ENUM in sof_static_kcontrol_set().
- Add sof_static_pipeline_trigger() for direct pipeline control.
- Guard trigger STOP operations against inactive pipelines to eliminate
  null pointer panics during early UAC2 terminal negotiation.
- Expand MAX_STATIC limits for pipelines, components, buffers, and controls.

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

- Define Pipeline 3 (TONE_TEST -> LEVEL_TEST -> SEL_TEST -> MIXER_PB).
- Register static kcontrols for Test Level Gain, Test Level Mute, and
  Test Selector Channel.
- Enable crossover, dcblock, multiband DRC, tone, level multiplier,
  selector, and mixer modules in board configuration.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
- Add section 3.4 to ESP32-P4 platform documentation detailing MCPS costs,
  cycle profiles, and percentage reductions for each accelerated module
  (eq_iir, drc, volume, eq_fir, tdfb, asrc, crossover, multiband_drc,
  tone, level_multiplier, selector, dcblock, mixer).

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

- Add board identity detection in usbd_init for Pallas (MAC ending in 0x17)
  and Ceres (MAC ending in 0x6C), assigning respective USB product strings.
- Set CONFIG_DMA_ESP32_MAX_DESCRIPTOR_NUM=64 for ring buffering.
- Enable bidirectional I2S0 BCK and WS pinmux in device tree overlay.
…uffering, and peek/consume

- Allow bursting up to 4 periods in dai_zephyr_multi_endpoint_copy on ESP32-P4
  to absorb host scheduling jitter and prevent DMA underruns/overruns.
- Fix audio stream converter direction for capture in set_new_local_buffer.
- Add 20ms pre-buffering in usb_audio to establish jitter margin before stream start.
- Implement peek and consume capture API to prevent data loss on USB send retries.
…clocking, and 64-period GDMA

- Detect board MAC in sof_static_pipelines_init to auto-configure Pallas (0x17)
  as clock master and Ceres (0x6C) as clock slave, switching DAI clock config.
- Route USB_PB -> VOL_PB -> DAI and DAI -> VOL_CAP -> USB_CAP with S16_LE
  stream formats and 65536 volume scale.
- Synchronize static kcontrol initialization on loader startup.
- Configure 64 DMA periods in zephyr/lib/dma.c for the ESP32-P4 GDMA driver.
…ace switching, and diagnostics

- Calculate host_period_bytes dynamically from sample rate, channels, and format
  in static pipeline reconfiguration instead of fixed period assumptions.
- Pass computed block_size dynamically when switching DAI mode at runtime.
- Update usb_audio to dynamically compute period_bytes and handle buffer chunks safely.
- Add sof regs, sof tone, and sof mute diagnostic shell commands.
- Size static pipeline buffers to 3072 bytes for high-resolution audio support.
… and mode switching

- Add static kcontrol ID 7 "DMIC Injector Switch" to dynamically toggle
  PDM DMIC Injector mode (Slave TX / external clock receiver).
- Implement sof_static_pipeline_set_dmic_injector() to reconfigure PDM DAI
  with DAI options = 1 (DMIC mode) and CBP_CFP clock polarity.
- Add sof dmic <enable|bypass> command and extend sof mode pdm to accept
  master, slave, or dmic.
- Increase shell stack size to 8192 to support complex command dispatch.
…ic routing

- Add Bluetooth LE Audio (BAP / LC3 @ 48kHz stereo) support utilizing the
  onboard ESP32-C6 co-processor via SDIO / GPIO 54 power control.
- Implement bt_audio component with zero-heap static ring buffers (10ms SDU).
- Implement bt_service to manage C6 power, scanning, and LE Audio broadcast.
- Extend sof_static_pipeline with dynamic 3-way endpoint routing:
  Route 0: USB <-> DAI (Default)
  Route 1: BT <-> DAI (DUT Audio Bridge)
  Route 2: USB <-> BT (PC to Bluetooth Broadcast)
- Add Kcontrols: ID 8 (BT Stream Switch), ID 9 (BT Stream Volume),
  ID 10 (Audio Endpoint Route).
- Add interactive shell commands: 'sof bt <status|broadcast|scan|power>'
  and 'sof route <usb_dai|bt_dai|usb_bt>'.
- Verified 100% pass on pre-commit loopback test suite (I2S: 93.88dB,
  PDM: 82.44dB, DMIC: 19.66dB).
- Add 'lgirdwood' remote (https://github.com/lgirdwood).
- Update 'zephyr' project to remote 'lgirdwood', branch 'feature/esp32p4-dai-port'.
- Whitelist and declare 'hal_espressif' project tracking 'lgirdwood/hal_espressif'
  on branch 'esp32p4-uac2' at 'modules/hal/espressif'.
…ack test suite

- Replace hardcoded component IDs 5 and 6 with dynamic topology iteration
  matching SOF_STATIC_COMP_DAI to prevent invalid component pointer casting
  on topologies with different component indexing (such as ESP32-C6).
- Add scripts/test_c6_loopback.py automated bidirectional I2S loopback test
  suite verifying forward and reverse audio transmission between Seeed Studio
  XIAO ESP32-C6 and Waveshare ESP32-C6-Zero.
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.

2 participants