Skip to content

Add STM32C5 target (NUCLEO-C5A3ZG)#768

Open
dgarske wants to merge 1 commit intowolfSSL:masterfrom
dgarske:stm32c5
Open

Add STM32C5 target (NUCLEO-C5A3ZG)#768
dgarske wants to merge 1 commit intowolfSSL:masterfrom
dgarske:stm32c5

Conversation

@dgarske
Copy link
Copy Markdown
Member

@dgarske dgarske commented May 1, 2026

Summary

Adds wolfBoot support for the STM32C5 family, validated on the NUCLEO-C5A3ZG (STM32C5A3ZGT6, Cortex-M33, no TrustZone, 1 MB dual-bank flash with 8 KB pages and 128-bit ECC quad-word writes).

  • New HAL: hal/stm32c5.{c,h,ld} — flash (with per-quad-word ECC merging for unaligned writes), USART2 VCP, ICACHE, and a PSIS clock-up to 144 MHz (HSE 48 MHz reference -> PSI -> PSIS, all bus prescalers /1, flash 4 WS + WRHIGHFREQ delay 2). Mirrors STM32CubeMX's generated mx_rcc_init() for this target.
  • New test app: test-app/app_stm32c5.c and test-app/ARM-stm32c5.ld — LD2 (PG1, active-low) blink with v1 -> v2 update trigger and v2 confirm.
  • Build wiring: arch.mk adds the stm32c5 target, test-app/Makefile adds the per-target flags, and the example configs live at config/examples/stm32c5.config and config/examples/stm32c5-dualbank.config.
  • CI: .github/workflows/test-configs.yml builds three matrix entries on every PR — the default config, the same config with WOLFBOOT_RESTORE_CLOCK=0, and the dual-bank-swap config.
  • Docs: new STM32C5 section in docs/Targets.md (flash layout, clock paragraph, build/flash/test instructions, dual-bank-swap variant, TZEN-not-supported note).

Highlights

144 MHz clock-up. clock_psi_on() brings SYSCLK from the post-reset HSIDIV3 (16 MHz) up to 144 MHz via the PSIS clock chain, mirroring the ST HAL bring-up sequence. Each polling loop has a generous timeout that, on failure, returns and falls back to the reset clock so the bootloader still runs (just slower); the SYSCLK-switch timeout also short-circuits the 144-MHz-only FLASH_ACR.WRHIGHFREQ write so a stuck switch can't leave flash configured for a frequency the chip isn't actually running at. USART2_BRR is computed for PCLK1 = 144 MHz and resolves to 1250 exactly for 115200 baud.

Lightweight hal_prepare_boot() clock restore. When WOLFBOOT_RESTORE_CLOCK is set (project default in options.mk), hal_prepare_boot() switches SYSCLK back to HSIDIV3 before handoff but leaves PSIS, PSI and HSE running. The loaded firmware's own clock_psi_on() then fast-paths through the HSE/PSI bring-up (everything already configured) and just bumps SYSCLK back to PSIS. This mirrors ST's HAL_RCC_ResetSystemClock() rather than the full HAL_RCC_Reset(). A full HSE/PSI tear-down was prototyped and works for the v1 boot loop (each cycle ends in a hardware reset) but breaks the swap-then-jump path where wolfBoot completes the partition swap, runs clock_psi_off(), and jumps directly into the loaded firmware without a reset between — the crystal does not always restart cleanly in that window. Hardware-tested both WOLFBOOT_RESTORE_CLOCK=1 (default) and =0 end-to-end.

Pre-clock-switch UART drain. hal_prepare_boot() polls USART2_ISR.TC to make sure the TX shift register has fully emptied before the SYSCLK switch — otherwise the trailing byte of wolfBoot's last UART line was being shifted out at the wrong baud and showed up as a glitch byte at the start of the loaded firmware's first line.

128-bit ECC writes. hal_flash_write() always assembles 16-byte aligned quad-words from the caller buffer (two memcpys: read existing flash, overlay caller bytes), so every programmed quad-word is a complete ECC block. Sub-quad-word writes leave per-quad-word ECC undefined and reads come back with bit-flipped "corrected" data, so the merge step is mandatory. Errors from the FLASH controller (WRPERR / PGSERR / STRBERR / INCERR / OPTCHANGEERR) are checked after every program / erase and propagated as -1. The erase loop uses an end-exclusive bound so single-page erases actually run, and hal_flash_opt_lock() does not unconditionally trigger OPTSTRT (which would be a foot-gun on a function called *_lock).

system_reset() preserves PRIGROUP and adds DSB barriers so the SYSRESETREQ write doesn't clobber unrelated AIRCR fields and pending stores complete before reset.

DUALBANK_SWAP variant (new, config/examples/stm32c5-dualbank.config). Uses the chip's FLASH_OPTCR.SWAP_BANK option byte (bit 31) to flip which physical bank is mapped at 0x08000000, replacing the copy-based swap with a single option-byte toggle and a system reset. hal_flash_dualbank_swap() reads FLASH_OPTSR_CUR.SWAP_BANK, toggles via FLASH_OPTSR_PRG, kicks FLASH_OPTCR.OPTSTRT, and triggers SYSRESETREQ (no separate OBL_LAUNCH register on this chip — the new bank mapping kicks in on the resulting reset). fork_bootloader() runs from hal_init() on first boot and copies wolfBoot from bank 1 to bank 2 if they differ, so the chip can boot from 0x08000000 regardless of which physical bank SWAP_BANK currently maps there. Hardware-tested: stage v2 at 0x08090000, reset, observe Versions: Boot 1, Update 2 -> Versions: Boot 2, Update 1, App version: 2, update OK -- success confirmed.

TZEN is not supported on this silicon. __SAUREGION_PRESENT is 0 in the CMSIS device header, no GTZC, no FLASH_NS_* / FLASH_SECCR* aliases, no secure peripheral address space — the hardware needed to partition memory and peripherals into secure / non-secure worlds is absent. The L5 / U5 / H5 TrustZone ports cannot be ported to the C5. For application security on the C5 use the MPU (__MPU_PRESENT 1U) and flash RDP. This is a deliberate roadmap close-out, documented in docs/Targets.md.

Flash layout

Default (copy-based update, config/examples/stm32c5.config):

Bank 1 (0x08000000 - 0x0807FFFF):
  0x08000000 - 0x0800FFFF   wolfBoot bootloader   (64 KB)
  0x08010000 - 0x0807FFFF   BOOT partition        (0x70000, 448 KB)

Bank 2 (0x08080000 - 0x080FFFFF):
  0x08080000 - 0x080EFFFF   UPDATE partition      (0x70000, 448 KB)
  0x080F0000 - 0x080F1FFF   SWAP sector           (8 KB)

Dual-bank swap (config/examples/stm32c5-dualbank.config):

Bank 1 (active by default):
  0x08000000  wolfBoot                 (64 KB)
  0x08010000  BOOT partition           (448 KB)

Bank 2 (active after FLASH_OPTCR.SWAP_BANK toggle):
  0x08080000  wolfBoot copy            (64 KB)
  0x08090000  UPDATE partition         (448 KB)

Default signing scheme is ECC256 + SHA256.

@dgarske dgarske self-assigned this May 1, 2026
@dgarske dgarske requested review from Copilot and danielinux May 1, 2026 22:44
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds wolfBoot support for the STM32C5 family (validated on NUCLEO-C5A3ZG) by introducing a new STM32C5 HAL, a test application + linker script, example configuration, build/CI wiring, and target documentation.

Changes:

  • Added STM32C5 HAL implementation and linker script (hal/stm32c5.{c,h,ld}).
  • Added STM32C5 test app + build integration (test-app/app_stm32c5.c, test-app/ARM-stm32c5.ld, test-app/Makefile, arch.mk).
  • Added docs + CI build coverage (docs/Targets.md, .github/workflows/test-configs.yml, config/examples/stm32c5.config).

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
test-app/app_stm32c5.c New STM32C5 bare-metal test app exercising versioning + update trigger/confirm.
test-app/Makefile Adds stm32c5 target flags + flash write-once define for test app builds.
test-app/ARM-stm32c5.ld New test-app linker script template for STM32C5.
hal/stm32c5.ld New wolfBoot linker script for STM32C5 memory layout.
hal/stm32c5.h New STM32C5 register/memory map definitions and cache/reset helpers.
hal/stm32c5.c New STM32C5 HAL: flash ops (quad-word/ECC), UART2, cache, clock init.
docs/Targets.md Adds STM32C5 target documentation section + TOC entry.
config/examples/stm32c5.config Adds an STM32C5 example config consistent with the described flash layout.
arch.mk Wires stm32c5 target into ARM arch build settings.
.github/workflows/test-configs.yml Adds CI matrix entry to ensure stm32c5 config builds.
Comments suppressed due to low confidence (2)

test-app/app_stm32c5.c:1

  • num is sized for at most 3 digits + NUL, but wolfBoot_current_firmware_version() returns a uint32_t. Versions >= 1000 will either overflow num or produce incorrect ASCII (e.g., '0' + (v/100) when v/100 > 9). Use a larger buffer and a bounded formatting approach (e.g., snprintf) or explicitly clamp/handle higher versions.
/* app_stm32c5.c

test-app/app_stm32c5.c:1

  • This file defines both active-high (led_on/off) and active-low (led_active_low_on/off) control paths, but the rest of the test app uses only the active-low variants. Consider removing the unused active-high helpers (or aliasing the correct polarity via a single led_on/off implementation) to avoid confusion about the board’s LED polarity.
/* app_stm32c5.c

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hal/stm32c5.c Outdated
Comment thread hal/stm32c5.c Outdated
Comment thread hal/stm32c5.c Outdated
Comment thread hal/stm32c5.c Outdated
Comment thread hal/stm32c5.c
Comment thread test-app/app_stm32c5.c Outdated
Comment thread docs/Targets.md Outdated
@dgarske dgarske changed the title Add wolfBoot support for the STM32C5 (tested on NUCLEO-C5A3ZG) Add STM32C5 target (NUCLEO-C5A3ZG) May 4, 2026
@dgarske dgarske requested a review from Copilot May 4, 2026 21:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hal/stm32c5.c
Comment thread hal/stm32c5.c Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/Targets.md Outdated
Comment thread hal/stm32c5.c Outdated
Comment thread hal/stm32c5.c Outdated
Comment thread hal/stm32c5.c Outdated
Comment thread hal/stm32c5.c
Comment thread test-app/ARM-stm32c5.ld Outdated
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