Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .claude/skills/port-stm32-platform/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,28 @@ typedef whal_<OrigPlatform><Type>_PinCfg whal_<NewPlatform><Type>_PinCfg;

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.

**API mapping macros stay in the leaf driver, not in the alias .c.** Most leaf drivers contain a guarded block that aliases the platform-specific function names directly to the generic `whal_<Type>_*` API:

```c
/* in src/<type>/<origplatform>_<type>.c — the LEAF */
#if defined(WHAL_CFG_<TYPE>_API_MAPPING_<ORIGPLATFORM>) || \
defined(WHAL_CFG_<TYPE>_API_MAPPING_<NEWPLATFORM>)
#define whal_<OrigPlatform><Type>_Init whal_<Type>_Init
/* ...one #define per driver entry point... */
#endif

/* ...driver implementation... */

#if !defined(WHAL_CFG_<TYPE>_API_MAPPING_<ORIGPLATFORM>) && \
!defined(WHAL_CFG_<TYPE>_API_MAPPING_<NEWPLATFORM>)
const whal_<Type>Driver whal_<OrigPlatform><Type>_Driver = { ... };
#endif
```

Add the new platform's `WHAL_CFG_<TYPE>_API_MAPPING_<NEWPLATFORM>` macro to **both** guards in the leaf driver. Do **not** translate the macro inside the alias `.c` stub like `#ifdef <NEW> #define <ORIG> #endif` — every leaf has to learn about every alias platform anyway, and putting the recognition in two places (alias shim + leaf driver) creates drift. Keep the alias `.c` as a single `#include` line.

**Alias the leaf directly — never daisy-chain.** If `<origplatform>` itself aliases another driver, alias `<newplatform>` to the **leaf** (the one with the actual implementation), not to the intermediate alias. Two-hop chains (`<new>` → `<intermediate>` → `<leaf>`) make every macro recognition twice as painful and obscure the dependency graph. Trace the include chain in the existing `.h` and `.c` files until you find the file with real driver code, and point your new alias at that.

**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`:

```c
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/boards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
board: [stm32wb55xx_nucleo, stm32wba55cg_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo, stm32f091rc_nucleo]
board: [stm32wb55xx_nucleo, stm32wba55cg_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo, stm32f091rc_nucleo, stm32f302r8_nucleo]
extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"]
include:
- board: stm32wb55xx_nucleo
Expand Down
1 change: 1 addition & 0 deletions boards/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ build configuration.
| Microchip PIC32CZ CA Curiosity Ultra | PIC32CZ | Cortex-M7 | `pic32cz_curiosity_ultra/` |
| ST NUCLEO-C031C6 | STM32C0 | Cortex-M0+ | `stm32c031_nucleo/` |
| ST NUCLEO-F091RC | STM32F0 | Cortex-M0 | `stm32f091rc_nucleo/` |
| ST NUCLEO-F302R8 | STM32F3 | Cortex-M4 | `stm32f302r8_nucleo/` |
| WeAct BlackPill STM32F411 | STM32F4 | Cortex-M4 | `stm32f411_blackpill/` |
| ST NUCLEO-H563ZI | STM32H5 | Cortex-M33 | `stm32h563zi_nucleo/` |
| ST NUCLEO-WB55RG | STM32WB | Cortex-M4 | `stm32wb55xx_nucleo/` |
Expand Down
43 changes: 43 additions & 0 deletions boards/stm32f302r8_nucleo/Makefile.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

PLATFORM = stm32f3
TESTS ?= clock gpio timer flash uart spi

GCC = $(GCC_PATH)arm-none-eabi-gcc
LD = $(GCC_PATH)arm-none-eabi-gcc
OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy

CFLAGS += -Wall -Werror $(INCLUDE) -g3 \
-ffreestanding -nostdlib \
-mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-DPLATFORM_STM32F3 -MMD -MP \
-DWHAL_CFG_GPIO_API_MAPPING_STM32F3 \
-DWHAL_CFG_CLOCK_API_MAPPING_STM32F3 \
-DWHAL_CFG_UART_API_MAPPING_STM32F3 \
-DWHAL_CFG_SPI_API_MAPPING_STM32F3 \
-DWHAL_CFG_I2C_API_MAPPING_STM32F3 \
$(if $(filter iwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_IWDG) \
$(if $(filter wwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_WWDG)
LDFLAGS = -mcpu=cortex-m4 -mthumb -mfloat-abi=hard -mfpu=fpv4-sp-d16 \
-ffreestanding -nostartfiles -Wl,--omagic -static

LINKER_SCRIPT ?= $(_BOARD_DIR)/linker.ld

INCLUDE += -I$(_BOARD_DIR) -I$(WHAL_DIR)/boards/peripheral

BOARD_SOURCE = $(_BOARD_DIR)/ivt.c
BOARD_SOURCE += $(_BOARD_DIR)/board.c
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/timer.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/supply.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/flash.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/sensor.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/block.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/watchdog.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32f3_*.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c)

# Peripheral devices
include $(WHAL_DIR)/boards/peripheral/Makefile.inc
294 changes: 294 additions & 0 deletions boards/stm32f302r8_nucleo/board.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
#include <stdint.h>
#include <stddef.h>
#include "board.h"
#include <wolfHAL/platform/st/stm32f302r8.h>
#include "peripheral.h"

volatile uint32_t g_tick = 0;
volatile uint8_t g_waiting = 0;
volatile uint8_t g_tickOverflow = 0;

void SysTick_Handler()
{
uint32_t tickBefore = g_tick++;
if (g_waiting) {
if (tickBefore > g_tick)
g_tickOverflow = 1;
}
}

uint32_t Board_GetTick(void)
{
return g_tick;
}

whal_Timeout g_whalTimeout = {
.timeoutTicks = 1000,
.GetTick = Board_GetTick,
};

/* Clock — PLL at 48 MHz (HSI/2 * 12) */
whal_Clock g_whalClock = {
.regmap = { WHAL_STM32F302_RCC_REGMAP },

.cfg = &(whal_Stm32f3Rcc_Cfg) {
.sysClkSrc = WHAL_STM32F3_RCC_SYSCLK_SRC_PLL,
.pllCfg = &(whal_Stm32f3Rcc_PllCfg) {
.clkSrc = WHAL_STM32F3_RCC_PLLSRC_HSI_DIV2,
.prediv = 1,
.pllmul = 12,
},
},
};

static const whal_Stm32f3Rcc_Clk g_clocks[] = {
{WHAL_STM32F302_GPIOA_CLOCK},
{WHAL_STM32F302_GPIOB_CLOCK},
{WHAL_STM32F302_GPIOC_CLOCK},
{WHAL_STM32F302_USART2_CLOCK},
{WHAL_STM32F302_SPI3_CLOCK},
{WHAL_STM32F302_I2C1_CLOCK},
#ifdef BOARD_WATCHDOG_WWDG
{WHAL_STM32F302_WWDG_CLOCK},
#endif
};
#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0]))

/* GPIO */
whal_Gpio g_whalGpio = {
.regmap = { WHAL_STM32F302_GPIO_REGMAP },

.cfg = &(whal_Stm32f3Gpio_Cfg) {
.pinCfg = (whal_Stm32f3Gpio_PinCfg[PIN_COUNT]) {
/* LD2 Green LED on PB13 (per UM1724 Figure 14, NUCLEO-F302R8) */
[LED_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_B, 13, WHAL_STM32F3_GPIO_MODE_OUT,
Comment thread
AlexLanzano marked this conversation as resolved.
WHAL_STM32F3_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F3_GPIO_SPEED_LOW,
WHAL_STM32F3_GPIO_PULL_NONE, 0),
/* USART2 TX on PA2, AF7 */
[UART_TX_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_A, 2, WHAL_STM32F3_GPIO_MODE_ALTFN,
WHAL_STM32F3_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_UP, 7),
/* USART2 RX on PA3, AF7 */
[UART_RX_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_A, 3, WHAL_STM32F3_GPIO_MODE_ALTFN,
WHAL_STM32F3_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_UP, 7),
/* SPI3 SCK on PB3, AF6 */
[SPI_SCK_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_B, 3, WHAL_STM32F3_GPIO_MODE_ALTFN,
WHAL_STM32F3_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_NONE, 6),
/* SPI3 MISO on PB4, AF6 */
[SPI_MISO_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_B, 4, WHAL_STM32F3_GPIO_MODE_ALTFN,
WHAL_STM32F3_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_NONE, 6),
/* SPI3 MOSI on PB5, AF6 */
[SPI_MOSI_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_B, 5, WHAL_STM32F3_GPIO_MODE_ALTFN,
WHAL_STM32F3_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_NONE, 6),
/* SPI CS on PB12, output, push-pull */
[SPI_CS_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_B, 12, WHAL_STM32F3_GPIO_MODE_OUT,
WHAL_STM32F3_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_UP, 0),
/* I2C1 SCL on PB8, AF4, open-drain */
[I2C_SCL_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_B, 8, WHAL_STM32F3_GPIO_MODE_ALTFN,
WHAL_STM32F3_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_UP, 4),
/* I2C1 SDA on PB9, AF4, open-drain */
[I2C_SDA_PIN] = WHAL_STM32F3_GPIO_PIN(
WHAL_STM32F3_GPIO_PORT_B, 9, WHAL_STM32F3_GPIO_MODE_ALTFN,
WHAL_STM32F3_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32F3_GPIO_SPEED_FAST,
WHAL_STM32F3_GPIO_PULL_UP, 4),
},
.pinCount = PIN_COUNT,
},
};

/* Timer — SysTick at 1 ms */
whal_Timer g_whalTimer = {
.regmap = { WHAL_CORTEX_M4_SYSTICK_REGMAP },
.driver = WHAL_CORTEX_M4_SYSTICK_DRIVER,

.cfg = &(whal_SysTick_Cfg) {
.cyclesPerTick = 48000000 / 1000,
.clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK,
.tickInt = WHAL_SYSTICK_TICKINT_ENABLED,
},
};

/* UART — USART2 at 115200 baud */
whal_Uart g_whalUart = {
.regmap = { WHAL_STM32F302_USART2_REGMAP },

.cfg = &(whal_Stm32f3Uart_Cfg) {
.timeout = &g_whalTimeout,
.brr = WHAL_STM32F3_UART_BRR(48000000, 115200),
},
};

/* SPI — SPI3 */
whal_Spi g_whalSpi = {
.regmap = { WHAL_STM32F302_SPI3_REGMAP },

.cfg = &(whal_Stm32f3Spi_Cfg) {
.pclk = 48000000,
.timeout = &g_whalTimeout,
},
};

/* I2C — I2C1 (HSI at 8 MHz per RCC_CFGR3.I2C1SW reset default) */
whal_I2c g_whalI2c = {
.regmap = { WHAL_STM32F302_I2C1_REGMAP },

.cfg = &(whal_Stm32f3I2c_Cfg) {
.pclk = 8000000,
.timeout = &g_whalTimeout,
},
};

/* Flash — 64 KB */
whal_Flash g_whalFlash = {
.regmap = { WHAL_STM32F302_FLASH_REGMAP },
.driver = WHAL_STM32F302_FLASH_DRIVER,

.cfg = &(whal_Stm32f3Flash_Cfg) {
.startAddr = 0x08000000,
.size = 0x10000,
.timeout = &g_whalTimeout,
},
};

#ifdef BOARD_WATCHDOG_IWDG
whal_Watchdog g_whalWatchdog = {
.regmap = { WHAL_STM32F302_IWDG_REGMAP },
.driver = WHAL_STM32F302_IWDG_DRIVER,

.cfg = &(whal_Stm32f3Iwdg_Cfg) {
.prescaler = WHAL_STM32F3_IWDG_PR_64,
.reload = 500,
.timeout = &g_whalTimeout,
},
};
#elif defined(BOARD_WATCHDOG_WWDG)
whal_Watchdog g_whalWatchdog = {
.regmap = { WHAL_STM32F302_WWDG_REGMAP },
.driver = WHAL_STM32F302_WWDG_DRIVER,

.cfg = &(whal_Stm32f3Wwdg_Cfg) {
.prescaler = 3,
.window = 0x7F,
.counter = 0x7F,
},
};
#endif

void Board_WaitMs(size_t ms)
{
uint32_t startCount = g_tick;
while ((g_tick - startCount) < ms)
;
}

whal_Error Board_Init(void)
{
whal_Error err;

/* Set flash latency before increasing clock speed.
* STM32F3: 0 WS for HCLK <= 24 MHz, 1 WS for 24 < HCLK <= 48 MHz,
* 2 WS for 48 < HCLK <= 72 MHz. */
err = whal_Stm32f3Flash_Ext_SetLatency(&g_whalFlash,
WHAL_STM32F3_FLASH_LATENCY_1);
if (err)
return err;

err = whal_Clock_Init(&g_whalClock);
if (err)
return err;

for (size_t i = 0; i < CLOCK_COUNT; i++) {
err = whal_Clock_Enable(&g_whalClock, &g_clocks[i]);
if (err)
return err;
}

err = whal_Gpio_Init(&g_whalGpio);
if (err)
return err;

err = whal_Uart_Init(&g_whalUart);
if (err)
return err;

err = whal_Spi_Init(&g_whalSpi);
if (err)
return err;

err = whal_I2c_Init(&g_whalI2c);
if (err)
return err;

err = whal_Timer_Init(&g_whalTimer);
if (err)
return err;

err = whal_Timer_Start(&g_whalTimer);
if (err)
return err;

err = Peripheral_Init();
if (err)
return err;

return WHAL_SUCCESS;
}

whal_Error Board_Deinit(void)
{
whal_Error err;

err = Peripheral_Deinit();
if (err)
return err;

err = whal_Timer_Stop(&g_whalTimer);
if (err)
return err;

err = whal_Timer_Deinit(&g_whalTimer);
if (err)
return err;

err = whal_Spi_Deinit(&g_whalSpi);
if (err)
return err;

err = whal_I2c_Deinit(&g_whalI2c);
if (err)
return err;

err = whal_Uart_Deinit(&g_whalUart);
if (err)
return err;

err = whal_Gpio_Deinit(&g_whalGpio);
if (err)
return err;

for (size_t i = 0; i < CLOCK_COUNT; i++) {
err = whal_Clock_Disable(&g_whalClock, &g_clocks[i]);
if (err)
return err;
}

err = whal_Clock_Deinit(&g_whalClock);
if (err)
return err;

return WHAL_SUCCESS;
}
Loading
Loading