Skip to content

Commit 9c1b142

Browse files
authored
Merge pull request #33 from AlexLanzano/stm32f0
[stm32f0] Implement initial support for stm32f0
2 parents fabe894 + 3d35466 commit 9c1b142

33 files changed

Lines changed: 2044 additions & 12 deletions

.claude/skills/port-stm32-platform/SKILL.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,14 @@ typedef whal_<OrigPlatform><Type>_PinCfg whal_<NewPlatform><Type>_PinCfg;
140140

141141
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.
142142

143+
**Test alias** — when a driver is reused via alias AND the original driver already has a platform-specific test file (`tests/<type>/test_<origplatform>_<type>.c`), create a matching test alias at `tests/<type>/test_<newplatform>_<type>.c`:
144+
145+
```c
146+
#include "test_<origplatform>_<type>.c"
147+
```
148+
149+
This is the same one-line pattern as the driver stub. The build system auto-discovers `test_$(PLATFORM)_$(t).c` files and defines `WHAL_TEST_ENABLE_<TYPE>_PLATFORM`, which gates the `whal_Test_<Type>_Platform()` call in `tests/main.c`. Examples in-tree: `tests/gpio/test_stm32c0_gpio.c`, `tests/gpio/test_stm32f0_gpio.c`.
150+
143151
### Common driver pitfalls (from prior ports)
144152
- **Flash**: check if already unlocked before writing keys — double-unlock hard-faults. Bit positions (LOCK, STRT, PNB) differ between families; do not copy-paste.
145153
- **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.
@@ -158,6 +166,9 @@ Exports `extern whal_<Type>` instances and declares `Board_Init`/`Board_Deinit`/
158166
### `board.c`
159167
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`.
160168

169+
### GPIO pin conflict check
170+
After writing the `pinCfg` array in `board.c`, scan every entry pair and verify no two entries share the same physical port+pin. This is a common mistake when a pin serves double duty (e.g., PA5 used as both an LED and SPI1_SCK). If a conflict is found, consult the chip's alternate-function table in the datasheet and remap the conflicting peripheral to an alternate pin on a different port.
171+
161172
### `Makefile.inc`
162173
Model on `boards/stm32wba55cg_nucleo/Makefile.inc`:
163174
- `PLATFORM = <platform>` — matches the prefix used in `src/*/<platform>_*.c`
@@ -171,6 +182,14 @@ Copy from a similar board and update the `MEMORY` block's FLASH/RAM origins and
171182
### `ivt.c`
172183
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.).
173184

185+
### boards/README.md
186+
187+
Add a row to the **Supported Boards** table in `boards/README.md` with the board name, platform, CPU core, and directory. Keep the table sorted alphabetically by platform name.
188+
189+
### GitHub CI
190+
191+
Add the new board to `.github/workflows/boards.yml` by appending it to the `board` matrix list. This ensures the board builds are verified on every PR and push to main. If the board supports peripheral devices (BMI270, SPI-NOR, etc.), also add entries to `.github/workflows/peripheral-tests.yml`. If it supports watchdog, add entries to `.github/workflows/watchdog-tests.yml`.
192+
174193
## Phase 5 — Build and validate
175194

176195
1. `make BOARD=<board_name>` from the repo root. Fix errors in order. Typical failures:

.github/workflows/boards.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212
strategy:
1313
matrix:
14-
board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo]
14+
board: [stm32wb55xx_nucleo, stm32wba55cg_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo, stm32f091rc_nucleo]
1515
extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"]
1616
include:
1717
- board: stm32wb55xx_nucleo

.github/workflows/watchdog-tests.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ jobs:
1616
watchdog: iwdg
1717
- board: stm32wb55xx_nucleo
1818
watchdog: wwdg
19+
- board: stm32f091rc_nucleo
20+
watchdog: iwdg
1921
steps:
2022
- uses: actions/checkout@v4
2123

boards/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ build configuration.
1616
|-------|----------|-----|-----------|
1717
| Microchip PIC32CZ CA Curiosity Ultra | PIC32CZ | Cortex-M7 | `pic32cz_curiosity_ultra/` |
1818
| ST NUCLEO-C031C6 | STM32C0 | Cortex-M0+ | `stm32c031_nucleo/` |
19+
| ST NUCLEO-F091RC | STM32F0 | Cortex-M0 | `stm32f091rc_nucleo/` |
1920
| WeAct BlackPill STM32F411 | STM32F4 | Cortex-M4 | `stm32f411_blackpill/` |
2021
| ST NUCLEO-H563ZI | STM32H5 | Cortex-M33 | `stm32h563zi_nucleo/` |
2122
| ST NUCLEO-WB55RG | STM32WB | Cortex-M4 | `stm32wb55xx_nucleo/` |
23+
| ST NUCLEO-WBA55CG | STM32WBA | Cortex-M33 | `stm32wba55cg_nucleo/` |
2224

2325
## Board Directory Contents
2426

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))
2+
3+
PLATFORM = stm32f0
4+
TESTS ?= clock gpio timer flash uart spi
5+
6+
GCC = $(GCC_PATH)arm-none-eabi-gcc
7+
LD = $(GCC_PATH)arm-none-eabi-gcc
8+
OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy
9+
10+
CFLAGS += -Wall -Werror $(INCLUDE) -g3 \
11+
-ffreestanding -nostdlib -mcpu=cortex-m0 -mthumb \
12+
-DPLATFORM_STM32F0 -MMD -MP \
13+
-DWHAL_CFG_GPIO_API_MAPPING_STM32F0 \
14+
-DWHAL_CFG_CLOCK_API_MAPPING_STM32F0 \
15+
-DWHAL_CFG_UART_API_MAPPING_STM32F0 \
16+
-DWHAL_CFG_SPI_API_MAPPING_STM32F0 \
17+
-DWHAL_CFG_I2C_API_MAPPING_STM32F0 \
18+
$(if $(filter iwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_IWDG)
19+
LDFLAGS = -mcpu=cortex-m0 -mthumb -ffreestanding -nostartfiles \
20+
-Wl,--omagic -static
21+
22+
LINKER_SCRIPT ?= $(_BOARD_DIR)/linker.ld
23+
24+
INCLUDE += -I$(_BOARD_DIR) -I$(WHAL_DIR)/boards/peripheral
25+
26+
BOARD_SOURCE = $(_BOARD_DIR)/ivt.c
27+
BOARD_SOURCE += $(_BOARD_DIR)/board.c
28+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*.c)
29+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/timer.c)
30+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/supply.c)
31+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/flash.c)
32+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c)
33+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c)
34+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/sensor.c)
35+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/block.c)
36+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/watchdog.c)
37+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32f0_*.c)
38+
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c)
39+
40+
# Peripheral devices
41+
include $(WHAL_DIR)/boards/peripheral/Makefile.inc

boards/stm32f091rc_nucleo/board.c

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
#include <stdint.h>
2+
#include <stddef.h>
3+
#include "board.h"
4+
#include <wolfHAL/platform/st/stm32f091xx.h>
5+
#include "peripheral.h"
6+
7+
volatile uint32_t g_tick = 0;
8+
volatile uint8_t g_waiting = 0;
9+
volatile uint8_t g_tickOverflow = 0;
10+
11+
void SysTick_Handler()
12+
{
13+
uint32_t tickBefore = g_tick++;
14+
if (g_waiting) {
15+
if (tickBefore > g_tick)
16+
g_tickOverflow = 1;
17+
}
18+
}
19+
20+
uint32_t Board_GetTick(void)
21+
{
22+
return g_tick;
23+
}
24+
25+
whal_Timeout g_whalTimeout = {
26+
.timeoutTicks = 1000,
27+
.GetTick = Board_GetTick,
28+
};
29+
30+
/* Clock — PLL at 48 MHz (HSI/2 * 12) */
31+
whal_Clock g_whalClock = {
32+
.regmap = { WHAL_STM32F091_RCC_REGMAP },
33+
34+
.cfg = &(whal_Stm32f0Rcc_Cfg) {
35+
.sysClkSrc = WHAL_STM32F0_RCC_SYSCLK_SRC_PLL,
36+
.pllCfg = &(whal_Stm32f0Rcc_PllCfg) {
37+
.clkSrc = WHAL_STM32F0_RCC_PLLSRC_HSI_DIV2,
38+
.prediv = 1,
39+
.pllmul = 12,
40+
},
41+
},
42+
};
43+
44+
static const whal_Stm32f0Rcc_Clk g_clocks[] = {
45+
{WHAL_STM32F091_GPIOA_CLOCK},
46+
{WHAL_STM32F091_GPIOB_CLOCK},
47+
{WHAL_STM32F091_GPIOC_CLOCK},
48+
{WHAL_STM32F091_USART2_CLOCK},
49+
{WHAL_STM32F091_SPI1_CLOCK},
50+
{WHAL_STM32F091_I2C1_CLOCK},
51+
};
52+
#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0]))
53+
54+
/* GPIO */
55+
whal_Gpio g_whalGpio = {
56+
.regmap = { WHAL_STM32F091_GPIO_REGMAP },
57+
58+
.cfg = &(whal_Stm32f0Gpio_Cfg) {
59+
.pinCfg = (whal_Stm32f0Gpio_PinCfg[PIN_COUNT]) {
60+
/* LD2 Green LED on PA5 */
61+
[LED_PIN] = WHAL_STM32F0_GPIO_PIN(
62+
WHAL_STM32F0_GPIO_PORT_A, 5, WHAL_STM32F0_GPIO_MODE_OUT,
63+
WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_LOW,
64+
WHAL_STM32F0_GPIO_PULL_NONE, 0),
65+
/* USART2 TX on PA2, AF1 */
66+
[UART_TX_PIN] = WHAL_STM32F0_GPIO_PIN(
67+
WHAL_STM32F0_GPIO_PORT_A, 2, WHAL_STM32F0_GPIO_MODE_ALTFN,
68+
WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST,
69+
WHAL_STM32F0_GPIO_PULL_UP, 1),
70+
/* USART2 RX on PA3, AF1 */
71+
[UART_RX_PIN] = WHAL_STM32F0_GPIO_PIN(
72+
WHAL_STM32F0_GPIO_PORT_A, 3, WHAL_STM32F0_GPIO_MODE_ALTFN,
73+
WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST,
74+
WHAL_STM32F0_GPIO_PULL_UP, 1),
75+
/* SPI1 SCK on PB3, AF0 */
76+
[SPI_SCK_PIN] = WHAL_STM32F0_GPIO_PIN(
77+
WHAL_STM32F0_GPIO_PORT_B, 3, WHAL_STM32F0_GPIO_MODE_ALTFN,
78+
WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST,
79+
WHAL_STM32F0_GPIO_PULL_NONE, 0),
80+
/* SPI1 MISO on PB4, AF0 */
81+
[SPI_MISO_PIN] = WHAL_STM32F0_GPIO_PIN(
82+
WHAL_STM32F0_GPIO_PORT_B, 4, WHAL_STM32F0_GPIO_MODE_ALTFN,
83+
WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST,
84+
WHAL_STM32F0_GPIO_PULL_NONE, 0),
85+
/* SPI1 MOSI on PB5, AF0 */
86+
[SPI_MOSI_PIN] = WHAL_STM32F0_GPIO_PIN(
87+
WHAL_STM32F0_GPIO_PORT_B, 5, WHAL_STM32F0_GPIO_MODE_ALTFN,
88+
WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST,
89+
WHAL_STM32F0_GPIO_PULL_NONE, 0),
90+
/* SPI CS on PB6, output, push-pull */
91+
[SPI_CS_PIN] = WHAL_STM32F0_GPIO_PIN(
92+
WHAL_STM32F0_GPIO_PORT_B, 6, WHAL_STM32F0_GPIO_MODE_OUT,
93+
WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST,
94+
WHAL_STM32F0_GPIO_PULL_UP, 0),
95+
/* I2C1 SCL on PB8, AF1, open-drain */
96+
[I2C_SCL_PIN] = WHAL_STM32F0_GPIO_PIN(
97+
WHAL_STM32F0_GPIO_PORT_B, 8, WHAL_STM32F0_GPIO_MODE_ALTFN,
98+
WHAL_STM32F0_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32F0_GPIO_SPEED_FAST,
99+
WHAL_STM32F0_GPIO_PULL_UP, 1),
100+
/* I2C1 SDA on PB9, AF1, open-drain */
101+
[I2C_SDA_PIN] = WHAL_STM32F0_GPIO_PIN(
102+
WHAL_STM32F0_GPIO_PORT_B, 9, WHAL_STM32F0_GPIO_MODE_ALTFN,
103+
WHAL_STM32F0_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32F0_GPIO_SPEED_FAST,
104+
WHAL_STM32F0_GPIO_PULL_UP, 1),
105+
},
106+
.pinCount = PIN_COUNT,
107+
},
108+
};
109+
110+
/* Timer — SysTick at 1 ms */
111+
whal_Timer g_whalTimer = {
112+
.regmap = { WHAL_CORTEX_M0_SYSTICK_REGMAP },
113+
.driver = WHAL_CORTEX_M0_SYSTICK_DRIVER,
114+
115+
.cfg = &(whal_SysTick_Cfg) {
116+
.cyclesPerTick = 48000000 / 1000,
117+
.clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK,
118+
.tickInt = WHAL_SYSTICK_TICKINT_ENABLED,
119+
},
120+
};
121+
122+
/* UART — USART2 at 115200 baud */
123+
whal_Uart g_whalUart = {
124+
.regmap = { WHAL_STM32F091_USART2_REGMAP },
125+
126+
.cfg = &(whal_Stm32f0Uart_Cfg) {
127+
.timeout = &g_whalTimeout,
128+
.brr = WHAL_STM32F0_UART_BRR(48000000, 115200),
129+
},
130+
};
131+
132+
/* SPI */
133+
whal_Spi g_whalSpi = {
134+
.regmap = { WHAL_STM32F091_SPI1_REGMAP },
135+
136+
.cfg = &(whal_Stm32f0Spi_Cfg) {
137+
.pclk = 48000000,
138+
.timeout = &g_whalTimeout,
139+
},
140+
};
141+
142+
/* I2C — I2C1 */
143+
whal_I2c g_whalI2c = {
144+
.regmap = { WHAL_STM32F091_I2C1_REGMAP },
145+
146+
.cfg = &(whal_Stm32f0I2c_Cfg) {
147+
.pclk = 48000000,
148+
.timeout = &g_whalTimeout,
149+
},
150+
};
151+
152+
/* Flash — 256 KB */
153+
whal_Flash g_whalFlash = {
154+
.regmap = { WHAL_STM32F091_FLASH_REGMAP },
155+
.driver = WHAL_STM32F091_FLASH_DRIVER,
156+
157+
.cfg = &(whal_Stm32f0Flash_Cfg) {
158+
.startAddr = 0x08000000,
159+
.size = 0x40000,
160+
.timeout = &g_whalTimeout,
161+
},
162+
};
163+
164+
#ifdef BOARD_WATCHDOG_IWDG
165+
whal_Watchdog g_whalWatchdog = {
166+
.regmap = { WHAL_STM32F091_IWDG_REGMAP },
167+
.driver = WHAL_STM32F091_IWDG_DRIVER,
168+
169+
.cfg = &(whal_Stm32f0Iwdg_Cfg) {
170+
.prescaler = WHAL_STM32F0_IWDG_PR_64,
171+
.reload = 500,
172+
.timeout = &g_whalTimeout,
173+
},
174+
};
175+
#endif
176+
177+
void Board_WaitMs(size_t ms)
178+
{
179+
uint32_t startCount = g_tick;
180+
while ((g_tick - startCount) < ms)
181+
;
182+
}
183+
184+
whal_Error Board_Init(void)
185+
{
186+
whal_Error err;
187+
188+
/* Set flash latency before increasing clock speed */
189+
err = whal_Stm32f0Flash_Ext_SetLatency(&g_whalFlash,
190+
WHAL_STM32F0_FLASH_LATENCY_1);
191+
if (err)
192+
return err;
193+
194+
err = whal_Clock_Init(&g_whalClock);
195+
if (err)
196+
return err;
197+
198+
for (size_t i = 0; i < CLOCK_COUNT; i++) {
199+
err = whal_Clock_Enable(&g_whalClock, &g_clocks[i]);
200+
if (err)
201+
return err;
202+
}
203+
204+
err = whal_Gpio_Init(&g_whalGpio);
205+
if (err)
206+
return err;
207+
208+
err = whal_Uart_Init(&g_whalUart);
209+
if (err)
210+
return err;
211+
212+
err = whal_Spi_Init(&g_whalSpi);
213+
if (err)
214+
return err;
215+
216+
err = whal_I2c_Init(&g_whalI2c);
217+
if (err)
218+
return err;
219+
220+
err = whal_Timer_Init(&g_whalTimer);
221+
if (err)
222+
return err;
223+
224+
err = whal_Timer_Start(&g_whalTimer);
225+
if (err)
226+
return err;
227+
228+
err = Peripheral_Init();
229+
if (err)
230+
return err;
231+
232+
return WHAL_SUCCESS;
233+
}
234+
235+
whal_Error Board_Deinit(void)
236+
{
237+
whal_Error err;
238+
239+
err = Peripheral_Deinit();
240+
if (err)
241+
return err;
242+
243+
err = whal_Timer_Stop(&g_whalTimer);
244+
if (err)
245+
return err;
246+
247+
err = whal_Timer_Deinit(&g_whalTimer);
248+
if (err)
249+
return err;
250+
251+
err = whal_Spi_Deinit(&g_whalSpi);
252+
if (err)
253+
return err;
254+
255+
err = whal_I2c_Deinit(&g_whalI2c);
256+
if (err)
257+
return err;
258+
259+
err = whal_Uart_Deinit(&g_whalUart);
260+
if (err)
261+
return err;
262+
263+
err = whal_Gpio_Deinit(&g_whalGpio);
264+
if (err)
265+
return err;
266+
267+
for (size_t i = 0; i < CLOCK_COUNT; i++) {
268+
err = whal_Clock_Disable(&g_whalClock, &g_clocks[i]);
269+
if (err)
270+
return err;
271+
}
272+
273+
err = whal_Clock_Deinit(&g_whalClock);
274+
if (err)
275+
return err;
276+
277+
return WHAL_SUCCESS;
278+
}

0 commit comments

Comments
 (0)