Skip to content

Commit cbbca3a

Browse files
committed
[stm32wba, crypto] Implement support for the STM32WBA. Provide helper functions for crypto algos
1 parent afa461a commit cbbca3a

42 files changed

Lines changed: 5026 additions & 235 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
---
2+
name: port-stm32-platform
3+
description: Port a new STM32 chip family to wolfHAL. Creates the platform header, scaffolds new drivers, adds alias header + stub .c for reused drivers, and optionally wires up a first board.
4+
argument-hint: <platform-short-name> [chip-name] [board-name]
5+
---
6+
7+
# Port a new STM32 chip family to wolfHAL
8+
9+
You are helping the user port a new STM32 chip family (e.g., `stm32g4`, `stm32u5`, `stm32l5`) to wolfHAL. A "platform" in wolfHAL is a family of register-compatible chips that share drivers (e.g., `stm32wba` covers wba52/wba54/wba55). A specific chip (e.g., `stm32wba55cg`) gets its own platform header with concrete base addresses and clock macros. A board (e.g., `stm32wba55cg_nucleo`) ties a chip to a physical dev board.
10+
11+
Arguments passed after the skill name identify the scope:
12+
- `$1`: platform short name (required, e.g., `stm32g4`)
13+
- `$2`: specific chip (optional, e.g., `stm32g431cb`)
14+
- `$3`: board name (optional, e.g., `stm32g431_nucleo`)
15+
16+
If any are missing, ask the user before starting the relevant phase.
17+
18+
## Prerequisites — gather before starting
19+
20+
Ask the user to provide (or confirm paths to):
21+
22+
1. **Reference Manual (TRM) PDF** for the chip family — e.g., `stm32g4_trm.pdf`. Place at repo root.
23+
2. **Datasheet PDF** for the specific chip — e.g., `stm32g431cb.pdf`. Place at repo root.
24+
3. **Board user guide PDF** if adding a board — e.g., `nucleo_g431.pdf`. Place at repo root.
25+
26+
Do NOT proceed with register layout work without the TRM — guessing from similar chips is the #1 source of silent bugs. STM32 family differences (bit positions, register offsets, new CONDRST/FIFO/voltage-scaling fields) are subtle and costly to debug later.
27+
28+
## Phase 1 — Discovery (read-only, no code changes)
29+
30+
Goal: figure out what is register-compatible with an existing wolfHAL driver vs what needs a new driver.
31+
32+
For each device type below, use `pdftotext -layout -f <start> -l <end> <trm.pdf>` on the TRM to extract the register map page, then compare against existing wolfHAL drivers in `src/<type>/`:
33+
34+
| Device type | Existing drivers to diff against | What to check in TRM |
35+
|---|---|---|
36+
| Clock/RCC | `stm32wb_rcc.c`, `stm32wba_rcc.c`, `stm32h5_rcc.c`, `stm32f4_rcc.c` | PLL config register (PLLCFGR split vs unified), voltage scaling (PWR_VOSR), AHB/APB prescaler fields, HSI/HSE/LSI/LSE, peripheral clock enable register offsets (AHBxENR, APBxENR) |
37+
| GPIO | `stm32wb_gpio.c`, `stm32f4_gpio.c` | MODER/OTYPER/OSPEEDR/PUPDR/AFRL/AFRH — usually compatible across STM32 |
38+
| UART | `stm32wb_uart.c`, `stm32h5_uart.c`, `stm32c0_uart.c`, `stm32f4_uart.c` | BRR calc (16x vs 8x oversample), FIFO enable (CR1.FIFOEN bit 29), ISR/ICR flags, TDR/RDR offsets |
39+
| Flash | `stm32wb_flash.c`, `stm32wba_flash.c`, `stm32h5_flash.c`, `stm32f4_flash.c` | NSKEYR/KEYR unlock sequence, SR bit positions (BSY, EOP, errors), CR bit positions (PG, PER, STRT, LOCK, PNB), page size |
40+
| RNG | `stm32wb_rng.c`, `stm32wba_rng.c` | CR bits (RNGEN, CED, CONDRST), SR bits (DRDY, errors), clock source selection register (CCIPRx RNGSEL) |
41+
| I2C | `stm32wb_i2c.c` | CR1/CR2/TIMINGR — usually compatible on modern STM32 (V2 I2C) |
42+
| SPI | `stm32wb_spi.c`, `stm32h5_spi.c`, `stm32f4_spi.c` | CR1/CR2/SR layout (V1 SPI differs from V2 SPI used on newer chips) |
43+
| AES/crypto | `stm32wb_aes.c` | CR (KEYSIZE, MODE, CHMOD, ALGOMODE, DATATYPE), KEYR, IVR, DIN/DOUT |
44+
| DMA | `stm32wb_dma.c` (classic DMA+DMAMUX), `stm32wba_gpdma.c` (GPDMA) | Is it DMA+DMAMUX (older) or GPDMA (newer)? Not compatible. GPDMA appears on U5/WBA/H5/C0/G0 variants. |
45+
| Timer | `systick.c` (shared) | SysTick is architectural (Cortex-M), works unchanged |
46+
| IRQ | `cortex_m4_nvic.c`, `cortex_m33_nvic.c` | NVIC is architectural per core (M4 vs M33) |
47+
| Watchdog | `stm32wb_iwdg.c`, `stm32wb_wwdg.c` | IWDG/WWDG are very stable across STM32 |
48+
49+
For each device type, decide **reuse existing driver (with alias)** OR **write a new driver**. Write the decision to a checklist and show the user before starting Phase 2.
50+
51+
The clock driver is almost always new per family. GPIO, I2C, and IWDG/WWDG are almost always reusable. UART, flash, RNG, DMA require careful diffing.
52+
53+
## Phase 2 — Platform header
54+
55+
Create `wolfHAL/platform/st/<chip>.h` (e.g., `stm32g431cb.h`). Reference: `stm32wba55cg.h` (GPDMA chip) or `stm32wb55xx.h` (DMA+DMAMUX chip).
56+
57+
Conventions:
58+
1. Every driver include uses the **new platform's prefix** — for reused drivers that means the alias header created in Phase 3, not the original family's header.
59+
2. Every device macro uses `.driver = &whal_<NewPlatform><Type>_Driver` — the alias header `#define`s this to the original symbol at preprocess time, so no renaming of actual code is needed but callers see the new-prefix name.
60+
3. Defines clock enable macros and, when applicable, DMA request mapping macros.
61+
62+
Skeleton:
63+
64+
```c
65+
#include <wolfHAL/platform/arm/cortex_m4.h> /* or cortex_m33.h / cortex_m7.h */
66+
67+
/* Every include uses the new platform's prefix — aliased or newly written */
68+
#include <wolfHAL/clock/<platform>_rcc.h>
69+
#include <wolfHAL/gpio/<platform>_gpio.h>
70+
#include <wolfHAL/uart/<platform>_uart.h>
71+
/* ...one include per device type... */
72+
73+
#define WHAL_<PLATFORM>_USART1_DEVICE \
74+
.regmap = { .base = 0x<addr>, .size = 0x400 }, \
75+
.driver = &whal_<Platform>Uart_Driver
76+
77+
#define WHAL_<PLATFORM>_USART1_CLOCK \
78+
.regOffset = 0x<offset>, \
79+
.enableMask = (1UL << <bit>), \
80+
.enablePos = <bit>
81+
```
82+
83+
## Phase 3 — Drivers
84+
85+
### For each device type marked "write new"
86+
87+
1. Read `docs/writing_a_driver.md` for the driver pattern.
88+
2. Copy the closest existing driver as a starting point.
89+
3. Update register offsets, bit positions, and sequences per the TRM. **Cross-check register-map diagrams against the textual bit descriptions** — they sometimes disagree, and the textual description is authoritative.
90+
4. Match the existing naming: `whal_<Platform><Type>_<Func>` for functions, `whal_<Platform><Type>_Driver` for the vtable, `whal_<Platform><Type>_Cfg` for the config struct.
91+
5. Place files at `wolfHAL/<type>/<platform>_<type>.h` and `src/<type>/<platform>_<type>.c`.
92+
6. Do not add cross-driver calls from inside a driver — clock enables, power sequencing, flash wait states, pin muxing are the board's responsibility.
93+
94+
### For each device type marked "reuse existing driver" — create an alias header + stub .c
95+
96+
Reference pattern in-tree: `wolfHAL/gpio/stm32f4_gpio.h` (alias header) and `src/gpio/stm32f4_gpio.c` (stub). Every symbol the caller sees must carry the new platform's prefix; aliasing is done at preprocess time via `typedef` and `#define`, so no code is duplicated and no GCC alias attribute is needed.
97+
98+
**Alias header** — `wolfHAL/<type>/<newplatform>_<type>.h`:
99+
100+
```c
101+
#ifndef WHAL_<NEWPLATFORM>_<TYPE>_H
102+
#define WHAL_<NEWPLATFORM>_<TYPE>_H
103+
104+
/*
105+
* @file <newplatform>_<type>.h
106+
* @brief <NewPlatform> <Type> driver (alias for <OrigPlatform> <Type>).
107+
*
108+
* The <NewPlatform> <Type> peripheral is register-compatible with the
109+
* <OrigPlatform> <Type>. This header re-exports the <OrigPlatform> driver
110+
* types and symbols under <NewPlatform>-specific names. The underlying
111+
* implementation is shared.
112+
*/
113+
114+
#include <wolfHAL/<type>/<origplatform>_<type>.h>
115+
116+
/* Type aliases — one typedef per exposed type from the original header */
117+
typedef whal_<OrigPlatform><Type>_Cfg whal_<NewPlatform><Type>_Cfg;
118+
typedef whal_<OrigPlatform><Type>_PinCfg whal_<NewPlatform><Type>_PinCfg;
119+
/* ...repeat for every exposed type... */
120+
121+
/* Driver and function aliases — one #define per exposed function/driver */
122+
#define whal_<NewPlatform><Type>_Driver whal_<OrigPlatform><Type>_Driver
123+
#define whal_<NewPlatform><Type>_Init whal_<OrigPlatform><Type>_Init
124+
#define whal_<NewPlatform><Type>_Deinit whal_<OrigPlatform><Type>_Deinit
125+
/* ...repeat for every exposed function... */
126+
127+
/* Macro / enum-value aliases — one #define per user-facing macro */
128+
#define WHAL_<NEWPLATFORM>_<TYPE>_<CONST1> WHAL_<ORIGPLATFORM>_<TYPE>_<CONST1>
129+
/* ...repeat for every mode selector, port letter, pin-packing macro, etc... */
130+
131+
#endif /* WHAL_<NEWPLATFORM>_<TYPE>_H */
132+
```
133+
134+
**Stub .c** — `src/<type>/<newplatform>_<type>.c`:
135+
136+
```c
137+
#include "<origplatform>_<type>.c"
138+
```
139+
140+
That is the entire file. Examples in-tree: `src/gpio/stm32f4_gpio.c`, `src/gpio/stm32wba_gpio.c`, `src/i2c/stm32wba_i2c.c`, `src/uart/stm32wba_uart.c`, `src/watchdog/stm32wba_iwdg.c` — each is one line. The stub exists so the board's Makefile wildcard (`src/*/<newplatform>_*.c`) compiles the original implementation under the new-prefix filename. The original `.c` is NOT added to the Makefile separately; the `#include` pulls it into this translation unit exactly once.
141+
142+
### Common driver pitfalls (from prior ports)
143+
- **Flash**: check if already unlocked before writing keys — double-unlock hard-faults. Bit positions (LOCK, STRT, PNB) differ between families; do not copy-paste.
144+
- **RNG**: CONDRST + per-config register sequence goes in Init, not per Generate call. Select RNG clock source via `RCC_CCIPR`/`CCIPR2` before Init — default is often LSE, which requires LSE running.
145+
- **Clock**: on chips with voltage scaling, transition to VOS Range 1 BEFORE raising SYSCLK above ~16 MHz; skipping this hard-faults at the first PLL switch.
146+
- **DMA + USART**: enable `CR1.FIFOEN` when available — DMA→USART without FIFO has produced silent byte drops.
147+
- **Polling loops**: every hardware-flag wait must go through `whal_Timeout` — bare `while` loops violate a repo-wide preference.
148+
- **One-time hardware setup** (clock sources, trimming, feature selects): belongs in Init, not in per-operation functions.
149+
150+
## Phase 4 — Board (optional, only if $3 provided)
151+
152+
Create `boards/<board_name>/` with:
153+
154+
### `board.h`
155+
Exports `extern whal_<Type>` instances and declares `Board_Init`/`Board_Deinit`/`Board_WaitMs`. Follow `docs/adding_a_board.md`.
156+
157+
### `board.c`
158+
Define each `whal_<Type>` global with its platform macro + board-specific config (pins, baud rates, timeout, DMA channel assignments). Implement `Board_Init` in dependency order: PWR → Clock → peripheral clock enables → GPIO → UART → Timer → the rest. Keep the watchdog out of `Board_Init` (the app starts it when ready to refresh) per `docs/adding_a_board.md`. Guard DMA-specific setup under `#ifdef BOARD_DMA`, matching `boards/stm32wba55cg_nucleo/board.c`.
159+
160+
### `Makefile.inc`
161+
Model on `boards/stm32wba55cg_nucleo/Makefile.inc`:
162+
- `PLATFORM = <platform>` — matches the prefix used in `src/*/<platform>_*.c`
163+
- `TESTS ?= clock gpio flash timer rng crypto uart spi i2c irq` — trim to what the board supports
164+
- `CFLAGS``-mcpu=cortex-m4`/`cortex-m33` to match the core, `-DPLATFORM_<UPPER>` for platform ifdefs
165+
- `BOARD_SOURCE` wildcards over `$(WHAL_DIR)/src/*/<platform>_*.c` — picks up both native drivers and the alias stub `.c` files created in Phase 3. **Do NOT also wildcard over the original family's prefix**, or the original `.c` will compile twice (once directly, once through the stub's include) and you'll get duplicate-symbol errors at link time.
166+
167+
### `linker.ld`
168+
Copy from a similar board and update the `MEMORY` block's FLASH/RAM origins and lengths from the chip's datasheet.
169+
170+
### `ivt.c`
171+
Copy from a similar board with the same core (M4/M33). Update the vector table — vectors from position 16 onward are device-specific and listed in the TRM's interrupt mapping table. At minimum: SysTick plus any peripheral IRQs the tests exercise (USART1_IRQHandler, GPDMAx_ChannelY_IRQHandler, etc.).
172+
173+
## Phase 5 — Build and validate
174+
175+
1. `make BOARD=<board_name>` from the repo root. Fix errors in order. Typical failures:
176+
- Missing symbol for an aliased driver → the alias header is missing a `#define` for that function/type, or the stub `.c` isn't present.
177+
- Duplicate symbol → the Makefile is picking up both `<newplatform>_*.c` and the original `<origplatform>_*.c`; restrict the wildcard to the new prefix only.
178+
- Implicit declaration warnings for `whal_Reg_*` / `whal_SetBits` in a stub include → you probably wrote `#include <wolfHAL/...>` with angle brackets in the stub instead of `#include "<origplatform>_<type>.c"` with quotes. The stub must use quoted include so the preprocessor finds the sibling `.c` in the same directory.
179+
2. Flash the binary (user runs this) and run the test suite. Each suite prints `PASS`, `FAIL`, or `SKIP`.
180+
3. If UART output is garbled or missing bytes and the chip uses DMA, enable `CR1.FIFOEN` in the UART init before chasing further — DMA→USART without FIFO has caused byte drops on WBA.
181+
182+
## Output to the user
183+
184+
At each phase transition, summarize in under 10 lines:
185+
- What was done
186+
- Which existing drivers were reused (and note the alias header + stub `.c` pair created for each) vs newly written
187+
- What the user should verify or flash
188+
189+
Wait for the user to confirm before moving to the next phase, unless they asked for an all-in-one run upfront.

boards/peripheral/peripheral.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,11 @@ whal_Error Peripheral_Init(void)
6363
return err;
6464
}
6565

66-
#if PERIPHERAL_SENSOR_COUNT > 0
6766
for (size_t i = 0; g_peripheralSensor[i].dev; i++) {
6867
err = whal_Sensor_Init(g_peripheralSensor[i].dev);
6968
if (err)
7069
return err;
7170
}
72-
#endif
7371

7472
return WHAL_SUCCESS;
7573
}
@@ -78,13 +76,11 @@ whal_Error Peripheral_Deinit(void)
7876
{
7977
whal_Error err;
8078

81-
#if PERIPHERAL_SENSOR_COUNT > 0
8279
for (size_t i = 0; g_peripheralSensor[i].dev; i++) {
8380
err = whal_Sensor_Deinit(g_peripheralSensor[i].dev);
8481
if (err)
8582
return err;
8683
}
87-
#endif
8884

8985
for (size_t i = 0; g_peripheralFlash[i].dev; i++) {
9086
err = whal_Flash_Deinit(g_peripheralFlash[i].dev);

boards/stm32wb55xx_nucleo/Makefile.inc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ CFLAGS += -Wall -Werror $(INCLUDE) -g3 \
2020
-DWHAL_CFG_CLOCK_API_MAPPING_STM32WB_PLL \
2121
-DWHAL_CFG_RNG_API_MAPPING_STM32WB \
2222
-DWHAL_CFG_DMA_API_MAPPING_STM32WB \
23-
-DWHAL_CFG_CRYPTO_API_MAPPING_STM32WB_AES
23+
-DWHAL_CFG_CRYPTO_API_MAPPING_STM32WB_AES \
24+
-DWHAL_CFG_CRYPTO_AES_ECB -DWHAL_CFG_CRYPTO_AES_CBC \
25+
-DWHAL_CFG_CRYPTO_AES_CTR -DWHAL_CFG_CRYPTO_AES_GCM \
26+
-DWHAL_CFG_CRYPTO_AES_GMAC -DWHAL_CFG_CRYPTO_AES_CCM
2427
LDFLAGS = --omagic -static
2528

2629
LINKER_SCRIPT ?= $(_BOARD_DIR)/linker.ld
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
2+
3+
PLATFORM = stm32wba
4+
TESTS ?= clock gpio flash timer rng crypto uart spi i2c irq
5+
6+
GCC = $(GCC_PATH)arm-none-eabi-gcc
7+
LD = $(GCC_PATH)arm-none-eabi-ld
8+
OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy
9+
10+
CFLAGS += -Wall -Werror $(INCLUDE) -g3 \
11+
-ffreestanding -nostdlib -mcpu=cortex-m33 -mthumb \
12+
-DPLATFORM_STM32WBA -MMD -MP \
13+
$(if $(DMA),-DBOARD_DMA) \
14+
$(if $(filter iwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_IWDG) \
15+
$(if $(filter wwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_WWDG) \
16+
-DWHAL_CFG_CRYPTO_AES_ECB -DWHAL_CFG_CRYPTO_AES_CBC \
17+
-DWHAL_CFG_CRYPTO_AES_CTR -DWHAL_CFG_CRYPTO_AES_GCM \
18+
-DWHAL_CFG_CRYPTO_AES_GMAC -DWHAL_CFG_CRYPTO_AES_CCM \
19+
-DWHAL_CFG_CRYPTO_SHA1 -DWHAL_CFG_CRYPTO_SHA224 \
20+
-DWHAL_CFG_CRYPTO_SHA256 -DWHAL_CFG_CRYPTO_HMAC_SHA1 \
21+
-DWHAL_CFG_CRYPTO_HMAC_SHA224 -DWHAL_CFG_CRYPTO_HMAC_SHA256
22+
LDFLAGS = --omagic -static
23+
24+
LINKER_SCRIPT ?= $(_BOARD_DIR)/linker.ld
25+
26+
INCLUDE += -I$(_BOARD_DIR) -I$(WHAL_DIR)/boards/peripheral
27+
28+
BOARD_SOURCE = $(_BOARD_DIR)/ivt.c
29+
BOARD_SOURCE += $(_BOARD_DIR)/board.c
30+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*.c)
31+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/gpio.c)
32+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/clock.c)
33+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/uart.c)
34+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/timer.c)
35+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/supply.c)
36+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/flash.c)
37+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/spi.c)
38+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/i2c.c)
39+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/sensor.c)
40+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/watchdog.c)
41+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c)
42+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c)
43+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/block.c)
44+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/dma.c)
45+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/irq.c)
46+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/irq/cortex_m4_nvic.c)
47+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32wba_*.c)
48+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c)
49+
50+
# Peripheral devices
51+
include $(WHAL_DIR)/boards/peripheral/Makefile.inc

0 commit comments

Comments
 (0)