diff --git a/.claude/skills/port-stm32-platform/SKILL.md b/.claude/skills/port-stm32-platform/SKILL.md index dc51474..6d529c3 100644 --- a/.claude/skills/port-stm32-platform/SKILL.md +++ b/.claude/skills/port-stm32-platform/SKILL.md @@ -140,6 +140,14 @@ typedef whal__PinCfg whal__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/*/_*.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. +**Test alias** — when a driver is reused via alias AND the original driver already has a platform-specific test file (`tests//test__.c`), create a matching test alias at `tests//test__.c`: + +```c +#include "test__.c" +``` + +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__PLATFORM`, which gates the `whal_Test__Platform()` call in `tests/main.c`. Examples in-tree: `tests/gpio/test_stm32c0_gpio.c`, `tests/gpio/test_stm32f0_gpio.c`. + ### Common driver pitfalls (from prior ports) - **Flash**: check if already unlocked before writing keys — double-unlock hard-faults. Bit positions (LOCK, STRT, PNB) differ between families; do not copy-paste. - **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_` instances and declares `Board_Init`/`Board_Deinit`/ ### `board.c` Define each `whal_` 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`. +### GPIO pin conflict check +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. + ### `Makefile.inc` Model on `boards/stm32wba55cg_nucleo/Makefile.inc`: - `PLATFORM = ` — matches the prefix used in `src/*/_*.c` @@ -171,6 +182,14 @@ Copy from a similar board and update the `MEMORY` block's FLASH/RAM origins and ### `ivt.c` 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.). +### boards/README.md + +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. + +### GitHub CI + +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`. + ## Phase 5 — Build and validate 1. `make BOARD=` from the repo root. Fix errors in order. Typical failures: diff --git a/.github/workflows/boards.yml b/.github/workflows/boards.yml index 71d3980..a531cfa 100644 --- a/.github/workflows/boards.yml +++ b/.github/workflows/boards.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo] + board: [stm32wb55xx_nucleo, stm32wba55cg_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo, stm32f091rc_nucleo] extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"] include: - board: stm32wb55xx_nucleo diff --git a/.github/workflows/watchdog-tests.yml b/.github/workflows/watchdog-tests.yml index f3668dd..be1a417 100644 --- a/.github/workflows/watchdog-tests.yml +++ b/.github/workflows/watchdog-tests.yml @@ -16,6 +16,8 @@ jobs: watchdog: iwdg - board: stm32wb55xx_nucleo watchdog: wwdg + - board: stm32f091rc_nucleo + watchdog: iwdg steps: - uses: actions/checkout@v4 diff --git a/boards/README.md b/boards/README.md index 14718b5..0d6bd6c 100644 --- a/boards/README.md +++ b/boards/README.md @@ -16,9 +16,11 @@ 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/` | | WeAct BlackPill STM32F411 | STM32F4 | Cortex-M4 | `stm32f411_blackpill/` | | ST NUCLEO-H563ZI | STM32H5 | Cortex-M33 | `stm32h563zi_nucleo/` | | ST NUCLEO-WB55RG | STM32WB | Cortex-M4 | `stm32wb55xx_nucleo/` | +| ST NUCLEO-WBA55CG | STM32WBA | Cortex-M33 | `stm32wba55cg_nucleo/` | ## Board Directory Contents diff --git a/boards/stm32f091rc_nucleo/Makefile.inc b/boards/stm32f091rc_nucleo/Makefile.inc new file mode 100644 index 0000000..964a520 --- /dev/null +++ b/boards/stm32f091rc_nucleo/Makefile.inc @@ -0,0 +1,41 @@ +_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +PLATFORM = stm32f0 +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-m0 -mthumb \ + -DPLATFORM_STM32F0 -MMD -MP \ + -DWHAL_CFG_GPIO_API_MAPPING_STM32F0 \ + -DWHAL_CFG_CLOCK_API_MAPPING_STM32F0 \ + -DWHAL_CFG_UART_API_MAPPING_STM32F0 \ + -DWHAL_CFG_SPI_API_MAPPING_STM32F0 \ + -DWHAL_CFG_I2C_API_MAPPING_STM32F0 \ + $(if $(filter iwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_IWDG) +LDFLAGS = -mcpu=cortex-m0 -mthumb -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/*/stm32f0_*.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c) + +# Peripheral devices +include $(WHAL_DIR)/boards/peripheral/Makefile.inc diff --git a/boards/stm32f091rc_nucleo/board.c b/boards/stm32f091rc_nucleo/board.c new file mode 100644 index 0000000..806f9a8 --- /dev/null +++ b/boards/stm32f091rc_nucleo/board.c @@ -0,0 +1,278 @@ +#include +#include +#include "board.h" +#include +#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_STM32F091_RCC_REGMAP }, + + .cfg = &(whal_Stm32f0Rcc_Cfg) { + .sysClkSrc = WHAL_STM32F0_RCC_SYSCLK_SRC_PLL, + .pllCfg = &(whal_Stm32f0Rcc_PllCfg) { + .clkSrc = WHAL_STM32F0_RCC_PLLSRC_HSI_DIV2, + .prediv = 1, + .pllmul = 12, + }, + }, +}; + +static const whal_Stm32f0Rcc_Clk g_clocks[] = { + {WHAL_STM32F091_GPIOA_CLOCK}, + {WHAL_STM32F091_GPIOB_CLOCK}, + {WHAL_STM32F091_GPIOC_CLOCK}, + {WHAL_STM32F091_USART2_CLOCK}, + {WHAL_STM32F091_SPI1_CLOCK}, + {WHAL_STM32F091_I2C1_CLOCK}, +}; +#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0])) + +/* GPIO */ +whal_Gpio g_whalGpio = { + .regmap = { WHAL_STM32F091_GPIO_REGMAP }, + + .cfg = &(whal_Stm32f0Gpio_Cfg) { + .pinCfg = (whal_Stm32f0Gpio_PinCfg[PIN_COUNT]) { + /* LD2 Green LED on PA5 */ + [LED_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_A, 5, WHAL_STM32F0_GPIO_MODE_OUT, + WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_LOW, + WHAL_STM32F0_GPIO_PULL_NONE, 0), + /* USART2 TX on PA2, AF1 */ + [UART_TX_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_A, 2, WHAL_STM32F0_GPIO_MODE_ALTFN, + WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_UP, 1), + /* USART2 RX on PA3, AF1 */ + [UART_RX_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_A, 3, WHAL_STM32F0_GPIO_MODE_ALTFN, + WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_UP, 1), + /* SPI1 SCK on PB3, AF0 */ + [SPI_SCK_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_B, 3, WHAL_STM32F0_GPIO_MODE_ALTFN, + WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_NONE, 0), + /* SPI1 MISO on PB4, AF0 */ + [SPI_MISO_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_B, 4, WHAL_STM32F0_GPIO_MODE_ALTFN, + WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_NONE, 0), + /* SPI1 MOSI on PB5, AF0 */ + [SPI_MOSI_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_B, 5, WHAL_STM32F0_GPIO_MODE_ALTFN, + WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_NONE, 0), + /* SPI CS on PB6, output, push-pull */ + [SPI_CS_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_B, 6, WHAL_STM32F0_GPIO_MODE_OUT, + WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_UP, 0), + /* I2C1 SCL on PB8, AF1, open-drain */ + [I2C_SCL_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_B, 8, WHAL_STM32F0_GPIO_MODE_ALTFN, + WHAL_STM32F0_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_UP, 1), + /* I2C1 SDA on PB9, AF1, open-drain */ + [I2C_SDA_PIN] = WHAL_STM32F0_GPIO_PIN( + WHAL_STM32F0_GPIO_PORT_B, 9, WHAL_STM32F0_GPIO_MODE_ALTFN, + WHAL_STM32F0_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32F0_GPIO_SPEED_FAST, + WHAL_STM32F0_GPIO_PULL_UP, 1), + }, + .pinCount = PIN_COUNT, + }, +}; + +/* Timer — SysTick at 1 ms */ +whal_Timer g_whalTimer = { + .regmap = { WHAL_CORTEX_M0_SYSTICK_REGMAP }, + .driver = WHAL_CORTEX_M0_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_STM32F091_USART2_REGMAP }, + + .cfg = &(whal_Stm32f0Uart_Cfg) { + .timeout = &g_whalTimeout, + .brr = WHAL_STM32F0_UART_BRR(48000000, 115200), + }, +}; + +/* SPI */ +whal_Spi g_whalSpi = { + .regmap = { WHAL_STM32F091_SPI1_REGMAP }, + + .cfg = &(whal_Stm32f0Spi_Cfg) { + .pclk = 48000000, + .timeout = &g_whalTimeout, + }, +}; + +/* I2C — I2C1 */ +whal_I2c g_whalI2c = { + .regmap = { WHAL_STM32F091_I2C1_REGMAP }, + + .cfg = &(whal_Stm32f0I2c_Cfg) { + .pclk = 48000000, + .timeout = &g_whalTimeout, + }, +}; + +/* Flash — 256 KB */ +whal_Flash g_whalFlash = { + .regmap = { WHAL_STM32F091_FLASH_REGMAP }, + .driver = WHAL_STM32F091_FLASH_DRIVER, + + .cfg = &(whal_Stm32f0Flash_Cfg) { + .startAddr = 0x08000000, + .size = 0x40000, + .timeout = &g_whalTimeout, + }, +}; + +#ifdef BOARD_WATCHDOG_IWDG +whal_Watchdog g_whalWatchdog = { + .regmap = { WHAL_STM32F091_IWDG_REGMAP }, + .driver = WHAL_STM32F091_IWDG_DRIVER, + + .cfg = &(whal_Stm32f0Iwdg_Cfg) { + .prescaler = WHAL_STM32F0_IWDG_PR_64, + .reload = 500, + .timeout = &g_whalTimeout, + }, +}; +#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 */ + err = whal_Stm32f0Flash_Ext_SetLatency(&g_whalFlash, + WHAL_STM32F0_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; +} diff --git a/boards/stm32f091rc_nucleo/board.h b/boards/stm32f091rc_nucleo/board.h new file mode 100644 index 0000000..f35c752 --- /dev/null +++ b/boards/stm32f091rc_nucleo/board.h @@ -0,0 +1,46 @@ +#ifndef BOARD_H +#define BOARD_H + +#include +#include +#include + +extern whal_Clock g_whalClock; +extern whal_Gpio g_whalGpio; +extern whal_Timer g_whalTimer; +extern whal_Uart g_whalUart; +extern whal_Spi g_whalSpi; +extern whal_I2c g_whalI2c; +extern whal_Flash g_whalFlash; +extern whal_Watchdog g_whalWatchdog; + +extern whal_Timeout g_whalTimeout; +extern volatile uint32_t g_tick; + +enum { + LED_PIN, + UART_TX_PIN, + UART_RX_PIN, + SPI_SCK_PIN, + SPI_MISO_PIN, + SPI_MOSI_PIN, + SPI_CS_PIN, + I2C_SCL_PIN, + I2C_SDA_PIN, + PIN_COUNT, +}; + +#define BOARD_LED_PIN 0 +#define BOARD_LED_PORT_OFFSET 0x000 /* GPIOA */ +#define BOARD_LED_PIN_NUM 5 + +#define BOARD_FLASH_START_ADDR 0x08000000 +#define BOARD_FLASH_SIZE 0x40000 +#define BOARD_FLASH_TEST_ADDR 0x0803F800 +#define BOARD_FLASH_SECTOR_SZ 0x800 + +whal_Error Board_Init(void); +whal_Error Board_Deinit(void); +void Board_WaitMs(size_t ms); + +#endif /* BOARD_H */ diff --git a/boards/stm32f091rc_nucleo/ivt.c b/boards/stm32f091rc_nucleo/ivt.c new file mode 100644 index 0000000..17af1be --- /dev/null +++ b/boards/stm32f091rc_nucleo/ivt.c @@ -0,0 +1,153 @@ +#include +#include + +extern uint32_t _estack[]; +extern uint32_t _sidata[]; +extern uint32_t _sdata[]; +extern uint32_t _edata[]; +extern uint32_t _sbss[]; +extern uint32_t _ebss[]; + +extern void main(); + +void __attribute__((naked,noreturn)) Default_Handler() +{ + while(1); +} + +void Reset_Handler() __attribute__((weak)); +void NMI_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void HardFault_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SVC_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void PendSV_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SysTick_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); + +/* STM32F091 peripheral interrupts */ +void WWDG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void PVD_VDDIO2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RTC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FLASH_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RCC_CRS_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI0_1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI2_3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI4_15_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TSC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_CH1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_CH2_3_DMA2_CH1_2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_CH4_5_6_7_DMA2_CH3_4_5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ADC_COMP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_BRK_UP_TRG_COM_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_CC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM6_DAC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM14_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM15_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM16_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM17_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SPI1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SPI2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART3_4_5_6_7_8_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void CEC_CAN_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USB_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); + +#define RESERVED Default_Handler + +void *memcpy(void *dest, const void *src, size_t n) +{ + unsigned char *d = dest; + const unsigned char *s = src; + + for (size_t i = 0; i < n; i++) + d[i] = s[i]; + + return dest; +} + +void *memset(void *s, int c, size_t n) +{ + unsigned char *p = s; + unsigned char v = (unsigned char)c; + + for (size_t i = 0; i < n; i++) + p[i] = v; + + return s; +} + +void (* const interrupt_vector_table[])() __attribute__((section(".isr_vector"))) = { + (void (*)())_estack, + Reset_Handler, + NMI_Handler, + HardFault_Handler, + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + SVC_Handler, + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + PendSV_Handler, + SysTick_Handler, + /* STM32F091 peripheral interrupts */ + WWDG_IRQHandler, /* 0 */ + PVD_VDDIO2_IRQHandler, /* 1 */ + RTC_IRQHandler, /* 2 */ + FLASH_IRQHandler, /* 3 */ + RCC_CRS_IRQHandler, /* 4 */ + EXTI0_1_IRQHandler, /* 5 */ + EXTI2_3_IRQHandler, /* 6 */ + EXTI4_15_IRQHandler, /* 7 */ + TSC_IRQHandler, /* 8 */ + DMA1_CH1_IRQHandler, /* 9 */ + DMA1_CH2_3_DMA2_CH1_2_IRQHandler, /* 10 */ + DMA1_CH4_5_6_7_DMA2_CH3_4_5_IRQHandler, /* 11 */ + ADC_COMP_IRQHandler, /* 12 */ + TIM1_BRK_UP_TRG_COM_IRQHandler, /* 13 */ + TIM1_CC_IRQHandler, /* 14 */ + TIM2_IRQHandler, /* 15 */ + TIM3_IRQHandler, /* 16 */ + TIM6_DAC_IRQHandler, /* 17 */ + TIM7_IRQHandler, /* 18 */ + TIM14_IRQHandler, /* 19 */ + TIM15_IRQHandler, /* 20 */ + TIM16_IRQHandler, /* 21 */ + TIM17_IRQHandler, /* 22 */ + I2C1_IRQHandler, /* 23 */ + I2C2_IRQHandler, /* 24 */ + SPI1_IRQHandler, /* 25 */ + SPI2_IRQHandler, /* 26 */ + USART1_IRQHandler, /* 27 */ + USART2_IRQHandler, /* 28 */ + USART3_4_5_6_7_8_IRQHandler, /* 29 */ + CEC_CAN_IRQHandler, /* 30 */ + USB_IRQHandler, /* 31 */ +}; + +void __attribute__((naked)) Reset_Handler() +{ + __asm__("ldr r0, =_estack\n\t" + "mov sp, r0"); + + /* Copy data section from flash to RAM */ + uint32_t data_section_size = _edata - _sdata; + memcpy(_sdata, _sidata, data_section_size * 4); + + /* Zero out bss */ + uint32_t bss_section_size = _ebss - _sbss; + memset(_sbss, 0, bss_section_size * 4); + + /* Set Interrupt Vector Table Offset */ + uint32_t *vtor = (uint32_t *)0xE000ED08; + *vtor = (uint32_t)interrupt_vector_table; + + main(); +} diff --git a/boards/stm32f091rc_nucleo/linker.ld b/boards/stm32f091rc_nucleo/linker.ld new file mode 100644 index 0000000..f1e2a3a --- /dev/null +++ b/boards/stm32f091rc_nucleo/linker.ld @@ -0,0 +1,121 @@ +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20008000; /* end of 32 KB RAM */ +/* Generate a link error if the stack don't fit into RAM */ +_Min_Stack_Size = 0x500; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256K +RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(8); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Stack_Size; + . = ALIGN(8); + } >RAM +} diff --git a/src/clock/stm32f0_rcc.c b/src/clock/stm32f0_rcc.c new file mode 100644 index 0000000..c396244 --- /dev/null +++ b/src/clock/stm32f0_rcc.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include +#include + +#define RCC_CR_REG 0x00 +#define RCC_CR_HSION_Pos 0 +#define RCC_CR_HSION_Msk (1UL << RCC_CR_HSION_Pos) +#define RCC_CR_HSIRDY_Pos 1 +#define RCC_CR_HSIRDY_Msk (1UL << RCC_CR_HSIRDY_Pos) +#define RCC_CR_HSEON_Pos 16 +#define RCC_CR_HSEON_Msk (1UL << RCC_CR_HSEON_Pos) +#define RCC_CR_HSERDY_Pos 17 +#define RCC_CR_HSERDY_Msk (1UL << RCC_CR_HSERDY_Pos) +#define RCC_CR_PLLON_Pos 24 +#define RCC_CR_PLLON_Msk (1UL << RCC_CR_PLLON_Pos) +#define RCC_CR_PLLRDY_Pos 25 +#define RCC_CR_PLLRDY_Msk (1UL << RCC_CR_PLLRDY_Pos) + +#define RCC_CFGR_REG 0x04 +#define RCC_CFGR_SW_Pos 0 +#define RCC_CFGR_SW_Msk (WHAL_BITMASK(2) << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SWS_Pos 2 +#define RCC_CFGR_SWS_Msk (WHAL_BITMASK(2) << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_PLLSRC_Pos 16 +#define RCC_CFGR_PLLSRC_Msk (1UL << RCC_CFGR_PLLSRC_Pos) +#define RCC_CFGR_PLLMUL_Pos 18 +#define RCC_CFGR_PLLMUL_Msk (WHAL_BITMASK(4) << RCC_CFGR_PLLMUL_Pos) + +#define RCC_CFGR_SW_HSI 0 +#define RCC_CFGR_SW_HSE 1 +#define RCC_CFGR_SW_PLL 2 +#define RCC_CFGR_SW_HSI48 3 + +#define RCC_CFGR2_REG 0x2C +#define RCC_CFGR2_PREDIV_Pos 0 +#define RCC_CFGR2_PREDIV_Msk (WHAL_BITMASK(4) << RCC_CFGR2_PREDIV_Pos) + +#define RCC_CR2_REG 0x34 +#define RCC_CR2_HSI48ON_Pos 16 +#define RCC_CR2_HSI48ON_Msk (1UL << RCC_CR2_HSI48ON_Pos) +#define RCC_CR2_HSI48RDY_Pos 17 +#define RCC_CR2_HSI48RDY_Msk (1UL << RCC_CR2_HSI48RDY_Pos) + +#ifdef WHAL_CFG_CLOCK_API_MAPPING_STM32F0 +#define whal_Stm32f0Rcc_Init whal_Clock_Init +#define whal_Stm32f0Rcc_Deinit whal_Clock_Deinit +#define whal_Stm32f0Rcc_Enable whal_Clock_Enable +#define whal_Stm32f0Rcc_Disable whal_Clock_Disable +#endif /* WHAL_CFG_CLOCK_API_MAPPING_STM32F0 */ + +static whal_Error Stm32f0Rcc_EnablePllSource(size_t base, + whal_Stm32f0Rcc_PllCfg *pll) +{ + size_t rdy; + + switch (pll->clkSrc) { + case WHAL_STM32F0_RCC_PLLSRC_HSI_DIV2: + case WHAL_STM32F0_RCC_PLLSRC_HSI_PREDIV: + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSION_Msk, + whal_SetBits(RCC_CR_HSION_Msk, RCC_CR_HSION_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSIRDY_Msk, RCC_CR_HSIRDY_Pos, &rdy); + } while (!rdy); + break; + + case WHAL_STM32F0_RCC_PLLSRC_HSE_PREDIV: + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSEON_Msk, + whal_SetBits(RCC_CR_HSEON_Msk, RCC_CR_HSEON_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSERDY_Msk, RCC_CR_HSERDY_Pos, &rdy); + } while (!rdy); + break; + + case WHAL_STM32F0_RCC_PLLSRC_HSI48_PREDIV: + whal_Reg_Update(base, RCC_CR2_REG, RCC_CR2_HSI48ON_Msk, + whal_SetBits(RCC_CR2_HSI48ON_Msk, RCC_CR2_HSI48ON_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR2_REG, + RCC_CR2_HSI48RDY_Msk, RCC_CR2_HSI48RDY_Pos, &rdy); + } while (!rdy); + break; + } + + return WHAL_SUCCESS; +} + +static void Stm32f0Rcc_ConfigurePll(size_t base, whal_Stm32f0Rcc_PllCfg *pll) +{ + uint32_t pllsrc; + + /* Disable PLL before reconfiguring */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 0)); + + /* Set PREDIV */ + whal_Reg_Update(base, RCC_CFGR2_REG, RCC_CFGR2_PREDIV_Msk, + whal_SetBits(RCC_CFGR2_PREDIV_Msk, RCC_CFGR2_PREDIV_Pos, + pll->prediv - 1)); + + /* Set PLLMUL */ + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_PLLMUL_Msk, + whal_SetBits(RCC_CFGR_PLLMUL_Msk, RCC_CFGR_PLLMUL_Pos, + pll->pllmul - 2)); + + /* Set PLL source: 0 = HSI/2 or HSI/PREDIV, 1 = HSE/PREDIV or HSI48/PREDIV */ + pllsrc = (pll->clkSrc == WHAL_STM32F0_RCC_PLLSRC_HSE_PREDIV || + pll->clkSrc == WHAL_STM32F0_RCC_PLLSRC_HSI48_PREDIV) ? 1 : 0; + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_PLLSRC_Msk, + whal_SetBits(RCC_CFGR_PLLSRC_Msk, RCC_CFGR_PLLSRC_Pos, + pllsrc)); + + /* Enable PLL and wait for lock */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 1)); + + size_t rdy; + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_PLLRDY_Msk, RCC_CR_PLLRDY_Pos, &rdy); + } while (!rdy); +} + +whal_Error whal_Stm32f0Rcc_Init(whal_Clock *clkDev) +{ + whal_Stm32f0Rcc_Cfg *cfg; + size_t base; + uint32_t sw; + size_t sws; + + if (!clkDev || !clkDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32f0Rcc_Cfg *)clkDev->cfg; + base = clkDev->regmap.base; + + switch (cfg->sysClkSrc) { + case WHAL_STM32F0_RCC_SYSCLK_SRC_HSI: { + size_t rdy; + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSION_Msk, + whal_SetBits(RCC_CR_HSION_Msk, RCC_CR_HSION_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSIRDY_Msk, RCC_CR_HSIRDY_Pos, &rdy); + } while (!rdy); + sw = RCC_CFGR_SW_HSI; + break; + } + + case WHAL_STM32F0_RCC_SYSCLK_SRC_HSE: { + size_t rdy; + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSEON_Msk, + whal_SetBits(RCC_CR_HSEON_Msk, RCC_CR_HSEON_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSERDY_Msk, RCC_CR_HSERDY_Pos, &rdy); + } while (!rdy); + sw = RCC_CFGR_SW_HSE; + break; + } + + case WHAL_STM32F0_RCC_SYSCLK_SRC_PLL: + if (!cfg->pllCfg || + cfg->pllCfg->prediv < 1 || cfg->pllCfg->prediv > 16 || + cfg->pllCfg->pllmul < 2 || cfg->pllCfg->pllmul > 16) + return WHAL_EINVAL; + + Stm32f0Rcc_EnablePllSource(base, cfg->pllCfg); + Stm32f0Rcc_ConfigurePll(base, cfg->pllCfg); + sw = RCC_CFGR_SW_PLL; + break; + + case WHAL_STM32F0_RCC_SYSCLK_SRC_HSI48: { + size_t rdy; + whal_Reg_Update(base, RCC_CR2_REG, RCC_CR2_HSI48ON_Msk, + whal_SetBits(RCC_CR2_HSI48ON_Msk, RCC_CR2_HSI48ON_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR2_REG, + RCC_CR2_HSI48RDY_Msk, RCC_CR2_HSI48RDY_Pos, &rdy); + } while (!rdy); + sw = RCC_CFGR_SW_HSI48; + break; + } + + default: + return WHAL_EINVAL; + } + + /* Switch system clock */ + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_SW_Msk, + whal_SetBits(RCC_CFGR_SW_Msk, RCC_CFGR_SW_Pos, sw)); + + /* Wait for switch status to confirm */ + do { + whal_Reg_Get(base, RCC_CFGR_REG, + RCC_CFGR_SWS_Msk, RCC_CFGR_SWS_Pos, &sws); + } while (sws != sw); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Rcc_Deinit(whal_Clock *clkDev) +{ + size_t sws; + + if (!clkDev) + return WHAL_EINVAL; + + /* Switch back to HSI */ + whal_Reg_Update(clkDev->regmap.base, RCC_CR_REG, RCC_CR_HSION_Msk, + whal_SetBits(RCC_CR_HSION_Msk, RCC_CR_HSION_Pos, 1)); + + size_t rdy; + do { + whal_Reg_Get(clkDev->regmap.base, RCC_CR_REG, + RCC_CR_HSIRDY_Msk, RCC_CR_HSIRDY_Pos, &rdy); + } while (!rdy); + + whal_Reg_Update(clkDev->regmap.base, RCC_CFGR_REG, RCC_CFGR_SW_Msk, + whal_SetBits(RCC_CFGR_SW_Msk, RCC_CFGR_SW_Pos, + RCC_CFGR_SW_HSI)); + + do { + whal_Reg_Get(clkDev->regmap.base, RCC_CFGR_REG, + RCC_CFGR_SWS_Msk, RCC_CFGR_SWS_Pos, &sws); + } while (sws != RCC_CFGR_SW_HSI); + + /* Disable PLL and HSI48 */ + whal_Reg_Update(clkDev->regmap.base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 0)); + whal_Reg_Update(clkDev->regmap.base, RCC_CR2_REG, RCC_CR2_HSI48ON_Msk, + whal_SetBits(RCC_CR2_HSI48ON_Msk, RCC_CR2_HSI48ON_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Rcc_Enable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32f0Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32f0Rcc_Clk *)clk; + + whal_Reg_Update(clkDev->regmap.base, stClk->regOffset, stClk->enableMask, + whal_SetBits(stClk->enableMask, stClk->enablePos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Rcc_Disable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32f0Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32f0Rcc_Clk *)clk; + + whal_Reg_Update(clkDev->regmap.base, stClk->regOffset, stClk->enableMask, + whal_SetBits(stClk->enableMask, stClk->enablePos, 0)); + + return WHAL_SUCCESS; +} + +#ifndef WHAL_CFG_CLOCK_API_MAPPING_STM32F0 +const whal_ClockDriver whal_Stm32f0Rcc_Driver = { + .Init = whal_Stm32f0Rcc_Init, + .Deinit = whal_Stm32f0Rcc_Deinit, + .Enable = whal_Stm32f0Rcc_Enable, + .Disable = whal_Stm32f0Rcc_Disable, +}; +#endif /* !WHAL_CFG_CLOCK_API_MAPPING_STM32F0 */ diff --git a/src/flash/stm32f0_flash.c b/src/flash/stm32f0_flash.c new file mode 100644 index 0000000..17babf5 --- /dev/null +++ b/src/flash/stm32f0_flash.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include +#include +#include + +#define FLASH_ACR_REG 0x00 +#define FLASH_ACR_LATENCY_Pos 0 +#define FLASH_ACR_LATENCY_Msk (WHAL_BITMASK(3) << FLASH_ACR_LATENCY_Pos) + +#define FLASH_KEYR_REG 0x04 +#define FLASH_KEYR_KEY_Msk (~0UL) + +#define FLASH_SR_REG 0x0C +#define FLASH_SR_BSY_Pos 0 +#define FLASH_SR_BSY_Msk (1UL << FLASH_SR_BSY_Pos) +#define FLASH_SR_PGERR_Pos 2 +#define FLASH_SR_PGERR_Msk (1UL << FLASH_SR_PGERR_Pos) +#define FLASH_SR_WRPRTERR_Pos 4 +#define FLASH_SR_WRPRTERR_Msk (1UL << FLASH_SR_WRPRTERR_Pos) +#define FLASH_SR_EOP_Pos 5 +#define FLASH_SR_EOP_Msk (1UL << FLASH_SR_EOP_Pos) + +#define FLASH_SR_ALL_ERR (FLASH_SR_PGERR_Msk | FLASH_SR_WRPRTERR_Msk) + +#define FLASH_CR_REG 0x10 +#define FLASH_CR_PG_Pos 0 +#define FLASH_CR_PG_Msk (1UL << FLASH_CR_PG_Pos) +#define FLASH_CR_PER_Pos 1 +#define FLASH_CR_PER_Msk (1UL << FLASH_CR_PER_Pos) +#define FLASH_CR_STRT_Pos 6 +#define FLASH_CR_STRT_Msk (1UL << FLASH_CR_STRT_Pos) +#define FLASH_CR_LOCK_Pos 7 +#define FLASH_CR_LOCK_Msk (1UL << FLASH_CR_LOCK_Pos) + +#define FLASH_AR_REG 0x14 + +#ifdef WHAL_CFG_FLASH_API_MAPPING_STM32F0 +#define whal_Stm32f0Flash_Init whal_Flash_Init +#define whal_Stm32f0Flash_Deinit whal_Flash_Deinit +#define whal_Stm32f0Flash_Lock whal_Flash_Lock +#define whal_Stm32f0Flash_Unlock whal_Flash_Unlock +#define whal_Stm32f0Flash_Read whal_Flash_Read +#define whal_Stm32f0Flash_Write whal_Flash_Write +#define whal_Stm32f0Flash_Erase whal_Flash_Erase +#endif /* WHAL_CFG_FLASH_API_MAPPING_STM32F0 */ + +whal_Error whal_Stm32f0Flash_Init(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Flash_Deinit(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len) +{ + (void)addr; + (void)len; + + if (!flashDev) + return WHAL_EINVAL; + + whal_Reg_Update(flashDev->regmap.base, FLASH_CR_REG, FLASH_CR_LOCK_Msk, + whal_SetBits(FLASH_CR_LOCK_Msk, FLASH_CR_LOCK_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len) +{ + (void)addr; + (void)len; + + if (!flashDev) + return WHAL_EINVAL; + + whal_Reg_Update(flashDev->regmap.base, FLASH_KEYR_REG, + FLASH_KEYR_KEY_Msk, 0x45670123); + whal_Reg_Update(flashDev->regmap.base, FLASH_KEYR_REG, + FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Flash_Read(whal_Flash *flashDev, size_t addr, void *data, + size_t dataSz) +{ + whal_Stm32f0Flash_Cfg *cfg; + uint8_t *dataBuf = (uint8_t *)data; + + if (!flashDev || !flashDev->cfg || !data) + return WHAL_EINVAL; + + if (dataSz == 0) + return WHAL_SUCCESS; + + cfg = flashDev->cfg; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + uint8_t *flashAddr = (uint8_t *)addr; + for (size_t i = 0; i < dataSz; ++i) + dataBuf[i] = flashAddr[i]; + + return WHAL_SUCCESS; +} + +static whal_Error whal_Stm32f0Flash_WriteOrErase(whal_Flash *flashDev, + size_t addr, + const uint8_t *data, + size_t dataSz, uint8_t write) +{ + whal_Stm32f0Flash_Cfg *cfg; + const whal_Regmap *regmap; + size_t bsy; + + if (!flashDev || !flashDev->cfg) + return WHAL_EINVAL; + + cfg = flashDev->cfg; + regmap = &flashDev->regmap; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + /* Write requires 2-byte alignment (16-bit half-word programming) */ + if (write && ((addr & 0x1) || (dataSz & 0x1))) + return WHAL_EINVAL; + + if (!write && dataSz == 0) + return WHAL_SUCCESS; + + whal_Reg_Get(regmap->base, FLASH_SR_REG, + FLASH_SR_BSY_Msk, FLASH_SR_BSY_Pos, &bsy); + if (bsy) + return WHAL_ENOTREADY; + + /* Clear error flags */ + whal_Reg_Update(regmap->base, FLASH_SR_REG, FLASH_SR_ALL_ERR, 0xffffffff); + + whal_Error err = WHAL_SUCCESS; + + if (write) { + /* Enable programming */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PG_Msk, + whal_SetBits(FLASH_CR_PG_Msk, FLASH_CR_PG_Pos, 1)); + + /* Program in 16-bit half-words */ + for (size_t i = 0; i < dataSz; i += 2) { + volatile uint16_t *flashAddr = (volatile uint16_t *)(addr + i); + uint16_t hw = (uint16_t)data[i] | ((uint16_t)data[i + 1] << 8); + + *flashAddr = hw; + + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, + FLASH_SR_BSY_Msk, 0, cfg->timeout); + if (err) + goto cleanup; + } + } else { + /* Calculate page range (2 KB per page) */ + size_t startPage = (addr - cfg->startAddr) >> 11; + size_t endPage = ((addr - cfg->startAddr) + dataSz - 1) >> 11; + + for (size_t page = startPage; page <= endPage; ++page) { + /* Enable page erase */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PER_Msk, + whal_SetBits(FLASH_CR_PER_Msk, FLASH_CR_PER_Pos, 1)); + + /* Write page start address to AR */ + whal_Reg_Write(regmap->base, FLASH_AR_REG, + cfg->startAddr + (page << 11)); + + /* Start erase */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_STRT_Msk, + whal_SetBits(FLASH_CR_STRT_Msk, FLASH_CR_STRT_Pos, 1)); + + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, + FLASH_SR_BSY_Msk, 0, cfg->timeout); + if (err) + goto cleanup; + } + + /* Disable page erase */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PER_Msk, + whal_SetBits(FLASH_CR_PER_Msk, FLASH_CR_PER_Pos, 0)); + } + +cleanup: + whal_Reg_Update(regmap->base, FLASH_CR_REG, + FLASH_CR_PG_Msk | FLASH_CR_PER_Msk, 0); + + return err; +} + +whal_Error whal_Stm32f0Flash_Write(whal_Flash *flashDev, size_t addr, + const void *data, size_t dataSz) +{ + return whal_Stm32f0Flash_WriteOrErase(flashDev, addr, + (const uint8_t *)data, dataSz, 1); +} + +whal_Error whal_Stm32f0Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz) +{ + return whal_Stm32f0Flash_WriteOrErase(flashDev, addr, NULL, dataSz, 0); +} + +whal_Error whal_Stm32f0Flash_Ext_SetLatency(whal_Flash *flashDev, + enum whal_Stm32f0Flash_Latency latency) +{ + if (!flashDev) + return WHAL_EINVAL; + + whal_Reg_Update(flashDev->regmap.base, FLASH_ACR_REG, + FLASH_ACR_LATENCY_Msk, latency); + return WHAL_SUCCESS; +} + +#ifndef WHAL_CFG_FLASH_API_MAPPING_STM32F0 +const whal_FlashDriver whal_Stm32f0Flash_Driver = { + .Init = whal_Stm32f0Flash_Init, + .Deinit = whal_Stm32f0Flash_Deinit, + .Lock = whal_Stm32f0Flash_Lock, + .Unlock = whal_Stm32f0Flash_Unlock, + .Read = whal_Stm32f0Flash_Read, + .Write = whal_Stm32f0Flash_Write, + .Erase = whal_Stm32f0Flash_Erase, +}; +#endif /* !WHAL_CFG_FLASH_API_MAPPING_STM32F0 */ diff --git a/src/gpio/stm32f0_gpio.c b/src/gpio/stm32f0_gpio.c new file mode 100644 index 0000000..7ddf812 --- /dev/null +++ b/src/gpio/stm32f0_gpio.c @@ -0,0 +1 @@ +#include "stm32wb_gpio.c" diff --git a/src/gpio/stm32wb_gpio.c b/src/gpio/stm32wb_gpio.c index 782252d..96dd1df 100644 --- a/src/gpio/stm32wb_gpio.c +++ b/src/gpio/stm32wb_gpio.c @@ -35,7 +35,8 @@ #if defined(WHAL_CFG_GPIO_API_MAPPING_STM32WB) || \ defined(WHAL_CFG_GPIO_API_MAPPING_STM32F4) || \ defined(WHAL_CFG_GPIO_API_MAPPING_STM32H5) || \ - defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) + defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) || \ + defined(WHAL_CFG_GPIO_API_MAPPING_STM32F0) #define whal_Stm32wbGpio_Init whal_Gpio_Init #define whal_Stm32wbGpio_Deinit whal_Gpio_Deinit #define whal_Stm32wbGpio_Get whal_Gpio_Get @@ -179,7 +180,8 @@ whal_Error whal_Stm32wbGpio_Set(whal_Gpio *gpioDev, size_t pin, size_t value) #if !defined(WHAL_CFG_GPIO_API_MAPPING_STM32WB) && \ !defined(WHAL_CFG_GPIO_API_MAPPING_STM32F4) && \ !defined(WHAL_CFG_GPIO_API_MAPPING_STM32H5) && \ - !defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) + !defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) && \ + !defined(WHAL_CFG_GPIO_API_MAPPING_STM32F0) const whal_GpioDriver whal_Stm32wbGpio_Driver = { .Init = whal_Stm32wbGpio_Init, .Deinit = whal_Stm32wbGpio_Deinit, diff --git a/src/i2c/stm32f0_i2c.c b/src/i2c/stm32f0_i2c.c new file mode 100644 index 0000000..394f909 --- /dev/null +++ b/src/i2c/stm32f0_i2c.c @@ -0,0 +1 @@ +#include "stm32wb_i2c.c" diff --git a/src/i2c/stm32wb_i2c.c b/src/i2c/stm32wb_i2c.c index c6cde78..f93dce7 100644 --- a/src/i2c/stm32wb_i2c.c +++ b/src/i2c/stm32wb_i2c.c @@ -121,13 +121,14 @@ #define I2C_FMP_TLOW_NS 500 /* Fast mode plus tLOW min */ #define I2C_FMP_THIGH_NS 260 /* Fast mode plus tHIGH min */ -#ifdef WHAL_CFG_I2C_API_MAPPING_STM32WB +#if defined(WHAL_CFG_I2C_API_MAPPING_STM32WB) || \ + defined(WHAL_CFG_I2C_API_MAPPING_STM32F0) #define whal_Stm32wbI2c_Init whal_I2c_Init #define whal_Stm32wbI2c_Deinit whal_I2c_Deinit #define whal_Stm32wbI2c_StartCom whal_I2c_StartCom #define whal_Stm32wbI2c_EndCom whal_I2c_EndCom #define whal_Stm32wbI2c_Transfer whal_I2c_Transfer -#endif /* WHAL_CFG_I2C_API_MAPPING_STM32WB */ +#endif /* WHAL_CFG_I2C_API_MAPPING */ static uint32_t Stm32wbI2c_CalcTimingr(uint32_t pclk, uint32_t freq) { @@ -508,7 +509,8 @@ whal_Error whal_Stm32wbI2c_Transfer(whal_I2c *i2cDev, whal_I2c_Msg *msgs, return WHAL_SUCCESS; } -#ifndef WHAL_CFG_I2C_API_MAPPING_STM32WB +#if !defined(WHAL_CFG_I2C_API_MAPPING_STM32WB) && \ + !defined(WHAL_CFG_I2C_API_MAPPING_STM32F0) const whal_I2cDriver whal_Stm32wbI2c_Driver = { .Init = whal_Stm32wbI2c_Init, .Deinit = whal_Stm32wbI2c_Deinit, @@ -516,4 +518,4 @@ const whal_I2cDriver whal_Stm32wbI2c_Driver = { .EndCom = whal_Stm32wbI2c_EndCom, .Transfer = whal_Stm32wbI2c_Transfer, }; -#endif /* !WHAL_CFG_I2C_API_MAPPING_STM32WB */ +#endif /* !WHAL_CFG_I2C_API_MAPPING */ diff --git a/src/spi/stm32f0_spi.c b/src/spi/stm32f0_spi.c new file mode 100644 index 0000000..b28e2b9 --- /dev/null +++ b/src/spi/stm32f0_spi.c @@ -0,0 +1 @@ +#include "stm32wb_spi.c" diff --git a/src/spi/stm32wb_spi.c b/src/spi/stm32wb_spi.c index c5e2641..11ecdbb 100644 --- a/src/spi/stm32wb_spi.c +++ b/src/spi/stm32wb_spi.c @@ -61,7 +61,8 @@ #define SPI_DR_Msk (WHAL_BITMASK(8) << SPI_DR_Pos) #if defined(WHAL_CFG_SPI_API_MAPPING_STM32WB) || \ - defined(WHAL_CFG_SPI_API_MAPPING_STM32C0) + defined(WHAL_CFG_SPI_API_MAPPING_STM32C0) || \ + defined(WHAL_CFG_SPI_API_MAPPING_STM32F0) #define whal_Stm32wbSpi_Init whal_Spi_Init #define whal_Stm32wbSpi_Deinit whal_Spi_Deinit #define whal_Stm32wbSpi_StartCom whal_Spi_StartCom @@ -249,7 +250,8 @@ whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, } #if !defined(WHAL_CFG_SPI_API_MAPPING_STM32WB) && \ - !defined(WHAL_CFG_SPI_API_MAPPING_STM32C0) + !defined(WHAL_CFG_SPI_API_MAPPING_STM32C0) && \ + !defined(WHAL_CFG_SPI_API_MAPPING_STM32F0) const whal_SpiDriver whal_Stm32wbSpi_Driver = { .Init = whal_Stm32wbSpi_Init, .Deinit = whal_Stm32wbSpi_Deinit, diff --git a/src/uart/stm32f0_uart.c b/src/uart/stm32f0_uart.c new file mode 100644 index 0000000..61e1d15 --- /dev/null +++ b/src/uart/stm32f0_uart.c @@ -0,0 +1,172 @@ +#include +#include +#include +#include +#include +#include +#include + +#define UART_CR1_REG 0x00 +#define UART_CR1_UE_Pos 0 +#define UART_CR1_UE_Msk (1UL << UART_CR1_UE_Pos) +#define UART_CR1_RE_Pos 2 +#define UART_CR1_RE_Msk (1UL << UART_CR1_RE_Pos) +#define UART_CR1_TE_Pos 3 +#define UART_CR1_TE_Msk (1UL << UART_CR1_TE_Pos) + +#define UART_BRR_REG 0x0C +#define UART_BRR_Pos 0 +#define UART_BRR_Msk (WHAL_BITMASK(16) << UART_BRR_Pos) + +#define UART_ISR_REG 0x1C +#define UART_ISR_RXNE_Pos 5 +#define UART_ISR_RXNE_Msk (1UL << UART_ISR_RXNE_Pos) +#define UART_ISR_TC_Pos 6 +#define UART_ISR_TC_Msk (1UL << UART_ISR_TC_Pos) +#define UART_ISR_TXE_Pos 7 +#define UART_ISR_TXE_Msk (1UL << UART_ISR_TXE_Pos) + +#define UART_RDR_REG 0x24 +#define UART_RDR_Pos 0 +#define UART_RDR_Msk (WHAL_BITMASK(9) << UART_RDR_Pos) + +#define UART_TDR_REG 0x28 +#define UART_TDR_Pos 0 +#define UART_TDR_Msk (WHAL_BITMASK(9) << UART_TDR_Pos) + +#ifdef WHAL_CFG_UART_API_MAPPING_STM32F0 +#define whal_Stm32f0Uart_Init whal_Uart_Init +#define whal_Stm32f0Uart_Deinit whal_Uart_Deinit +#define whal_Stm32f0Uart_Send whal_Uart_Send +#define whal_Stm32f0Uart_Recv whal_Uart_Recv +#define whal_Stm32f0Uart_SendAsync whal_Uart_SendAsync +#define whal_Stm32f0Uart_RecvAsync whal_Uart_RecvAsync +#endif /* WHAL_CFG_UART_API_MAPPING_STM32F0 */ + +whal_Error whal_Stm32f0Uart_Init(whal_Uart *uartDev) +{ + whal_Stm32f0Uart_Cfg *cfg; + const whal_Regmap *reg; + + if (!uartDev || !uartDev->cfg) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + cfg = (whal_Stm32f0Uart_Cfg *)uartDev->cfg; + + whal_Reg_Update(reg->base, UART_BRR_REG, UART_BRR_Msk, + whal_SetBits(UART_BRR_Msk, UART_BRR_Pos, cfg->brr)); + + /* Enable UE, RE, TE — no FIFOEN on STM32F0 */ + whal_Reg_Update(reg->base, UART_CR1_REG, + UART_CR1_UE_Msk | UART_CR1_RE_Msk | UART_CR1_TE_Msk, + whal_SetBits(UART_CR1_UE_Msk, UART_CR1_UE_Pos, 1) | + whal_SetBits(UART_CR1_RE_Msk, UART_CR1_RE_Pos, 1) | + whal_SetBits(UART_CR1_TE_Msk, UART_CR1_TE_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Uart_Deinit(whal_Uart *uartDev) +{ + const whal_Regmap *reg; + + if (!uartDev) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + + whal_Reg_Update(reg->base, UART_CR1_REG, + UART_CR1_UE_Msk | UART_CR1_RE_Msk | UART_CR1_TE_Msk, + whal_SetBits(UART_CR1_UE_Msk, UART_CR1_UE_Pos, 0) | + whal_SetBits(UART_CR1_RE_Msk, UART_CR1_RE_Pos, 0) | + whal_SetBits(UART_CR1_TE_Msk, UART_CR1_TE_Pos, 0)); + + whal_Reg_Update(reg->base, UART_BRR_REG, UART_BRR_Msk, + whal_SetBits(UART_BRR_Msk, UART_BRR_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Uart_Send(whal_Uart *uartDev, const void *data, + size_t dataSz) +{ + const whal_Regmap *reg; + whal_Stm32f0Uart_Cfg *cfg; + const uint8_t *buf = data; + + if (!uartDev || !uartDev->cfg || !data) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + cfg = (whal_Stm32f0Uart_Cfg *)uartDev->cfg; + + for (size_t i = 0; i < dataSz; ++i) { + whal_Error err; + whal_Reg_Update(reg->base, UART_TDR_REG, UART_TDR_Msk, + whal_SetBits(UART_TDR_Msk, UART_TDR_Pos, buf[i])); + + err = whal_Reg_ReadPoll(reg->base, UART_ISR_REG, UART_ISR_TC_Msk, + UART_ISR_TC_Msk, cfg->timeout); + if (err) + return err; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Uart_Recv(whal_Uart *uartDev, void *data, size_t dataSz) +{ + const whal_Regmap *reg; + whal_Stm32f0Uart_Cfg *cfg; + uint8_t *buf = data; + + if (!uartDev || !uartDev->cfg || !data) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + cfg = (whal_Stm32f0Uart_Cfg *)uartDev->cfg; + + for (size_t i = 0; i < dataSz; ++i) { + size_t d; + whal_Error err = whal_Reg_ReadPoll(reg->base, UART_ISR_REG, + UART_ISR_RXNE_Msk, + UART_ISR_RXNE_Msk, cfg->timeout); + if (err) + return err; + + whal_Reg_Get(reg->base, UART_RDR_REG, UART_RDR_Msk, UART_RDR_Pos, &d); + buf[i] = d; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Uart_SendAsync(whal_Uart *uartDev, const void *data, + size_t dataSz) +{ + (void)dataSz; + if (!uartDev || !data) + return WHAL_EINVAL; + return WHAL_ENOTSUP; +} + +whal_Error whal_Stm32f0Uart_RecvAsync(whal_Uart *uartDev, void *data, + size_t dataSz) +{ + (void)dataSz; + if (!uartDev || !data) + return WHAL_EINVAL; + return WHAL_ENOTSUP; +} + +#ifndef WHAL_CFG_UART_API_MAPPING_STM32F0 +const whal_UartDriver whal_Stm32f0Uart_Driver = { + .Init = whal_Stm32f0Uart_Init, + .Deinit = whal_Stm32f0Uart_Deinit, + .Send = whal_Stm32f0Uart_Send, + .Recv = whal_Stm32f0Uart_Recv, + .SendAsync = whal_Stm32f0Uart_SendAsync, + .RecvAsync = whal_Stm32f0Uart_RecvAsync, +}; +#endif /* !WHAL_CFG_UART_API_MAPPING_STM32F0 */ diff --git a/src/watchdog/stm32f0_iwdg.c b/src/watchdog/stm32f0_iwdg.c new file mode 100644 index 0000000..a0cd8a4 --- /dev/null +++ b/src/watchdog/stm32f0_iwdg.c @@ -0,0 +1,4 @@ +#ifdef WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_IWDG +#define WHAL_CFG_WATCHDOG_API_MAPPING_STM32WB_IWDG +#endif +#include "stm32wb_iwdg.c" diff --git a/src/watchdog/stm32f0_wwdg.c b/src/watchdog/stm32f0_wwdg.c new file mode 100644 index 0000000..38ab207 --- /dev/null +++ b/src/watchdog/stm32f0_wwdg.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + +#define CR_REG 0x00 +#define CR_T_Pos 0 +#define CR_T_Msk (WHAL_BITMASK(7) << CR_T_Pos) +#define CR_WDGA_Pos 7 +#define CR_WDGA_Msk (1UL << CR_WDGA_Pos) + +#define CFR_REG 0x04 +#define CFR_W_Pos 0 +#define CFR_W_Msk (WHAL_BITMASK(7) << CFR_W_Pos) +#define CFR_WDGTB_Pos 7 +#define CFR_WDGTB_Msk (WHAL_BITMASK(2) << CFR_WDGTB_Pos) +#define CFR_EWI_Pos 9 +#define CFR_EWI_Msk (1UL << CFR_EWI_Pos) + +#ifdef WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG +#define whal_Stm32f0Wwdg_Init whal_Watchdog_Init +#define whal_Stm32f0Wwdg_Deinit whal_Watchdog_Deinit +#define whal_Stm32f0Wwdg_Refresh whal_Watchdog_Refresh +#endif /* WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG */ + +whal_Error whal_Stm32f0Wwdg_Init(whal_Watchdog *wdgDev) +{ + size_t base; + whal_Stm32f0Wwdg_Cfg *cfg; + + if (!wdgDev || !wdgDev->cfg) + return WHAL_EINVAL; + + base = wdgDev->regmap.base; + cfg = wdgDev->cfg; + + if (cfg->prescaler > 3 || cfg->window > 0x7F || cfg->counter > 0x7F) + return WHAL_EINVAL; + + whal_Reg_Update(base, CFR_REG, CFR_W_Msk | CFR_WDGTB_Msk, + whal_SetBits(CFR_W_Msk, CFR_W_Pos, cfg->window) | + whal_SetBits(CFR_WDGTB_Msk, CFR_WDGTB_Pos, cfg->prescaler)); + + whal_Reg_Write(base, CR_REG, CR_WDGA_Msk | cfg->counter); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Wwdg_Deinit(whal_Watchdog *wdgDev) +{ + if (!wdgDev) + return WHAL_EINVAL; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f0Wwdg_Refresh(whal_Watchdog *wdgDev) +{ + size_t base; + whal_Stm32f0Wwdg_Cfg *cfg; + + if (!wdgDev || !wdgDev->cfg) + return WHAL_EINVAL; + + base = wdgDev->regmap.base; + cfg = wdgDev->cfg; + + whal_Reg_Write(base, CR_REG, CR_WDGA_Msk | cfg->counter); + + return WHAL_SUCCESS; +} + +#ifndef WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG +const whal_WatchdogDriver whal_Stm32f0Wwdg_Driver = { + .Init = whal_Stm32f0Wwdg_Init, + .Deinit = whal_Stm32f0Wwdg_Deinit, + .Refresh = whal_Stm32f0Wwdg_Refresh, +}; +#endif /* !WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG */ diff --git a/tests/gpio/test_stm32f0_gpio.c b/tests/gpio/test_stm32f0_gpio.c new file mode 100644 index 0000000..c287cb9 --- /dev/null +++ b/tests/gpio/test_stm32f0_gpio.c @@ -0,0 +1 @@ +#include "test_stm32wb_gpio.c" diff --git a/tests/watchdog/test_watchdog.c b/tests/watchdog/test_watchdog.c index 5a0405d..f3f4b08 100644 --- a/tests/watchdog/test_watchdog.c +++ b/tests/watchdog/test_watchdog.c @@ -85,14 +85,15 @@ static void Test_Watchdog(void) while (1); } - /* Phase 1: watchdog fired — verify refresh loop completed and clean up */ - WHAL_ASSERT_EQ(state.refreshOk, WDG_TEST_REFRESH_OK); + /* Phase 1: watchdog fired — clean up first, then verify */ + uint32_t refreshOk = state.refreshOk; WHAL_ASSERT_EQ(whal_Flash_Unlock(&g_whalFlash, BOARD_FLASH_TEST_ADDR, BOARD_FLASH_SECTOR_SZ), WHAL_SUCCESS); WHAL_ASSERT_EQ(whal_Flash_Erase(&g_whalFlash, BOARD_FLASH_TEST_ADDR, BOARD_FLASH_SECTOR_SZ), WHAL_SUCCESS); WHAL_ASSERT_EQ(whal_Flash_Lock(&g_whalFlash, BOARD_FLASH_TEST_ADDR, BOARD_FLASH_SECTOR_SZ), WHAL_SUCCESS); + WHAL_ASSERT_EQ(refreshOk, WDG_TEST_REFRESH_OK); } void whal_Test_Watchdog(void) diff --git a/wolfHAL/clock/stm32f0_rcc.h b/wolfHAL/clock/stm32f0_rcc.h new file mode 100644 index 0000000..8bf2163 --- /dev/null +++ b/wolfHAL/clock/stm32f0_rcc.h @@ -0,0 +1,65 @@ +#ifndef WHAL_STM32F0_RCC_H +#define WHAL_STM32F0_RCC_H + +#include +#include +#include + +/* + * @file stm32f0_rcc.h + * @brief STM32F0 RCC (Reset and Clock Control) driver configuration. + * + * The STM32F0 RCC peripheral controls: + * - System clock source selection (HSI, HSE, PLL, HSI48) + * - PLL with PREDIV prescaler and PLLMUL multiplier + * - Peripheral clock gating (AHB, APB1, APB2 buses) + * - HSI48 oscillator (available on F04x/F07x/F09x) + * + * Clock sources: + * HSI = 8 MHz internal RC oscillator + * HSE = 4-32 MHz external oscillator + * HSI48 = 48 MHz internal RC (F04x/F07x/F09x only) + * PLL = HSI/2, HSI/PREDIV, HSE/PREDIV, or HSI48/PREDIV * PLLMUL + */ + +typedef enum { + WHAL_STM32F0_RCC_SYSCLK_SRC_HSI, + WHAL_STM32F0_RCC_SYSCLK_SRC_HSE, + WHAL_STM32F0_RCC_SYSCLK_SRC_PLL, + WHAL_STM32F0_RCC_SYSCLK_SRC_HSI48, +} whal_Stm32f0Rcc_SysClockSrc; + +typedef enum { + WHAL_STM32F0_RCC_PLLSRC_HSI_DIV2, + WHAL_STM32F0_RCC_PLLSRC_HSI_PREDIV, + WHAL_STM32F0_RCC_PLLSRC_HSE_PREDIV, + WHAL_STM32F0_RCC_PLLSRC_HSI48_PREDIV, +} whal_Stm32f0Rcc_PllClockSrc; + +typedef struct { + whal_Stm32f0Rcc_PllClockSrc clkSrc; + uint8_t prediv; /* 1-16 (written as value - 1) */ + uint8_t pllmul; /* 2-16 (written as value - 2) */ +} whal_Stm32f0Rcc_PllCfg; + +typedef struct whal_Stm32f0Rcc_Clk { + size_t regOffset; + size_t enableMask; + size_t enablePos; +} whal_Stm32f0Rcc_Clk; + +typedef struct whal_Stm32f0Rcc_Cfg { + whal_Stm32f0Rcc_SysClockSrc sysClkSrc; + whal_Stm32f0Rcc_PllCfg *pllCfg; +} whal_Stm32f0Rcc_Cfg; + +#ifndef WHAL_CFG_CLOCK_API_MAPPING_STM32F0 +extern const whal_ClockDriver whal_Stm32f0Rcc_Driver; + +whal_Error whal_Stm32f0Rcc_Init(whal_Clock *clkDev); +whal_Error whal_Stm32f0Rcc_Deinit(whal_Clock *clkDev); +whal_Error whal_Stm32f0Rcc_Enable(whal_Clock *clkDev, const void *clk); +whal_Error whal_Stm32f0Rcc_Disable(whal_Clock *clkDev, const void *clk); +#endif /* !WHAL_CFG_CLOCK_API_MAPPING_STM32F0 */ + +#endif /* WHAL_STM32F0_RCC_H */ diff --git a/wolfHAL/flash/stm32f0_flash.h b/wolfHAL/flash/stm32f0_flash.h new file mode 100644 index 0000000..7d947e9 --- /dev/null +++ b/wolfHAL/flash/stm32f0_flash.h @@ -0,0 +1,47 @@ +#ifndef WHAL_STM32F0_FLASH_H +#define WHAL_STM32F0_FLASH_H + +#include +#include + +/* + * @file stm32f0_flash.h + * @brief STM32F0 flash driver configuration. + * + * The STM32F0 embedded flash provides: + * - Up to 256 KB organized in 2 KB pages + * - Half-word (16-bit) programming + * - Page erase via FLASH_AR address register + * - Configurable wait states based on CPU frequency + */ + +typedef struct whal_Stm32f0Flash_Cfg { + size_t startAddr; + size_t size; + whal_Timeout *timeout; +} whal_Stm32f0Flash_Cfg; + +typedef enum whal_Stm32f0Flash_Latency { + WHAL_STM32F0_FLASH_LATENCY_0, + WHAL_STM32F0_FLASH_LATENCY_1, +} whal_Stm32f0Flash_Latency; + +#ifndef WHAL_CFG_FLASH_API_MAPPING_STM32F0 +extern const whal_FlashDriver whal_Stm32f0Flash_Driver; + +whal_Error whal_Stm32f0Flash_Init(whal_Flash *flashDev); +whal_Error whal_Stm32f0Flash_Deinit(whal_Flash *flashDev); +whal_Error whal_Stm32f0Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len); +whal_Error whal_Stm32f0Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); +whal_Error whal_Stm32f0Flash_Read(whal_Flash *flashDev, size_t addr, void *data, + size_t dataSz); +whal_Error whal_Stm32f0Flash_Write(whal_Flash *flashDev, size_t addr, + const void *data, size_t dataSz); +whal_Error whal_Stm32f0Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz); +#endif /* !WHAL_CFG_FLASH_API_MAPPING_STM32F0 */ + +whal_Error whal_Stm32f0Flash_Ext_SetLatency(whal_Flash *flashDev, + enum whal_Stm32f0Flash_Latency latency); + +#endif /* WHAL_STM32F0_FLASH_H */ diff --git a/wolfHAL/gpio/stm32f0_gpio.h b/wolfHAL/gpio/stm32f0_gpio.h new file mode 100644 index 0000000..6be1daf --- /dev/null +++ b/wolfHAL/gpio/stm32f0_gpio.h @@ -0,0 +1,52 @@ +#ifndef WHAL_STM32F0_GPIO_H +#define WHAL_STM32F0_GPIO_H + +/* + * @file stm32f0_gpio.h + * @brief STM32F0 GPIO driver (alias for STM32WB GPIO). + * + * The STM32F0 GPIO peripheral is register-compatible with the STM32WB GPIO. + * This header re-exports the STM32WB GPIO driver types and symbols under + * STM32F0-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbGpio_Cfg whal_Stm32f0Gpio_Cfg; +typedef whal_Stm32wbGpio_PinCfg whal_Stm32f0Gpio_PinCfg; + +#ifndef WHAL_CFG_GPIO_API_MAPPING_STM32F0 +#define whal_Stm32f0Gpio_Driver whal_Stm32wbGpio_Driver +#define whal_Stm32f0Gpio_Init whal_Stm32wbGpio_Init +#define whal_Stm32f0Gpio_Deinit whal_Stm32wbGpio_Deinit +#define whal_Stm32f0Gpio_Get whal_Stm32wbGpio_Get +#define whal_Stm32f0Gpio_Set whal_Stm32wbGpio_Set +#endif /* !WHAL_CFG_GPIO_API_MAPPING_STM32F0 */ + +#define WHAL_STM32F0_GPIO_MODE_IN WHAL_STM32WB_GPIO_MODE_IN +#define WHAL_STM32F0_GPIO_MODE_OUT WHAL_STM32WB_GPIO_MODE_OUT +#define WHAL_STM32F0_GPIO_MODE_ALTFN WHAL_STM32WB_GPIO_MODE_ALTFN +#define WHAL_STM32F0_GPIO_MODE_ANALOG WHAL_STM32WB_GPIO_MODE_ANALOG + +#define WHAL_STM32F0_GPIO_OUTTYPE_PUSHPULL WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL +#define WHAL_STM32F0_GPIO_OUTTYPE_OPENDRAIN WHAL_STM32WB_GPIO_OUTTYPE_OPENDRAIN + +#define WHAL_STM32F0_GPIO_SPEED_LOW WHAL_STM32WB_GPIO_SPEED_LOW +#define WHAL_STM32F0_GPIO_SPEED_MEDIUM WHAL_STM32WB_GPIO_SPEED_MEDIUM +#define WHAL_STM32F0_GPIO_SPEED_FAST WHAL_STM32WB_GPIO_SPEED_FAST +#define WHAL_STM32F0_GPIO_SPEED_HIGH WHAL_STM32WB_GPIO_SPEED_HIGH + +#define WHAL_STM32F0_GPIO_PULL_NONE WHAL_STM32WB_GPIO_PULL_NONE +#define WHAL_STM32F0_GPIO_PULL_UP WHAL_STM32WB_GPIO_PULL_UP +#define WHAL_STM32F0_GPIO_PULL_DOWN WHAL_STM32WB_GPIO_PULL_DOWN + +#define WHAL_STM32F0_GPIO_PORT_A WHAL_STM32WB_GPIO_PORT_A +#define WHAL_STM32F0_GPIO_PORT_B WHAL_STM32WB_GPIO_PORT_B +#define WHAL_STM32F0_GPIO_PORT_C WHAL_STM32WB_GPIO_PORT_C +#define WHAL_STM32F0_GPIO_PORT_D WHAL_STM32WB_GPIO_PORT_D +#define WHAL_STM32F0_GPIO_PORT_E WHAL_STM32WB_GPIO_PORT_E +#define WHAL_STM32F0_GPIO_PORT_F WHAL_STM32WB_GPIO_PORT_F + +#define WHAL_STM32F0_GPIO_PIN WHAL_STM32WB_GPIO_PIN + +#endif /* WHAL_STM32F0_GPIO_H */ diff --git a/wolfHAL/gpio/stm32wb_gpio.h b/wolfHAL/gpio/stm32wb_gpio.h index a3a9461..41d7030 100644 --- a/wolfHAL/gpio/stm32wb_gpio.h +++ b/wolfHAL/gpio/stm32wb_gpio.h @@ -110,7 +110,8 @@ typedef struct { #if !defined(WHAL_CFG_GPIO_API_MAPPING_STM32WB) && \ !defined(WHAL_CFG_GPIO_API_MAPPING_STM32F4) && \ !defined(WHAL_CFG_GPIO_API_MAPPING_STM32H5) && \ - !defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) + !defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) && \ + !defined(WHAL_CFG_GPIO_API_MAPPING_STM32F0) /* * @brief Driver instance for STM32 GPIO. */ diff --git a/wolfHAL/i2c/stm32f0_i2c.h b/wolfHAL/i2c/stm32f0_i2c.h new file mode 100644 index 0000000..90b59ef --- /dev/null +++ b/wolfHAL/i2c/stm32f0_i2c.h @@ -0,0 +1,26 @@ +#ifndef WHAL_STM32F0_I2C_H +#define WHAL_STM32F0_I2C_H + +/* + * @file stm32f0_i2c.h + * @brief STM32F0 I2C driver (alias for STM32WB I2C). + * + * The STM32F0 I2C peripheral is register-compatible with the STM32WB I2C + * (I2C v2 with CR1/CR2/TIMINGR). This header re-exports the STM32WB I2C + * driver types and symbols under STM32F0-specific names. + */ + +#include + +typedef whal_Stm32wbI2c_Cfg whal_Stm32f0I2c_Cfg; + +#ifndef WHAL_CFG_I2C_API_MAPPING_STM32F0 +#define whal_Stm32f0I2c_Driver whal_Stm32wbI2c_Driver +#define whal_Stm32f0I2c_Init whal_Stm32wbI2c_Init +#define whal_Stm32f0I2c_Deinit whal_Stm32wbI2c_Deinit +#define whal_Stm32f0I2c_StartCom whal_Stm32wbI2c_StartCom +#define whal_Stm32f0I2c_EndCom whal_Stm32wbI2c_EndCom +#define whal_Stm32f0I2c_Transfer whal_Stm32wbI2c_Transfer +#endif /* !WHAL_CFG_I2C_API_MAPPING_STM32F0 */ + +#endif /* WHAL_STM32F0_I2C_H */ diff --git a/wolfHAL/platform/arm/cortex_m0.h b/wolfHAL/platform/arm/cortex_m0.h new file mode 100644 index 0000000..fc6bc26 --- /dev/null +++ b/wolfHAL/platform/arm/cortex_m0.h @@ -0,0 +1,11 @@ +#ifndef WHAL_CORTEX_M0_H +#define WHAL_CORTEX_M0_H + +#include + +#define WHAL_CORTEX_M0_SYSTICK_REGMAP \ + .base = 0xE000E010, \ + .size = 0x400 +#define WHAL_CORTEX_M0_SYSTICK_DRIVER &whal_SysTick_Driver + +#endif /* WHAL_CORTEX_M0_H */ diff --git a/wolfHAL/platform/st/stm32f091xx.h b/wolfHAL/platform/st/stm32f091xx.h new file mode 100644 index 0000000..d68eee8 --- /dev/null +++ b/wolfHAL/platform/st/stm32f091xx.h @@ -0,0 +1,264 @@ +#ifndef WHAL_STM32F091XX_H +#define WHAL_STM32F091XX_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * @file stm32f091xx.h + * @brief Convenience initializers for STM32F091xx device instances. + * + * Base addresses from RM0091 Table 1 (memory map). + * RCC: 0x40021000 + * GPIO: 0x48000000 (port A), 0x400 spacing per port + * USART1: 0x40013800, USART2: 0x40004400 + * SPI1: 0x40013000, SPI2: 0x40003800 + * I2C1: 0x40005400, I2C2: 0x40005800 + * Flash: 0x40022000 + * IWDG: 0x40003000, WWDG: 0x40002C00 + */ + +/* --- Device macros --- */ + +#define WHAL_STM32F091_RCC_REGMAP \ + .base = 0x40021000, \ + .size = 0x400 +#define WHAL_STM32F091_RCC_DRIVER &whal_Stm32f0Rcc_Driver + +#define WHAL_STM32F091_GPIO_REGMAP \ + .base = 0x48000000, \ + .size = 0x1800 +#define WHAL_STM32F091_GPIO_DRIVER &whal_Stm32f0Gpio_Driver + +#define WHAL_STM32F091_USART1_REGMAP \ + .base = 0x40013800, \ + .size = 0x400 +#define WHAL_STM32F091_USART1_DRIVER &whal_Stm32f0Uart_Driver + +#define WHAL_STM32F091_USART2_REGMAP \ + .base = 0x40004400, \ + .size = 0x400 +#define WHAL_STM32F091_USART2_DRIVER &whal_Stm32f0Uart_Driver + +#define WHAL_STM32F091_USART3_REGMAP \ + .base = 0x40004800, \ + .size = 0x400 +#define WHAL_STM32F091_USART3_DRIVER &whal_Stm32f0Uart_Driver + +#define WHAL_STM32F091_SPI1_REGMAP \ + .base = 0x40013000, \ + .size = 0x400 +#define WHAL_STM32F091_SPI1_DRIVER &whal_Stm32f0Spi_Driver + +#define WHAL_STM32F091_SPI2_REGMAP \ + .base = 0x40003800, \ + .size = 0x400 +#define WHAL_STM32F091_SPI2_DRIVER &whal_Stm32f0Spi_Driver + +#define WHAL_STM32F091_I2C1_REGMAP \ + .base = 0x40005400, \ + .size = 0x400 +#define WHAL_STM32F091_I2C1_DRIVER &whal_Stm32f0I2c_Driver + +#define WHAL_STM32F091_I2C2_REGMAP \ + .base = 0x40005800, \ + .size = 0x400 +#define WHAL_STM32F091_I2C2_DRIVER &whal_Stm32f0I2c_Driver + +#define WHAL_STM32F091_FLASH_REGMAP \ + .base = 0x40022000, \ + .size = 0x400 +#define WHAL_STM32F091_FLASH_DRIVER &whal_Stm32f0Flash_Driver + +#define WHAL_STM32F091_IWDG_REGMAP \ + .base = 0x40003000, \ + .size = 0x400 +#define WHAL_STM32F091_IWDG_DRIVER &whal_Stm32f0Iwdg_Driver + +#define WHAL_STM32F091_WWDG_REGMAP \ + .base = 0x40002C00, \ + .size = 0x400 +#define WHAL_STM32F091_WWDG_DRIVER &whal_Stm32f0Wwdg_Driver + +/* --- Clock gate macros --- */ + +/* RCC_AHBENR (offset 0x014) */ + +#define WHAL_STM32F091_GPIOA_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +#define WHAL_STM32F091_GPIOB_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 18), \ + .enablePos = 18 + +#define WHAL_STM32F091_GPIOC_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 19), \ + .enablePos = 19 + +#define WHAL_STM32F091_GPIOD_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 20), \ + .enablePos = 20 + +#define WHAL_STM32F091_GPIOE_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 21), \ + .enablePos = 21 + +#define WHAL_STM32F091_GPIOF_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 22), \ + .enablePos = 22 + +#define WHAL_STM32F091_FLASH_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32F091_DMA1_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32F091_DMA2_CLOCK \ + .regOffset = 0x014, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +/* RCC_APB2ENR (offset 0x018) */ + +#define WHAL_STM32F091_SYSCFG_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32F091_USART6_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 5), \ + .enablePos = 5 + +#define WHAL_STM32F091_USART7_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 6), \ + .enablePos = 6 + +#define WHAL_STM32F091_USART8_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 7), \ + .enablePos = 7 + +#define WHAL_STM32F091_TIM1_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 11), \ + .enablePos = 11 + +#define WHAL_STM32F091_SPI1_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 12), \ + .enablePos = 12 + +#define WHAL_STM32F091_USART1_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +#define WHAL_STM32F091_TIM15_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 16), \ + .enablePos = 16 + +#define WHAL_STM32F091_TIM16_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +#define WHAL_STM32F091_TIM17_CLOCK \ + .regOffset = 0x018, \ + .enableMask = (1UL << 18), \ + .enablePos = 18 + +/* RCC_APB1ENR (offset 0x01C) */ + +#define WHAL_STM32F091_TIM2_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32F091_TIM3_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +#define WHAL_STM32F091_TIM6_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32F091_TIM7_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 5), \ + .enablePos = 5 + +#define WHAL_STM32F091_TIM14_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 8), \ + .enablePos = 8 + +#define WHAL_STM32F091_WWDG_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 11), \ + .enablePos = 11 + +#define WHAL_STM32F091_SPI2_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +#define WHAL_STM32F091_USART2_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +#define WHAL_STM32F091_USART3_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 18), \ + .enablePos = 18 + +#define WHAL_STM32F091_USART4_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 19), \ + .enablePos = 19 + +#define WHAL_STM32F091_USART5_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 20), \ + .enablePos = 20 + +#define WHAL_STM32F091_I2C1_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 21), \ + .enablePos = 21 + +#define WHAL_STM32F091_I2C2_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 22), \ + .enablePos = 22 + +#define WHAL_STM32F091_PWR_CLOCK \ + .regOffset = 0x01C, \ + .enableMask = (1UL << 28), \ + .enablePos = 28 + +#endif /* WHAL_STM32F091XX_H */ diff --git a/wolfHAL/spi/stm32f0_spi.h b/wolfHAL/spi/stm32f0_spi.h new file mode 100644 index 0000000..c5fee5d --- /dev/null +++ b/wolfHAL/spi/stm32f0_spi.h @@ -0,0 +1,26 @@ +#ifndef WHAL_STM32F0_SPI_H +#define WHAL_STM32F0_SPI_H + +/* + * @file stm32f0_spi.h + * @brief STM32F0 SPI driver (alias for STM32WB SPI). + * + * The STM32F0 SPI peripheral is register-compatible with the STM32WB SPI + * (SPI v2 with DS[3:0] data size field in CR2). This header re-exports + * the STM32WB SPI driver types and symbols under STM32F0-specific names. + */ + +#include + +typedef whal_Stm32wbSpi_Cfg whal_Stm32f0Spi_Cfg; + +#ifndef WHAL_CFG_SPI_API_MAPPING_STM32F0 +#define whal_Stm32f0Spi_Driver whal_Stm32wbSpi_Driver +#define whal_Stm32f0Spi_Init whal_Stm32wbSpi_Init +#define whal_Stm32f0Spi_Deinit whal_Stm32wbSpi_Deinit +#define whal_Stm32f0Spi_StartCom whal_Stm32wbSpi_StartCom +#define whal_Stm32f0Spi_EndCom whal_Stm32wbSpi_EndCom +#define whal_Stm32f0Spi_SendRecv whal_Stm32wbSpi_SendRecv +#endif /* !WHAL_CFG_SPI_API_MAPPING_STM32F0 */ + +#endif /* WHAL_STM32F0_SPI_H */ diff --git a/wolfHAL/uart/stm32f0_uart.h b/wolfHAL/uart/stm32f0_uart.h new file mode 100644 index 0000000..66856f6 --- /dev/null +++ b/wolfHAL/uart/stm32f0_uart.h @@ -0,0 +1,35 @@ +#ifndef WHAL_STM32F0_UART_H +#define WHAL_STM32F0_UART_H + +#include +#include +#include +#include + +/* + * @file stm32f0_uart.h + * @brief STM32F0 UART driver — polled variant. + * + * The STM32F0 USART uses the same ISR/TDR/RDR register layout as the + * STM32WB but does not have the FIFOEN bit in CR1 (no hardware FIFO). + */ + +#define WHAL_STM32F0_UART_BRR(clk, baud) ((clk) / (baud)) + +typedef struct whal_Stm32f0Uart_Cfg { + uint32_t brr; + whal_Timeout *timeout; +} whal_Stm32f0Uart_Cfg; + +#ifndef WHAL_CFG_UART_API_MAPPING_STM32F0 +extern const whal_UartDriver whal_Stm32f0Uart_Driver; + +whal_Error whal_Stm32f0Uart_Init(whal_Uart *uartDev); +whal_Error whal_Stm32f0Uart_Deinit(whal_Uart *uartDev); +whal_Error whal_Stm32f0Uart_Send(whal_Uart *uartDev, const void *data, + size_t dataSz); +whal_Error whal_Stm32f0Uart_Recv(whal_Uart *uartDev, void *data, + size_t dataSz); +#endif /* !WHAL_CFG_UART_API_MAPPING_STM32F0 */ + +#endif /* WHAL_STM32F0_UART_H */ diff --git a/wolfHAL/watchdog/stm32f0_iwdg.h b/wolfHAL/watchdog/stm32f0_iwdg.h new file mode 100644 index 0000000..1a2f2ac --- /dev/null +++ b/wolfHAL/watchdog/stm32f0_iwdg.h @@ -0,0 +1,32 @@ +#ifndef WHAL_STM32F0_IWDG_H +#define WHAL_STM32F0_IWDG_H + +/* + * @file stm32f0_iwdg.h + * @brief STM32F0 IWDG driver (alias for STM32WB IWDG). + * + * The STM32F0 IWDG peripheral is register-compatible with the STM32WB IWDG. + * This header re-exports the STM32WB IWDG driver types and symbols under + * STM32F0-specific names. + */ + +#include + +typedef whal_Stm32wbIwdg_Cfg whal_Stm32f0Iwdg_Cfg; + +#ifndef WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_IWDG +#define whal_Stm32f0Iwdg_Driver whal_Stm32wbIwdg_Driver +#define whal_Stm32f0Iwdg_Init whal_Stm32wbIwdg_Init +#define whal_Stm32f0Iwdg_Deinit whal_Stm32wbIwdg_Deinit +#define whal_Stm32f0Iwdg_Refresh whal_Stm32wbIwdg_Refresh +#endif /* !WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_IWDG */ + +#define WHAL_STM32F0_IWDG_PR_4 WHAL_STM32WB_IWDG_PR_4 +#define WHAL_STM32F0_IWDG_PR_8 WHAL_STM32WB_IWDG_PR_8 +#define WHAL_STM32F0_IWDG_PR_16 WHAL_STM32WB_IWDG_PR_16 +#define WHAL_STM32F0_IWDG_PR_32 WHAL_STM32WB_IWDG_PR_32 +#define WHAL_STM32F0_IWDG_PR_64 WHAL_STM32WB_IWDG_PR_64 +#define WHAL_STM32F0_IWDG_PR_128 WHAL_STM32WB_IWDG_PR_128 +#define WHAL_STM32F0_IWDG_PR_256 WHAL_STM32WB_IWDG_PR_256 + +#endif /* WHAL_STM32F0_IWDG_H */ diff --git a/wolfHAL/watchdog/stm32f0_wwdg.h b/wolfHAL/watchdog/stm32f0_wwdg.h new file mode 100644 index 0000000..caecd3b --- /dev/null +++ b/wolfHAL/watchdog/stm32f0_wwdg.h @@ -0,0 +1,30 @@ +#ifndef WHAL_STM32F0_WWDG_H +#define WHAL_STM32F0_WWDG_H + +#include +#include +#include + +/* + * @file stm32f0_wwdg.h + * @brief STM32F0 window watchdog (WWDG) driver. + * + * The F0 WWDG has a 2-bit WDGTB prescaler at CFR bits 8:7 (divides by + * 1/2/4/8), unlike the WB which has a 3-bit WDGTB at bits 13:11. + */ + +typedef struct { + uint8_t prescaler; + uint8_t window; + uint8_t counter; +} whal_Stm32f0Wwdg_Cfg; + +#ifndef WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG +extern const whal_WatchdogDriver whal_Stm32f0Wwdg_Driver; + +whal_Error whal_Stm32f0Wwdg_Init(whal_Watchdog *wdgDev); +whal_Error whal_Stm32f0Wwdg_Deinit(whal_Watchdog *wdgDev); +whal_Error whal_Stm32f0Wwdg_Refresh(whal_Watchdog *wdgDev); +#endif /* !WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG */ + +#endif /* WHAL_STM32F0_WWDG_H */