From 27229bb8824b8e83402a3816a93275ed3b775cc9 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Mon, 30 Mar 2026 13:14:12 -0400 Subject: [PATCH] [stm32c0, stm32c031_nucleo] Implement support for the stm32c0 --- .github/workflows/ci.yml | 2 +- boards/stm32c031_nucleo/Makefile.inc | 37 ++++ boards/stm32c031_nucleo/board.c | 252 +++++++++++++++++++++++ boards/stm32c031_nucleo/board.h | 41 ++++ boards/stm32c031_nucleo/ivt.c | 151 ++++++++++++++ boards/stm32c031_nucleo/linker.ld | 121 +++++++++++ boards/stm32h563zi_nucleo/board.h | 6 +- boards/stm32wb55xx_nucleo/board.h | 4 + src/clock/stm32c0_rcc.c | 139 +++++++++++++ src/flash/stm32c0_flash.c | 291 +++++++++++++++++++++++++++ src/flash/stm32wb_flash.c | 5 +- src/gpio/stm32c0_gpio.c | 1 + src/spi/stm32c0_spi.c | 1 + src/uart/stm32c0_uart.c | 1 + tests/flash/test_flash.c | 34 ++++ tests/gpio/test_stm32c0_gpio.c | 1 + tests/gpio/test_stm32wb_gpio.c | 40 ++-- wolfHAL/clock/stm32c0_rcc.h | 127 ++++++++++++ wolfHAL/flash/stm32c0_flash.h | 147 ++++++++++++++ wolfHAL/gpio/stm32c0_gpio.h | 62 ++++++ wolfHAL/platform/arm/cortex_m0plus.h | 13 ++ wolfHAL/platform/st/stm32c031xx.h | 185 +++++++++++++++++ wolfHAL/spi/stm32c0_spi.h | 24 +++ wolfHAL/uart/stm32c0_uart.h | 39 ++++ 24 files changed, 1708 insertions(+), 16 deletions(-) create mode 100644 boards/stm32c031_nucleo/Makefile.inc create mode 100644 boards/stm32c031_nucleo/board.c create mode 100644 boards/stm32c031_nucleo/board.h create mode 100644 boards/stm32c031_nucleo/ivt.c create mode 100644 boards/stm32c031_nucleo/linker.ld create mode 100644 src/clock/stm32c0_rcc.c create mode 100644 src/flash/stm32c0_flash.c create mode 100644 src/gpio/stm32c0_gpio.c create mode 100644 src/spi/stm32c0_spi.c create mode 100644 src/uart/stm32c0_uart.c create mode 100644 tests/gpio/test_stm32c0_gpio.c create mode 100644 wolfHAL/clock/stm32c0_rcc.h create mode 100644 wolfHAL/flash/stm32c0_flash.h create mode 100644 wolfHAL/gpio/stm32c0_gpio.h create mode 100644 wolfHAL/platform/arm/cortex_m0plus.h create mode 100644 wolfHAL/platform/st/stm32c031xx.h create mode 100644 wolfHAL/spi/stm32c0_spi.h create mode 100644 wolfHAL/uart/stm32c0_uart.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 90f8f20..7777469 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill] + board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo] extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"] steps: - uses: actions/checkout@v4 diff --git a/boards/stm32c031_nucleo/Makefile.inc b/boards/stm32c031_nucleo/Makefile.inc new file mode 100644 index 0000000..15866a9 --- /dev/null +++ b/boards/stm32c031_nucleo/Makefile.inc @@ -0,0 +1,37 @@ +_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +PLATFORM = stm32c0 +TESTS ?= clock gpio timer flash + +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-m0plus -mthumb \ + -DPLATFORM_STM32C0 -MMD -MP +LDFLAGS = -mcpu=cortex-m0plus -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/*/gpio.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/clock.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/uart.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/*/spi.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/block.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32c0_*.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c) + +# Peripheral devices +include $(WHAL_DIR)/boards/peripheral/Makefile.inc diff --git a/boards/stm32c031_nucleo/board.c b/boards/stm32c031_nucleo/board.c new file mode 100644 index 0000000..dfbf37e --- /dev/null +++ b/boards/stm32c031_nucleo/board.c @@ -0,0 +1,252 @@ +/* Board configuration for the NUCLEO-C031C6 dev board */ + +#include +#include +#include "board.h" +#include +#include "peripheral.h" + +/* SysTick timing */ +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, /* 1s timeout */ + .GetTick = Board_GetTick, +}; + +/* Clock */ +whal_Clock g_whalClock = { + WHAL_STM32C031_RCC_DEVICE, + + .cfg = &(whal_Stm32c0Rcc_Cfg) { + .hsidiv = WHAL_STM32C0_RCC_HSIDIV_1, /* HSI48 / 1 = 48 MHz */ + }, +}; + +static const whal_Stm32c0Rcc_Clk g_clocks[] = { + {WHAL_STM32C031_GPIOA_CLOCK}, + {WHAL_STM32C031_GPIOB_CLOCK}, + {WHAL_STM32C031_GPIOC_CLOCK}, + {WHAL_STM32C031_USART1_CLOCK}, + {WHAL_STM32C031_SPI1_CLOCK}, +}; +#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0])) + +/* GPIO */ +whal_Gpio g_whalGpio = { + WHAL_STM32C031_GPIO_DEVICE, + + .cfg = &(whal_Stm32c0Gpio_Cfg) { + .pinCfg = (whal_Stm32c0Gpio_PinCfg[PIN_COUNT]) { + [LED_PIN] = { /* LD4 Green LED on PA5 */ + .port = WHAL_STM32C0_GPIO_PORT_A, + .pin = 5, + .mode = WHAL_STM32C0_GPIO_MODE_OUT, + .outType = WHAL_STM32C0_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32C0_GPIO_SPEED_LOW, + .pull = WHAL_STM32C0_GPIO_PULL_NONE, + .altFn = 0, + }, + [UART_TX_PIN] = { /* USART1 TX on PB6, AF1 */ + .port = WHAL_STM32C0_GPIO_PORT_B, + .pin = 6, + .mode = WHAL_STM32C0_GPIO_MODE_ALTFN, + .outType = WHAL_STM32C0_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32C0_GPIO_SPEED_FAST, + .pull = WHAL_STM32C0_GPIO_PULL_UP, + .altFn = 0, + }, + [UART_RX_PIN] = { /* USART1 RX on PB7, AF1 */ + .port = WHAL_STM32C0_GPIO_PORT_B, + .pin = 7, + .mode = WHAL_STM32C0_GPIO_MODE_ALTFN, + .outType = WHAL_STM32C0_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32C0_GPIO_SPEED_FAST, + .pull = WHAL_STM32C0_GPIO_PULL_UP, + .altFn = 0, + }, + [SPI_SCK_PIN] = { /* SPI1 SCK on PA1, AF0 */ + .port = WHAL_STM32C0_GPIO_PORT_A, + .pin = 1, + .mode = WHAL_STM32C0_GPIO_MODE_ALTFN, + .outType = WHAL_STM32C0_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32C0_GPIO_SPEED_FAST, + .pull = WHAL_STM32C0_GPIO_PULL_NONE, + .altFn = 0, + }, + [SPI_MISO_PIN] = { /* SPI1 MISO on PA6, AF0 */ + .port = WHAL_STM32C0_GPIO_PORT_A, + .pin = 6, + .mode = WHAL_STM32C0_GPIO_MODE_ALTFN, + .outType = WHAL_STM32C0_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32C0_GPIO_SPEED_FAST, + .pull = WHAL_STM32C0_GPIO_PULL_NONE, + .altFn = 0, + }, + [SPI_MOSI_PIN] = { /* SPI1 MOSI on PA7, AF0 */ + .port = WHAL_STM32C0_GPIO_PORT_A, + .pin = 7, + .mode = WHAL_STM32C0_GPIO_MODE_ALTFN, + .outType = WHAL_STM32C0_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32C0_GPIO_SPEED_FAST, + .pull = WHAL_STM32C0_GPIO_PULL_NONE, + .altFn = 0, + }, + }, + .pinCount = PIN_COUNT, + }, +}; + +/* Timer */ +whal_Timer g_whalTimer = { + WHAL_CORTEX_M0PLUS_SYSTICK_DEVICE, + + .cfg = &(whal_SysTick_Cfg) { + .cyclesPerTick = 48000000 / 1000, /* 48 MHz / 1 kHz = 1 ms tick */ + .clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK, + .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, + }, +}; + +/* UART */ +whal_Uart g_whalUart = { + WHAL_STM32C031_USART1_DEVICE, + + .cfg = &(whal_Stm32c0Uart_Cfg) { + .timeout = &g_whalTimeout, + .brr = WHAL_STM32C0_UART_BRR(48000000, 115200), + }, +}; + +/* SPI */ +whal_Spi g_whalSpi = { + WHAL_STM32C031_SPI1_DEVICE, + + .cfg = &(whal_Stm32c0Spi_Cfg) { + .pclk = 48000000, + .timeout = &g_whalTimeout, + }, +}; + +/* Flash */ +whal_Flash g_whalFlash = { + WHAL_STM32C031_FLASH_DEVICE, + + .cfg = &(whal_Stm32c0Flash_Cfg) { + .startAddr = 0x08000000, + .size = 0x8000, /* 32 KB */ + .timeout = &g_whalTimeout, + }, +}; + +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_Stm32c0Flash_Ext_SetLatency(&g_whalFlash, WHAL_STM32C0_FLASH_LATENCY_1); + if (err) + return err; + + err = whal_Clock_Init(&g_whalClock); + if (err) + return err; + + /* Enable clocks */ + 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_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_Uart_Deinit(&g_whalUart); + if (err) + return err; + + err = whal_Gpio_Deinit(&g_whalGpio); + if (err) + return err; + + /* Disable clocks */ + 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/stm32c031_nucleo/board.h b/boards/stm32c031_nucleo/board.h new file mode 100644 index 0000000..68d6678 --- /dev/null +++ b/boards/stm32c031_nucleo/board.h @@ -0,0 +1,41 @@ +#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_Flash g_whalFlash; + +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, + 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 0x8000 +#define BOARD_FLASH_TEST_ADDR 0x08007800 +#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/stm32c031_nucleo/ivt.c b/boards/stm32c031_nucleo/ivt.c new file mode 100644 index 0000000..dca832f --- /dev/null +++ b/boards/stm32c031_nucleo/ivt.c @@ -0,0 +1,151 @@ +#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"))); + +/* STM32C031 peripheral interrupts */ +void WWDG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void PVD_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 USB_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel2_3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel4_5_6_7_DMAMUX_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ADC_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 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_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FDCAN_IT0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FDCAN_IT1_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, + /* STM32C031 peripheral interrupts */ + WWDG_IRQHandler, /* 0 */ + PVD_IRQHandler, /* 1 */ + RTC_IRQHandler, /* 2 */ + FLASH_IRQHandler, /* 3 */ + RCC_CRS_IRQHandler, /* 4 */ + EXTI0_1_IRQHandler, /* 5 */ + EXTI2_3_IRQHandler, /* 6 */ + EXTI4_15_IRQHandler, /* 7 */ + USB_IRQHandler, /* 8 */ + DMA1_Channel1_IRQHandler, /* 9 */ + DMA1_Channel2_3_IRQHandler, /* 10 */ + DMA1_Channel4_5_6_7_DMAMUX_IRQHandler, /* 11 */ + ADC_IRQHandler, /* 12 */ + TIM1_BRK_UP_TRG_COM_IRQHandler, /* 13 */ + TIM1_CC_IRQHandler, /* 14 */ + TIM2_IRQHandler, /* 15 */ + TIM3_IRQHandler, /* 16 */ + RESERVED, /* 17 */ + RESERVED, /* 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_IRQHandler, /* 29 */ + FDCAN_IT0_IRQHandler, /* 30 */ + FDCAN_IT1_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/stm32c031_nucleo/linker.ld b/boards/stm32c031_nucleo/linker.ld new file mode 100644 index 0000000..ac6b305 --- /dev/null +++ b/boards/stm32c031_nucleo/linker.ld @@ -0,0 +1,121 @@ +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20003000; /* end of 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 = 32K +RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 12K +} + +/* 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/boards/stm32h563zi_nucleo/board.h b/boards/stm32h563zi_nucleo/board.h index a0e2649..1c59fe8 100644 --- a/boards/stm32h563zi_nucleo/board.h +++ b/boards/stm32h563zi_nucleo/board.h @@ -41,8 +41,10 @@ enum { #define BOARD_LED_PIN 0 /* Flash test address: last sector of bank 2 (safe area away from firmware) */ -#define BOARD_FLASH_TEST_ADDR 0x081FE000 -#define BOARD_FLASH_SECTOR_SZ 0x2000 +#define BOARD_FLASH_START_ADDR 0x08000000 +#define BOARD_FLASH_SIZE 0x200000 +#define BOARD_FLASH_TEST_ADDR 0x081FE000 +#define BOARD_FLASH_SECTOR_SZ 0x2000 /* Ethernet PHY: LAN8742A on MDIO address 0 */ #define BOARD_ETH_PHY_ADDR 0 diff --git a/boards/stm32wb55xx_nucleo/board.h b/boards/stm32wb55xx_nucleo/board.h index a4d59ab..92deefb 100644 --- a/boards/stm32wb55xx_nucleo/board.h +++ b/boards/stm32wb55xx_nucleo/board.h @@ -29,6 +29,10 @@ enum { }; #define BOARD_LED_PIN 0 +#define BOARD_LED_PORT_OFFSET 0x400 /* GPIOB */ +#define BOARD_LED_PIN_NUM 5 +#define BOARD_FLASH_START_ADDR 0x08000000 +#define BOARD_FLASH_SIZE 0x100000 #define BOARD_FLASH_TEST_ADDR 0x08080000 #define BOARD_FLASH_SECTOR_SZ 0x1000 diff --git a/src/clock/stm32c0_rcc.c b/src/clock/stm32c0_rcc.c new file mode 100644 index 0000000..54ae72b --- /dev/null +++ b/src/clock/stm32c0_rcc.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include + +/* + * STM32C0 RCC Register Definitions + * + * The RCC (Reset and Clock Control) peripheral manages: + * - HSI48 oscillator with HSIDIV prescaler + * - System clock source selection (HSISYS, HSE, LSI, LSE) + * - Peripheral clock gating (IOP, AHB, APB buses) + */ + +/* Clock Control Register - oscillator enables and status */ +#define RCC_CR_REG 0x000 +#define RCC_CR_HSION_Pos 8 /* HSI enable */ +#define RCC_CR_HSION_Msk (1UL << RCC_CR_HSION_Pos) + +#define RCC_CR_HSIRDY_Pos 10 /* HSI ready */ +#define RCC_CR_HSIRDY_Msk (1UL << RCC_CR_HSIRDY_Pos) + +#define RCC_CR_HSIDIV_Pos 11 /* HSI divider */ +#define RCC_CR_HSIDIV_Msk (WHAL_BITMASK(3) << RCC_CR_HSIDIV_Pos) + +/* Clock Configuration Register - clock source and prescaler selection */ +#define RCC_CFGR_REG 0x008 +#define RCC_CFGR_SW_Pos 0 /* System clock switch */ +#define RCC_CFGR_SW_Msk (WHAL_BITMASK(3) << RCC_CFGR_SW_Pos) + +#define RCC_CFGR_SWS_Pos 3 /* System clock switch status */ +#define RCC_CFGR_SWS_Msk (WHAL_BITMASK(3) << RCC_CFGR_SWS_Pos) + +/* HSISYS clock source selection value */ +#define RCC_CFGR_SW_HSISYS 0 + +whal_Error whal_Stm32c0Rcc_Init(whal_Clock *clkDev) +{ + whal_Stm32c0Rcc_Cfg *cfg; + size_t rdy; + + if (!clkDev || !clkDev->cfg) { + return WHAL_EINVAL; + } + + cfg = (whal_Stm32c0Rcc_Cfg *)clkDev->cfg; + + /* Set HSIDIV to configured divider */ + whal_Reg_Update(clkDev->regmap.base, RCC_CR_REG, RCC_CR_HSIDIV_Msk, + whal_SetBits(RCC_CR_HSIDIV_Msk, RCC_CR_HSIDIV_Pos, cfg->hsidiv)); + + /* Ensure HSI is enabled */ + whal_Reg_Update(clkDev->regmap.base, RCC_CR_REG, RCC_CR_HSION_Msk, + whal_SetBits(RCC_CR_HSION_Msk, RCC_CR_HSION_Pos, 1)); + + /* Wait for HSI to be ready */ + do { + whal_Reg_Get(clkDev->regmap.base, RCC_CR_REG, + RCC_CR_HSIRDY_Msk, RCC_CR_HSIRDY_Pos, &rdy); + } while (!rdy); + + /* Select HSISYS as system clock source */ + 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_HSISYS)); + + /* Wait for system clock switch status to confirm HSISYS */ + size_t sws; + do { + whal_Reg_Get(clkDev->regmap.base, RCC_CFGR_REG, + RCC_CFGR_SWS_Msk, RCC_CFGR_SWS_Pos, &sws); + } while (sws != RCC_CFGR_SW_HSISYS); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32c0Rcc_Deinit(whal_Clock *clkDev) +{ + if (!clkDev) { + return WHAL_EINVAL; + } + + /* Reset HSIDIV to default (div1 = 48 MHz) */ + whal_Reg_Update(clkDev->regmap.base, RCC_CR_REG, RCC_CR_HSIDIV_Msk, + whal_SetBits(RCC_CR_HSIDIV_Msk, RCC_CR_HSIDIV_Pos, + WHAL_STM32C0_RCC_HSIDIV_1)); + + /* Select HSISYS as system clock source */ + 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_HSISYS)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32c0Rcc_Enable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32c0Rcc_Clk *stClk = (whal_Stm32c0Rcc_Clk *)clk; + + /* Set the peripheral's enable bit in the appropriate RCC enable register */ + whal_Reg_Update(clkDev->regmap.base, stClk->regOffset, stClk->enableMask, + whal_SetBits(stClk->enableMask, stClk->enablePos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32c0Rcc_Disable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32c0Rcc_Clk *stClk = (whal_Stm32c0Rcc_Clk *)clk; + + /* Clear the peripheral's enable bit to gate its clock */ + whal_Reg_Update(clkDev->regmap.base, stClk->regOffset, stClk->enableMask, + whal_SetBits(stClk->enableMask, stClk->enablePos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32c0Rcc_GetRate(whal_Clock *clkDev, size_t *rateOut) +{ + whal_Stm32c0Rcc_Cfg *cfg; + + if (!clkDev || !clkDev->cfg || !rateOut) { + return WHAL_EINVAL; + } + + cfg = (whal_Stm32c0Rcc_Cfg *)clkDev->cfg; + + /* HSI48 base frequency divided by HSIDIV (1 << hsidiv) */ + *rateOut = 48000000 / (1 << cfg->hsidiv); + + return WHAL_SUCCESS; +} + +const whal_ClockDriver whal_Stm32c0Rcc_Driver = { + .Init = whal_Stm32c0Rcc_Init, + .Deinit = whal_Stm32c0Rcc_Deinit, + .Enable = whal_Stm32c0Rcc_Enable, + .Disable = whal_Stm32c0Rcc_Disable, + .GetRate = whal_Stm32c0Rcc_GetRate, +}; diff --git a/src/flash/stm32c0_flash.c b/src/flash/stm32c0_flash.c new file mode 100644 index 0000000..09e4422 --- /dev/null +++ b/src/flash/stm32c0_flash.c @@ -0,0 +1,291 @@ +#include +#include +#include +#include +#include +#include + +/* + * STM32C0 Flash Register Definitions + * + * The flash controller manages embedded flash memory operations including + * programming, erasing, and access control. Flash is organized in 2 KB pages. + */ + +/* Access Control Register - configures latency and caches */ +#define FLASH_ACR_REG 0x00 +#define FLASH_ACR_LATENCY_Pos 0 /* Wait states (0-1) */ +#define FLASH_ACR_LATENCY_Msk (WHAL_BITMASK(3) << FLASH_ACR_LATENCY_Pos) + +/* Key Register - unlock sequence for write operations */ +#define FLASH_KEYR_REG 0x08 +#define FLASH_KEYR_KEY_Msk (~0UL) + +/* Status Register - operation status and error flags */ +#define FLASH_SR_REG 0x10 +#define FLASH_SR_EOP_Pos 0 /* End of operation */ +#define FLASH_SR_EOP_Msk (1UL << FLASH_SR_EOP_Pos) + +#define FLASH_SR_OP_ERR_Pos 1 /* Operation error */ +#define FLASH_SR_OP_ERR_Msk (1UL << FLASH_SR_OP_ERR_Pos) + +#define FLASH_SR_PROG_ERR_Pos 3 /* Programming error */ +#define FLASH_SR_PROG_ERR_Msk (1UL << FLASH_SR_PROG_ERR_Pos) + +#define FLASH_SR_WRP_ERR_Pos 4 /* Write protection error */ +#define FLASH_SR_WRP_ERR_Msk (1UL << FLASH_SR_WRP_ERR_Pos) + +#define FLASH_SR_PGA_ERR_Pos 5 /* Programming alignment error */ +#define FLASH_SR_PGA_ERR_Msk (1UL << FLASH_SR_PGA_ERR_Pos) + +#define FLASH_SR_SIZ_ERR_Pos 6 /* Size error */ +#define FLASH_SR_SIZ_ERR_Msk (1UL << FLASH_SR_SIZ_ERR_Pos) + +#define FLASH_SR_PGS_ERR_Pos 7 /* Programming sequence error */ +#define FLASH_SR_PGS_ERR_Msk (1UL << FLASH_SR_PGS_ERR_Pos) + +#define FLASH_SR_MISS_ERR_Pos 8 /* Fast programming miss error */ +#define FLASH_SR_MISS_ERR_Msk (1UL << FLASH_SR_MISS_ERR_Pos) + +#define FLASH_SR_FAST_ERR_Pos 9 /* Fast programming error */ +#define FLASH_SR_FAST_ERR_Msk (1UL << FLASH_SR_FAST_ERR_Pos) + +#define FLASH_SR_RD_ERR_Pos 14 /* Read protection error */ +#define FLASH_SR_RD_ERR_Msk (1UL << FLASH_SR_RD_ERR_Pos) + +#define FLASH_SR_OPTV_ERR_Pos 15 /* Option validity error */ +#define FLASH_SR_OPTV_ERR_Msk (1UL << FLASH_SR_OPTV_ERR_Pos) + +#define FLASH_SR_BSY_Pos 16 /* Busy flag */ +#define FLASH_SR_BSY_Msk (1UL << FLASH_SR_BSY_Pos) + +#define FLASH_SR_CFGBSY_Pos 18 /* Configuration busy */ +#define FLASH_SR_CFGBSY_Msk (1UL << FLASH_SR_CFGBSY_Pos) + +/* Combined mask for all error flags */ +#define FLASH_SR_ALL_ERR (FLASH_SR_OP_ERR_Msk | FLASH_SR_PROG_ERR_Msk | FLASH_SR_WRP_ERR_Msk | \ + FLASH_SR_PGA_ERR_Msk | FLASH_SR_SIZ_ERR_Msk | FLASH_SR_PGS_ERR_Msk | \ + FLASH_SR_MISS_ERR_Msk | FLASH_SR_FAST_ERR_Msk | FLASH_SR_RD_ERR_Msk | \ + FLASH_SR_OPTV_ERR_Msk) + +/* Control Register - enables operations and selects pages */ +#define FLASH_CR_REG 0x14 +#define FLASH_CR_PG_Pos 0 /* Programming enable */ +#define FLASH_CR_PG_Msk (1UL << FLASH_CR_PG_Pos) + +#define FLASH_CR_PER_Pos 1 /* Page erase enable */ +#define FLASH_CR_PER_Msk (1UL << FLASH_CR_PER_Pos) + +#define FLASH_CR_PNB_Pos 3 /* Page number for erase (7 bits for C0) */ +#define FLASH_CR_PNB_Msk (WHAL_BITMASK(7) << FLASH_CR_PNB_Pos) + +#define FLASH_CR_STRT_Pos 16 /* Start erase operation */ +#define FLASH_CR_STRT_Msk (1UL << FLASH_CR_STRT_Pos) + +#define FLASH_CR_LOCK_Pos 31 /* Lock flash control */ +#define FLASH_CR_LOCK_Msk (1UL << FLASH_CR_LOCK_Pos) + +whal_Error whal_Stm32c0Flash_Init(whal_Flash *flashDev) +{ + (void)flashDev; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32c0Flash_Deinit(whal_Flash *flashDev) +{ + (void)flashDev; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32c0Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len) +{ + const whal_Regmap *regmap; + + (void)addr; + (void)len; + + if (!flashDev) { + return WHAL_EINVAL; + } + + regmap = &flashDev->regmap; + + /* Setting LOCK bit prevents further flash modifications until next unlock */ + whal_Reg_Update(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_Stm32c0Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len) +{ + const whal_Regmap *regmap; + + (void)addr; + (void)len; + + if (!flashDev) { + return WHAL_EINVAL; + } + + regmap = &flashDev->regmap; + + /* + * Unlock sequence: write KEY1 then KEY2 to KEYR register. + * Incorrect sequence or order will trigger a bus error. + */ + whal_Reg_Update(regmap->base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0x45670123); + whal_Reg_Update(regmap->base, FLASH_KEYR_REG, FLASH_KEYR_KEY_Msk, 0xCDEF89AB); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32c0Flash_Read(whal_Flash *flashDev, size_t addr, uint8_t *data, + size_t dataSz) +{ + (void)flashDev; + + /* Flash is memory-mapped, so reading is a simple memory copy */ + uint8_t *flashAddr = (uint8_t *)addr; + for (size_t i = 0; i < dataSz; ++i) { + data[i] = flashAddr[i]; + } + return WHAL_SUCCESS; +} + +/* + * Internal helper for write and erase operations. + * + * For write (write=1): Programs data in 64-bit (8 byte) chunks. + * For erase (write=0): Erases 2 KB pages covering the address range. + */ +static whal_Error whal_Stm32c0Flash_WriteOrErase(whal_Flash *flashDev, size_t addr, const uint8_t *data, + size_t dataSz, uint8_t write) +{ + whal_Stm32c0Flash_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 8-byte alignment (64-bit double-word programming) */ + if (write && ((addr & 0x7) || (dataSz & 0x7))) + return WHAL_EINVAL; + + if (!write && dataSz == 0) + return WHAL_SUCCESS; + + /* Check if flash is busy */ + whal_Reg_Get(regmap->base, FLASH_SR_REG, FLASH_SR_BSY_Msk, FLASH_SR_BSY_Pos, &bsy); + + if (bsy) { + return WHAL_ENOTREADY; + } + + /* Clear all error flags by writing 1 to each */ + whal_Reg_Update(regmap->base, FLASH_SR_REG, FLASH_SR_ALL_ERR, 0xffffffff); + + whal_Error err = WHAL_SUCCESS; + + if (write) { + /* Enable flash programming mode */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PG_Msk, 1); + + /* Program data in 64-bit (8 byte) double-word chunks */ + for (size_t i = 0; i < dataSz; i += 8) { + uint32_t *flashAddr = (uint32_t *)(addr + i); + uint32_t *dataAddr = (uint32_t *)(data + i); + + /* Write both 32-bit words to trigger the 64-bit programming */ + flashAddr[0] = dataAddr[0]; + flashAddr[1] = dataAddr[1]; + + /* Wait for programming to complete */ + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, + FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); + if (err) + goto cleanup; + } + } + else { + /* Calculate page range to erase (2 KB per page) */ + size_t startPage, endPage; + startPage = (addr - cfg->startAddr) >> 11; + endPage = ((addr - cfg->startAddr) + dataSz - 1) >> 11; + + /* Enable page erase mode */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PER_Msk, + whal_SetBits(FLASH_CR_PER_Msk, FLASH_CR_PER_Pos, 1)); + + /* Erase each page in the range */ + for (size_t page = startPage; page <= endPage; ++page) { + /* Select page number */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PNB_Msk, + whal_SetBits(FLASH_CR_PNB_Msk, FLASH_CR_PNB_Pos, page)); + + /* Start erase operation */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_STRT_Msk, + whal_SetBits(FLASH_CR_STRT_Msk, FLASH_CR_STRT_Pos, 1)); + + /* Wait for erase to complete */ + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, + FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); + if (err) + goto cleanup; + } + + /* Disable page erase mode */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PER_Msk, + whal_SetBits(FLASH_CR_PER_Msk, FLASH_CR_PER_Pos, 0)); + } + +cleanup: + /* Clear programming and erase mode bits */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, + FLASH_CR_PG_Msk | FLASH_CR_PER_Msk, 0); + + return err; +} + +whal_Error whal_Stm32c0Flash_Write(whal_Flash *flashDev, size_t addr, const uint8_t *data, + size_t dataSz) +{ + return whal_Stm32c0Flash_WriteOrErase(flashDev, addr, data, dataSz, 1); +} + +whal_Error whal_Stm32c0Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz) +{ + return whal_Stm32c0Flash_WriteOrErase(flashDev, addr, NULL, dataSz, 0); +} + +whal_Error whal_Stm32c0Flash_Ext_SetLatency(whal_Flash *flashDev, enum whal_Stm32c0Flash_Latency latency) +{ + if (!flashDev) { + return WHAL_EINVAL; + } + + const whal_Regmap *reg = &flashDev->regmap; + whal_Reg_Update(reg->base, FLASH_ACR_REG, FLASH_ACR_LATENCY_Msk, latency); + return WHAL_SUCCESS; +} + +const whal_FlashDriver whal_Stm32c0Flash_Driver = { + .Init = whal_Stm32c0Flash_Init, + .Deinit = whal_Stm32c0Flash_Deinit, + .Lock = whal_Stm32c0Flash_Lock, + .Unlock = whal_Stm32c0Flash_Unlock, + .Read = whal_Stm32c0Flash_Read, + .Write = whal_Stm32c0Flash_Write, + .Erase = whal_Stm32c0Flash_Erase, +}; diff --git a/src/flash/stm32wb_flash.c b/src/flash/stm32wb_flash.c index cdc1bde..02c44f0 100644 --- a/src/flash/stm32wb_flash.c +++ b/src/flash/stm32wb_flash.c @@ -179,6 +179,9 @@ static whal_Error whal_Stm32wbFlash_WriteOrErase(whal_Flash *flashDev, size_t ad cfg = flashDev->cfg; regmap = &flashDev->regmap; + if (dataSz == 0) + return WHAL_SUCCESS; + /* Validate address alignment and bounds */ if (addr & 0xf || addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) { return WHAL_EINVAL; @@ -221,7 +224,7 @@ static whal_Error whal_Stm32wbFlash_WriteOrErase(whal_Flash *flashDev, size_t ad /* Calculate page range to erase (4 KB per page) */ size_t startPage, endPage; startPage = (addr - cfg->startAddr) >> 12; - endPage = ((addr - cfg->startAddr) + dataSz) >> 12; + endPage = ((addr - cfg->startAddr) + dataSz - 1) >> 12; /* Enable page erase mode */ whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PER_Msk, diff --git a/src/gpio/stm32c0_gpio.c b/src/gpio/stm32c0_gpio.c new file mode 100644 index 0000000..7ddf812 --- /dev/null +++ b/src/gpio/stm32c0_gpio.c @@ -0,0 +1 @@ +#include "stm32wb_gpio.c" diff --git a/src/spi/stm32c0_spi.c b/src/spi/stm32c0_spi.c new file mode 100644 index 0000000..b28e2b9 --- /dev/null +++ b/src/spi/stm32c0_spi.c @@ -0,0 +1 @@ +#include "stm32wb_spi.c" diff --git a/src/uart/stm32c0_uart.c b/src/uart/stm32c0_uart.c new file mode 100644 index 0000000..feaed0c --- /dev/null +++ b/src/uart/stm32c0_uart.c @@ -0,0 +1 @@ +#include "stm32wb_uart.c" diff --git a/tests/flash/test_flash.c b/tests/flash/test_flash.c index af4ffe8..3f8a4a7 100644 --- a/tests/flash/test_flash.c +++ b/tests/flash/test_flash.c @@ -7,6 +7,10 @@ static whal_Flash *g_testFlashDev; static size_t g_testFlashAddr; static size_t g_testFlashSectorSz; +#ifdef BOARD_FLASH_SIZE +static size_t g_testFlashStartAddr; +static size_t g_testFlashSize; +#endif static void Test_Flash_EraseBlank(void) { @@ -60,6 +64,29 @@ static void Test_Flash_WriteRead(void) g_testFlashSectorSz), WHAL_SUCCESS); } +#ifdef BOARD_FLASH_SIZE +static void Test_Flash_EraseLastSector(void) +{ + size_t lastSectorAddr = g_testFlashStartAddr + g_testFlashSize - g_testFlashSectorSz; + uint8_t readback[8] = {0}; + uint8_t erased[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + WHAL_ASSERT_EQ(whal_Flash_Unlock(g_testFlashDev, lastSectorAddr, + g_testFlashSectorSz), WHAL_SUCCESS); + + WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, lastSectorAddr, + g_testFlashSectorSz), WHAL_SUCCESS); + + WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, lastSectorAddr, + readback, sizeof(readback)), WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(readback, erased, sizeof(erased)); + + WHAL_ASSERT_EQ(whal_Flash_Lock(g_testFlashDev, lastSectorAddr, + g_testFlashSectorSz), WHAL_SUCCESS); +} +#endif + static void run_flash_tests(const char *name) { WHAL_TEST_SUITE_START("flash"); @@ -67,6 +94,9 @@ static void run_flash_tests(const char *name) whal_Test_Printf(" device: %s\n", name); WHAL_TEST(Test_Flash_EraseBlank); WHAL_TEST(Test_Flash_WriteRead); +#ifdef BOARD_FLASH_SIZE + WHAL_TEST(Test_Flash_EraseLastSector); +#endif WHAL_TEST_SUITE_END(); } @@ -75,6 +105,10 @@ void whal_Test_Flash(void) /* Test on-chip flash */ g_testFlashDev = &g_whalFlash; g_testFlashAddr = BOARD_FLASH_TEST_ADDR; +#ifdef BOARD_FLASH_SIZE + g_testFlashStartAddr = BOARD_FLASH_START_ADDR; + g_testFlashSize = BOARD_FLASH_SIZE; +#endif g_testFlashSectorSz = BOARD_FLASH_SECTOR_SZ; run_flash_tests("on-chip"); diff --git a/tests/gpio/test_stm32c0_gpio.c b/tests/gpio/test_stm32c0_gpio.c new file mode 100644 index 0000000..c287cb9 --- /dev/null +++ b/tests/gpio/test_stm32c0_gpio.c @@ -0,0 +1 @@ +#include "test_stm32wb_gpio.c" diff --git a/tests/gpio/test_stm32wb_gpio.c b/tests/gpio/test_stm32wb_gpio.c index a5f7a9f..44c08d1 100644 --- a/tests/gpio/test_stm32wb_gpio.c +++ b/tests/gpio/test_stm32wb_gpio.c @@ -5,21 +5,35 @@ #include "test.h" /* - * GPIO register offsets (GPIOB port base = GPIO base + 0x400) - * LED is on PB5. + * GPIO register offsets. + * LED port and pin come from board.h (BOARD_LED_PORT_OFFSET, BOARD_LED_PIN_NUM). */ -#define GPIOB_BASE_OFFSET 0x400 #define GPIOx_MODE_REG 0x00 #define GPIOx_ODR_REG 0x14 +static void Test_Gpio_NoDuplicatePins(void) +{ + whal_Stm32wbGpio_Cfg *cfg = (whal_Stm32wbGpio_Cfg *)g_whalGpio.cfg; + whal_Stm32wbGpio_PinCfg *pins = cfg->pinCfg; + + for (size_t i = 0; i < cfg->pinCount; i++) { + for (size_t j = i + 1; j < cfg->pinCount; j++) { + if (pins[i].port == pins[j].port && + pins[i].pin == pins[j].pin) { + WHAL_ASSERT_NEQ(pins[i].port, pins[j].port); + } + } + } +} + static void Test_Gpio_ModeRegister(void) { - /* PB5 should be configured as output (mode = 0x01) in bits [11:10] */ - size_t portBase = g_whalGpio.regmap.base + GPIOB_BASE_OFFSET; - size_t mask = (WHAL_BITMASK(2) << 10); + size_t portBase = g_whalGpio.regmap.base + BOARD_LED_PORT_OFFSET; + size_t bitPos = BOARD_LED_PIN_NUM << 1; + size_t mask = (WHAL_BITMASK(2) << bitPos); size_t val = 0; - whal_Reg_Get(portBase, GPIOx_MODE_REG, mask, 10, &val); + whal_Reg_Get(portBase, GPIOx_MODE_REG, mask, bitPos, &val); WHAL_ASSERT_EQ(val, WHAL_STM32WB_GPIO_MODE_OUT); } @@ -27,10 +41,10 @@ static void Test_Gpio_SetHighReg(void) { WHAL_ASSERT_EQ(whal_Gpio_Set(&g_whalGpio, BOARD_LED_PIN, 1), WHAL_SUCCESS); - /* Readback ODR bit 5 */ - size_t portBase = g_whalGpio.regmap.base + GPIOB_BASE_OFFSET; + size_t portBase = g_whalGpio.regmap.base + BOARD_LED_PORT_OFFSET; size_t val = 0; - whal_Reg_Get(portBase, GPIOx_ODR_REG, (1UL << 5), 5, &val); + whal_Reg_Get(portBase, GPIOx_ODR_REG, (1UL << BOARD_LED_PIN_NUM), + BOARD_LED_PIN_NUM, &val); WHAL_ASSERT_EQ(val, 1); } @@ -38,14 +52,16 @@ static void Test_Gpio_SetLowReg(void) { WHAL_ASSERT_EQ(whal_Gpio_Set(&g_whalGpio, BOARD_LED_PIN, 0), WHAL_SUCCESS); - size_t portBase = g_whalGpio.regmap.base + GPIOB_BASE_OFFSET; + size_t portBase = g_whalGpio.regmap.base + BOARD_LED_PORT_OFFSET; size_t val = 0; - whal_Reg_Get(portBase, GPIOx_ODR_REG, (1UL << 5), 5, &val); + whal_Reg_Get(portBase, GPIOx_ODR_REG, (1UL << BOARD_LED_PIN_NUM), + BOARD_LED_PIN_NUM, &val); WHAL_ASSERT_EQ(val, 0); } void whal_Test_Gpio_Platform(void) { + WHAL_TEST(Test_Gpio_NoDuplicatePins); WHAL_TEST(Test_Gpio_ModeRegister); WHAL_TEST(Test_Gpio_SetHighReg); WHAL_TEST(Test_Gpio_SetLowReg); diff --git a/wolfHAL/clock/stm32c0_rcc.h b/wolfHAL/clock/stm32c0_rcc.h new file mode 100644 index 0000000..62473e9 --- /dev/null +++ b/wolfHAL/clock/stm32c0_rcc.h @@ -0,0 +1,127 @@ +#ifndef WHAL_STM32C0_RCC_H +#define WHAL_STM32C0_RCC_H + +#include +#include +#include + +/* + * @file stm32c0_rcc.h + * @brief STM32C0 RCC (Reset and Clock Control) driver configuration. + * + * The STM32C0 RCC peripheral controls: + * - System clock source selection (HSISYS, HSE, LSI, LSE) + * - HSI48 oscillator with configurable HSIDIV prescaler + * - Peripheral clock gating (IOP, AHB, APB buses) + * - Bus clock prescalers + * + * The STM32C0 has no PLL. The primary high-speed clock is HSI48 (48 MHz) + * with a configurable divider (HSIDIV) producing HSISYS. + */ + +/* + * @brief HSI divider selection. + * + * The HSI48 oscillator runs at 48 MHz. HSIDIV divides it to produce + * HSISYS which can be selected as the system clock. + */ +typedef enum { + WHAL_STM32C0_RCC_HSIDIV_1, /* 48 MHz */ + WHAL_STM32C0_RCC_HSIDIV_2, /* 24 MHz */ + WHAL_STM32C0_RCC_HSIDIV_4, /* 12 MHz */ + WHAL_STM32C0_RCC_HSIDIV_8, /* 6 MHz */ + WHAL_STM32C0_RCC_HSIDIV_16, /* 3 MHz */ + WHAL_STM32C0_RCC_HSIDIV_32, /* 1.5 MHz */ + WHAL_STM32C0_RCC_HSIDIV_64, /* 750 kHz */ + WHAL_STM32C0_RCC_HSIDIV_128, /* 375 kHz */ +} whal_Stm32c0Rcc_HsiDiv; + +/* + * @brief Peripheral clock enable descriptor. + * + * Describes the register offset and bit mask needed to enable/disable + * a peripheral's bus clock. Used with whal_Stm32c0Rcc_Enable/Disable. + * + * Example for GPIOA: + * { .regOffset = 0x034, .enableMask = (1 << 0), .enablePos = 0 } + */ +typedef struct whal_Stm32c0Rcc_Clk { + size_t regOffset; /* Offset from RCC base to enable register */ + size_t enableMask; /* Bit mask for the peripheral enable bit */ + size_t enablePos; /* Bit position for the peripheral enable bit */ +} whal_Stm32c0Rcc_Clk; + +/* + * @brief RCC driver configuration. + * + * Contains all parameters needed to configure the system clock. + */ +typedef struct whal_Stm32c0Rcc_Cfg { + whal_Stm32c0Rcc_HsiDiv hsidiv; /* HSI divider for HSISYS frequency */ +} whal_Stm32c0Rcc_Cfg; + +/* + * @brief Driver instance for the STM32C0 RCC clock controller. + */ +extern const whal_ClockDriver whal_Stm32c0Rcc_Driver; + +/* + * @brief Initialize the RCC peripheral. + * + * Configures HSIDIV, enables HSI, and selects HSISYS as SYSCLK. + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Rcc_Init(whal_Clock *clkDev); + +/* + * @brief Deinitialize the RCC peripheral. + * + * Resets HSIDIV to default (div1) and selects HSISYS as SYSCLK. + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Rcc_Deinit(whal_Clock *clkDev); + +/* + * @brief Enable a peripheral clock gate. + * + * @param clkDev Clock device instance. + * @param clk Pointer to a whal_Stm32c0Rcc_Clk descriptor. + * + * @retval WHAL_SUCCESS Clock enabled. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Rcc_Enable(whal_Clock *clkDev, const void *clk); + +/* + * @brief Disable a peripheral clock gate. + * + * @param clkDev Clock device instance. + * @param clk Pointer to a whal_Stm32c0Rcc_Clk descriptor. + * + * @retval WHAL_SUCCESS Clock disabled. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Rcc_Disable(whal_Clock *clkDev, const void *clk); + +/* + * @brief Compute the current system clock rate. + * + * Returns 48 MHz divided by the configured HSIDIV setting. + * + * @param clkDev Clock device instance. + * @param rateOut Output for the computed rate in Hz. + * + * @retval WHAL_SUCCESS Rate computed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Rcc_GetRate(whal_Clock *clkDev, size_t *rateOut); + +#endif /* WHAL_STM32C0_RCC_H */ diff --git a/wolfHAL/flash/stm32c0_flash.h b/wolfHAL/flash/stm32c0_flash.h new file mode 100644 index 0000000..bf195d7 --- /dev/null +++ b/wolfHAL/flash/stm32c0_flash.h @@ -0,0 +1,147 @@ +#ifndef WHAL_STM32C0_FLASH_H +#define WHAL_STM32C0_FLASH_H + +#include +#include + +/* + * @file stm32c0_flash.h + * @brief STM32C0 flash driver configuration and helpers. + * + * The STM32C0 embedded flash provides: + * - Up to 32 KB of flash memory organized in 2 KB pages + * - Double-word (64-bit) programming + * - Page erase and mass erase operations + * - Configurable wait states based on CPU frequency + * + * Flash must be unlocked before write/erase operations and locked + * afterward for protection. Wait states must be configured appropriately + * for the system clock frequency. + */ + +/* + * @brief Flash device configuration. + */ +typedef struct whal_Stm32c0Flash_Cfg { + size_t startAddr; /* Flash base address (typically 0x08000000) */ + size_t size; /* Flash size in bytes */ + whal_Timeout *timeout; +} whal_Stm32c0Flash_Cfg; + +/* + * @brief Flash access latency (wait states). + * + * The number of wait states must be configured based on the CPU frequency. + * - 0 WS: up to 24 MHz + * - 1 WS: up to 48 MHz + */ +typedef enum whal_Stm32c0Flash_Latency { + WHAL_STM32C0_FLASH_LATENCY_0, /* 0 wait states */ + WHAL_STM32C0_FLASH_LATENCY_1, /* 1 wait state */ +} whal_Stm32c0Flash_Latency; + +/* + * @brief Driver instance for STM32C0 flash. + */ +extern const whal_FlashDriver whal_Stm32c0Flash_Driver; + +/* + * @brief Initialize the STM32C0 flash interface. + * + * @param flashDev Flash device instance to initialize. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Init(whal_Flash *flashDev); + +/* + * @brief Deinitialize the STM32C0 flash interface. + * + * @param flashDev Flash device instance to deinitialize. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Deinit(whal_Flash *flashDev); + +/* + * @brief Lock the flash control register. + * + * @param flashDev Flash device instance. + * @param addr Unused. + * @param len Unused. + * + * @retval WHAL_SUCCESS Lock applied. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len); + +/* + * @brief Unlock the flash control register. + * + * @param flashDev Flash device instance. + * @param addr Unused. + * @param len Unused. + * + * @retval WHAL_SUCCESS Unlock applied. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); + +/* + * @brief Read data from flash into a buffer. + * + * @param flashDev Flash device instance. + * @param addr Flash address to read. + * @param data Destination buffer. + * @param dataSz Number of bytes to read. + * + * @retval WHAL_SUCCESS Read completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Read(whal_Flash *flashDev, size_t addr, uint8_t *data, + size_t dataSz); + +/* + * @brief Write a block of data to flash. + * + * Data is programmed in 64-bit (8 byte) double-word chunks. + * + * @param flashDev Flash device instance. + * @param addr Flash address to program. + * @param data Buffer to program. + * @param dataSz Number of bytes to program. + * + * @retval WHAL_SUCCESS Program completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Write(whal_Flash *flashDev, size_t addr, const uint8_t *data, + size_t dataSz); + +/* + * @brief Erase flash pages covering the given range. + * + * Erases 2 KB pages. Address must fall within configured flash bounds. + * + * @param flashDev Flash device instance. + * @param addr Flash address to start erasing. + * @param dataSz Number of bytes to erase. + * + * @retval WHAL_SUCCESS Erase completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Erase(whal_Flash *flashDev, size_t addr, size_t dataSz); + +/* + * @brief Update flash latency wait states. + * + * @param flashDev Flash device instance. + * @param latency Latency setting to apply. + * + * @retval WHAL_SUCCESS Latency updated. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32c0Flash_Ext_SetLatency(whal_Flash *flashDev, enum whal_Stm32c0Flash_Latency latency); + +#endif /* WHAL_STM32C0_FLASH_H */ diff --git a/wolfHAL/gpio/stm32c0_gpio.h b/wolfHAL/gpio/stm32c0_gpio.h new file mode 100644 index 0000000..8ae0981 --- /dev/null +++ b/wolfHAL/gpio/stm32c0_gpio.h @@ -0,0 +1,62 @@ +#ifndef WHAL_STM32C0_GPIO_H +#define WHAL_STM32C0_GPIO_H + +/* + * @file stm32c0_gpio.h + * @brief STM32C0 GPIO driver (alias for STM32WB GPIO). + * + * The STM32C0 GPIO peripheral is register-compatible with the STM32WB GPIO. + * This header re-exports the STM32WB GPIO driver types and symbols under + * STM32C0-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbGpio_Cfg whal_Stm32c0Gpio_Cfg; +typedef whal_Stm32wbGpio_PinCfg whal_Stm32c0Gpio_PinCfg; + +#define whal_Stm32c0Gpio_Driver whal_Stm32wbGpio_Driver +#define whal_Stm32c0Gpio_Init whal_Stm32wbGpio_Init +#define whal_Stm32c0Gpio_Deinit whal_Stm32wbGpio_Deinit +#define whal_Stm32c0Gpio_Get whal_Stm32wbGpio_Get +#define whal_Stm32c0Gpio_Set whal_Stm32wbGpio_Set + +/* + * @brief GPIO mode selection (re-exported from STM32WB). + */ +#define WHAL_STM32C0_GPIO_MODE_IN WHAL_STM32WB_GPIO_MODE_IN +#define WHAL_STM32C0_GPIO_MODE_OUT WHAL_STM32WB_GPIO_MODE_OUT +#define WHAL_STM32C0_GPIO_MODE_ALTFN WHAL_STM32WB_GPIO_MODE_ALTFN +#define WHAL_STM32C0_GPIO_MODE_ANALOG WHAL_STM32WB_GPIO_MODE_ANALOG + +/* + * @brief GPIO output type (re-exported from STM32WB). + */ +#define WHAL_STM32C0_GPIO_OUTTYPE_PUSHPULL WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL +#define WHAL_STM32C0_GPIO_OUTTYPE_OPENDRAIN WHAL_STM32WB_GPIO_OUTTYPE_OPENDRAIN + +/* + * @brief GPIO speed selection (re-exported from STM32WB). + */ +#define WHAL_STM32C0_GPIO_SPEED_LOW WHAL_STM32WB_GPIO_SPEED_LOW +#define WHAL_STM32C0_GPIO_SPEED_MEDIUM WHAL_STM32WB_GPIO_SPEED_MEDIUM +#define WHAL_STM32C0_GPIO_SPEED_FAST WHAL_STM32WB_GPIO_SPEED_FAST +#define WHAL_STM32C0_GPIO_SPEED_HIGH WHAL_STM32WB_GPIO_SPEED_HIGH + +/* + * @brief GPIO pull-up/pull-down selection (re-exported from STM32WB). + */ +#define WHAL_STM32C0_GPIO_PULL_NONE WHAL_STM32WB_GPIO_PULL_NONE +#define WHAL_STM32C0_GPIO_PULL_UP WHAL_STM32WB_GPIO_PULL_UP +#define WHAL_STM32C0_GPIO_PULL_DOWN WHAL_STM32WB_GPIO_PULL_DOWN + +/* + * @brief GPIO port selection (re-exported from STM32WB). + */ +#define WHAL_STM32C0_GPIO_PORT_A WHAL_STM32WB_GPIO_PORT_A +#define WHAL_STM32C0_GPIO_PORT_B WHAL_STM32WB_GPIO_PORT_B +#define WHAL_STM32C0_GPIO_PORT_C WHAL_STM32WB_GPIO_PORT_C +#define WHAL_STM32C0_GPIO_PORT_D WHAL_STM32WB_GPIO_PORT_D +#define WHAL_STM32C0_GPIO_PORT_F WHAL_STM32WB_GPIO_PORT_F + +#endif /* WHAL_STM32C0_GPIO_H */ diff --git a/wolfHAL/platform/arm/cortex_m0plus.h b/wolfHAL/platform/arm/cortex_m0plus.h new file mode 100644 index 0000000..802179f --- /dev/null +++ b/wolfHAL/platform/arm/cortex_m0plus.h @@ -0,0 +1,13 @@ +#ifndef WHAL_CORTEX_M0PLUS_H +#define WHAL_CORTEX_M0PLUS_H + +#include + +#define WHAL_CORTEX_M0PLUS_SYSTICK_DEVICE \ + .regmap = { \ + .base = 0xE000E010, \ + .size = 0x400, \ + }, \ + .driver = &whal_SysTick_Driver + +#endif /* WHAL_CORTEX_M0PLUS_H */ diff --git a/wolfHAL/platform/st/stm32c031xx.h b/wolfHAL/platform/st/stm32c031xx.h new file mode 100644 index 0000000..5843bbb --- /dev/null +++ b/wolfHAL/platform/st/stm32c031xx.h @@ -0,0 +1,185 @@ +#ifndef WHAL_STM32C031XX_H +#define WHAL_STM32C031XX_H + +#include + +#include +#include +#include +#include +#include + +/* + * @file stm32c031xx.h + * @brief Convenience initializers for STM32C031xx device instances. + * + * Base addresses from RM0490 Table 7 (memory map). + * RCC: 0x40021000 + * GPIO: 0x50000000 (port A), 0x400 spacing per port + * USART1: 0x40013800 + * USART2: 0x40004400 + * SPI1: 0x40013000 + * FLASH: 0x40022000 + * SysTick: ARM core peripheral (0xE000E010) + */ + +/* --- Device macros --- */ + +#define WHAL_STM32C031_RCC_DEVICE \ + .regmap = { \ + .base = 0x40021000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32c0Rcc_Driver + +#define WHAL_STM32C031_GPIO_DEVICE \ + .regmap = { \ + .base = 0x50000000, \ + .size = 0x1800, \ + }, \ + .driver = &whal_Stm32c0Gpio_Driver + +#define WHAL_STM32C031_USART1_DEVICE \ + .regmap = { \ + .base = 0x40013800, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32c0Uart_Driver + +#define WHAL_STM32C031_USART2_DEVICE \ + .regmap = { \ + .base = 0x40004400, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32c0Uart_Driver + +#define WHAL_STM32C031_SPI1_DEVICE \ + .regmap = { \ + .base = 0x40013000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32c0Spi_Driver + +#define WHAL_STM32C031_FLASH_DEVICE \ + .regmap = { \ + .base = 0x40022000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32c0Flash_Driver + +/* --- Clock gate macros --- */ + +/* RCC_IOPENR (offset 0x034) - I/O port clock enable */ + +#define WHAL_STM32C031_GPIOA_CLOCK \ + .regOffset = 0x034, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32C031_GPIOB_CLOCK \ + .regOffset = 0x034, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +#define WHAL_STM32C031_GPIOC_CLOCK \ + .regOffset = 0x034, \ + .enableMask = (1UL << 2), \ + .enablePos = 2 + +#define WHAL_STM32C031_GPIOD_CLOCK \ + .regOffset = 0x034, \ + .enableMask = (1UL << 3), \ + .enablePos = 3 + +#define WHAL_STM32C031_GPIOF_CLOCK \ + .regOffset = 0x034, \ + .enableMask = (1UL << 5), \ + .enablePos = 5 + +/* RCC_AHBENR (offset 0x038) - AHB peripheral clock enable */ + +#define WHAL_STM32C031_FLASH_CLOCK \ + .regOffset = 0x038, \ + .enableMask = (1UL << 8), \ + .enablePos = 8 + +/* RCC_APBENR1 (offset 0x03C) - APB peripheral clock enable register 1 */ + +#define WHAL_STM32C031_USART2_CLOCK \ + .regOffset = 0x03C, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +#define WHAL_STM32C031_SPI2_CLOCK \ + .regOffset = 0x03C, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +#define WHAL_STM32C031_I2C1_CLOCK \ + .regOffset = 0x03C, \ + .enableMask = (1UL << 21), \ + .enablePos = 21 + +#define WHAL_STM32C031_I2C2_CLOCK \ + .regOffset = 0x03C, \ + .enableMask = (1UL << 22), \ + .enablePos = 22 + +#define WHAL_STM32C031_TIM2_CLOCK \ + .regOffset = 0x03C, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32C031_TIM3_CLOCK \ + .regOffset = 0x03C, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +#define WHAL_STM32C031_PWR_CLOCK \ + .regOffset = 0x03C, \ + .enableMask = (1UL << 28), \ + .enablePos = 28 + +/* RCC_APBENR2 (offset 0x040) - APB peripheral clock enable register 2 */ + +#define WHAL_STM32C031_SYSCFG_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32C031_TIM1_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 11), \ + .enablePos = 11 + +#define WHAL_STM32C031_SPI1_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 12), \ + .enablePos = 12 + +#define WHAL_STM32C031_USART1_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +#define WHAL_STM32C031_TIM14_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 15), \ + .enablePos = 15 + +#define WHAL_STM32C031_TIM16_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +#define WHAL_STM32C031_TIM17_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 18), \ + .enablePos = 18 + +#define WHAL_STM32C031_ADC_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 20), \ + .enablePos = 20 + +#endif /* WHAL_STM32C031XX_H */ diff --git a/wolfHAL/spi/stm32c0_spi.h b/wolfHAL/spi/stm32c0_spi.h new file mode 100644 index 0000000..f63f1bb --- /dev/null +++ b/wolfHAL/spi/stm32c0_spi.h @@ -0,0 +1,24 @@ +#ifndef WHAL_STM32C0_SPI_H +#define WHAL_STM32C0_SPI_H + +/* + * @file stm32c0_spi.h + * @brief STM32C0 SPI driver (alias for STM32WB SPI). + * + * The STM32C0 SPI peripheral is register-compatible with the STM32WB SPI. + * This header re-exports the STM32WB SPI driver types and symbols under + * STM32C0-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbSpi_Cfg whal_Stm32c0Spi_Cfg; + +#define whal_Stm32c0Spi_Driver whal_Stm32wbSpi_Driver +#define whal_Stm32c0Spi_Init whal_Stm32wbSpi_Init +#define whal_Stm32c0Spi_Deinit whal_Stm32wbSpi_Deinit +#define whal_Stm32c0Spi_StartCom whal_Stm32wbSpi_StartCom +#define whal_Stm32c0Spi_EndCom whal_Stm32wbSpi_EndCom +#define whal_Stm32c0Spi_SendRecv whal_Stm32wbSpi_SendRecv + +#endif /* WHAL_STM32C0_SPI_H */ diff --git a/wolfHAL/uart/stm32c0_uart.h b/wolfHAL/uart/stm32c0_uart.h new file mode 100644 index 0000000..edcc0fc --- /dev/null +++ b/wolfHAL/uart/stm32c0_uart.h @@ -0,0 +1,39 @@ +#ifndef WHAL_STM32C0_UART_H +#define WHAL_STM32C0_UART_H + +/* + * @file stm32c0_uart.h + * @brief STM32C0 UART driver (alias for STM32WB UART). + * + * The STM32C0 USART peripheral is register-compatible with the STM32WB USART. + * This header re-exports the STM32WB UART driver types and symbols under + * STM32C0-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbUart_Cfg whal_Stm32c0Uart_Cfg; + +/* + * @brief Compute UART BRR register value. + * + * @param clk Peripheral clock frequency in Hz. + * @param baud Desired baud rate. + */ +#define WHAL_STM32C0_UART_BRR(clk, baud) WHAL_STM32WB_UART_BRR(clk, baud) + +/* + * @brief Compute LPUART BRR register value. + * + * @param clk Peripheral clock frequency in Hz. + * @param baud Desired baud rate. + */ +#define WHAL_STM32C0_LPUART_BRR(clk, baud) WHAL_STM32WB_LPUART_BRR(clk, baud) + +#define whal_Stm32c0Uart_Driver whal_Stm32wbUart_Driver +#define whal_Stm32c0Uart_Init whal_Stm32wbUart_Init +#define whal_Stm32c0Uart_Deinit whal_Stm32wbUart_Deinit +#define whal_Stm32c0Uart_Send whal_Stm32wbUart_Send +#define whal_Stm32c0Uart_Recv whal_Stm32wbUart_Recv + +#endif /* WHAL_STM32C0_UART_H */