Skip to content

fix(ch32v): no SYSCLK_FREQ_* define injected - all CH32V firmware runs at reset-default HSI (2-18x under-clocked) #1119

Description

@zackees

Severity: CRITICAL — every CH32V board boots at its reset-default HSI clock, 2–18× slower than spec. FastLED clockless LED timing (the flagship downstream consumer) is broken on all parts, and the failure hides from a plain blink test.

Problem, in plain terms

The OpenWCH Arduino core does not configure the PLL by itself. It expects the build system to pass a macro like -DSYSCLK_FREQ_144MHz_HSI=144000000 — that macro selects which SetSysClock() branch gets compiled. At the pinned core commit (d767162), every system/<series>/USER/system_*.c ships with all SYSCLK_FREQ_* lines commented out, and the file says: "If none of the define below is enabled, the HSI is used as System clock source (default after reset)". So with no macro, SetSysClock() compiles to a no-op and the chip stays on raw HSI.

fbuild's board JSONs carry exactly the data needed (build.f_cpu + build.clock_source in all 18 CH32 JSONs) — but no Rust code reads clock_source, and nothing emits a SYSCLK_FREQ_* define. grep -r SYSCLK crates/ → zero hits (verified). The orchestrator (crates/fbuild-build-mcu/src/ch32v/orchestrator.rs:122-131) emits only F_CPU and the board extra_flags.

PlatformIO's community platform synthesizes the macro in builder/frameworks/common_clk_config.py from the same two fields; the vendor boards.txt clock menu does the equivalent. fbuild is the odd one out.

Worked example (what the bench will show)

CH32V203 board, f_cpu = 144000000:

  • fbuild passes -DF_CPU=144000000L and no SYSCLK define (verified in a real compile response file).
  • Firmware boots at 8 MHz HSI instead of 144 MHz — 18× slow.
  • SystemCoreClock is set to HSI_VALUE by the fallback branch, so millis()/delay()/UART baud are all self-consistentblink and serial look normal.
  • But anything compiled against F_CPU believes it runs at 144 MHz. FastLED's cycle-counted WS281x driver emits waveforms 18× too slow → dead/garbage LEDs.

Per-family reset-default vs claimed: V003/V006 24 MHz vs 48 (2×); V103 8 vs 72 (9×); V203/V208/V303/V307 8 vs 144 (18×); L103 8 vs 96 (12×); X035 48 MHz HSI but SystemInit sets HPRE=/6 → X035 blink is visibly ~6× slow (the one family where a naive test catches it).

Fix direction

In the CH32V orchestrator, map f_cpu + clock_source → the series' exact macro name and insert into defines alongside F_CPU. Two traps:

  1. Spelling differs per series/file: pinned CH32V00x/CH32VM00X use SYSCLK_FREQ_48MHz_HSI (MHz), the 1.0.4-era V00x file used SYSCLK_FREQ_48MHZ_HSI (MHZ). Take the exact strings from each pinned USER/system_*.c — do not generate blindly.
  2. Validate f_cpu against each series' supported PLL table (e.g. V203 supports 48/56/72/96/120/144 HSI) and fail loudly on an unsupported value instead of silently booting at HSI.

Model on PIO's common_clk_config.py (same input fields).

Acceptance

  • Compile response file for tests/platform/ch32v203 contains -DSYSCLK_FREQ_144MHz_HSI=144000000 (exact spelling from the pinned system_ch32v20x.c).
  • All 9 tests/platform/ch32* envs build.
  • Bench: X035 blink runs at correct speed; a V203 board drives WS2812 LEDs correctly via FastLED.
  • Unit test: unsupported f_cpu for a series → hard error naming the supported values.

Found during the 2026-07-21 CH32V bench-readiness sweep. Independently confirmed by two audit passes (code sweep + board-data sweep) and against the pinned core sources.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions