diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 98e857e..fd0feaf 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] + board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo] extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"] steps: - uses: actions/checkout@v4 diff --git a/boards/stm32h563zi_nucleo/Makefile.inc b/boards/stm32h563zi_nucleo/Makefile.inc new file mode 100644 index 0000000..3a18ddc --- /dev/null +++ b/boards/stm32h563zi_nucleo/Makefile.inc @@ -0,0 +1,36 @@ +_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +PLATFORM = stm32h5 +TESTS ?= clock gpio timer flash rng + +GCC = $(GCC_PATH)arm-none-eabi-gcc +LD = $(GCC_PATH)arm-none-eabi-ld +OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy + +CFLAGS += -Wall -Werror $(INCLUDE) -g3 \ + -ffreestanding -nostdlib -mcpu=cortex-m33 \ + -DPLATFORM_STM32H5 -MMD -MP +LDFLAGS = --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/*/stm32h5_*.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c) + +# Peripheral devices +include $(WHAL_DIR)/boards/peripheral/Makefile.inc diff --git a/boards/stm32h563zi_nucleo/board.c b/boards/stm32h563zi_nucleo/board.c new file mode 100644 index 0000000..5171fdf --- /dev/null +++ b/boards/stm32h563zi_nucleo/board.c @@ -0,0 +1,300 @@ +/* Board configuration for the STM32H563ZI Nucleo-144 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_STM32H563_RCC_PLL_DEVICE, + + .cfg = &(whal_Stm32h5Rcc_Cfg) { + .sysClkSrc = WHAL_STM32H5_RCC_SYSCLK_SRC_PLL1, + .sysClkCfg = &(whal_Stm32h5Rcc_PllClkCfg) { + .clkSrc = WHAL_STM32H5_RCC_PLLCLK_SRC_HSI, + /* HSI = 64 MHz (div1), PLL1: (64 / 8) * (62+1) / (2+1) = 504 / 3 = 168 MHz */ + .m = 8, + .n = 62, + .p = 2, + .q = 2, + .r = 2, + }, + }, +}; + +static const whal_Stm32h5Rcc_Clk g_clocks[] = { + {WHAL_STM32H563_GPIOA_CLOCK}, + {WHAL_STM32H563_GPIOB_CLOCK}, + {WHAL_STM32H563_GPIOD_CLOCK}, + {WHAL_STM32H563_GPIOG_CLOCK}, + {WHAL_STM32H563_USART2_CLOCK}, + {WHAL_STM32H563_SPI1_CLOCK}, + {WHAL_STM32H563_RNG_CLOCK}, +}; +#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0])) + +/* GPIO */ +whal_Gpio g_whalGpio = { + WHAL_STM32H563_GPIO_DEVICE, + + .cfg = &(whal_Stm32h5Gpio_Cfg) { + .pinCfg = (whal_Stm32h5Gpio_PinCfg[PIN_COUNT]) { + [LED_PIN] = { /* LD1 Green LED on PB0 */ + .port = WHAL_STM32H5_GPIO_PORT_B, + .pin = 0, + .mode = WHAL_STM32H5_GPIO_MODE_OUT, + .outType = WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32H5_GPIO_SPEED_LOW, + .pull = WHAL_STM32H5_GPIO_PULL_NONE, + .altFn = 0, + }, + [UART_TX_PIN] = { /* USART2 TX on PD5 */ + .port = WHAL_STM32H5_GPIO_PORT_D, + .pin = 5, + .mode = WHAL_STM32H5_GPIO_MODE_ALTFN, + .outType = WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32H5_GPIO_SPEED_FAST, + .pull = WHAL_STM32H5_GPIO_PULL_UP, + .altFn = 7, + }, + [UART_RX_PIN] = { /* USART2 RX on PD6 */ + .port = WHAL_STM32H5_GPIO_PORT_D, + .pin = 6, + .mode = WHAL_STM32H5_GPIO_MODE_ALTFN, + .outType = WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32H5_GPIO_SPEED_FAST, + .pull = WHAL_STM32H5_GPIO_PULL_UP, + .altFn = 7, + }, + [SPI_SCK_PIN] = { /* SPI1 SCK on PA5 */ + .port = WHAL_STM32H5_GPIO_PORT_A, + .pin = 5, + .mode = WHAL_STM32H5_GPIO_MODE_ALTFN, + .outType = WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32H5_GPIO_SPEED_FAST, + .pull = WHAL_STM32H5_GPIO_PULL_NONE, + .altFn = 5, + }, + [SPI_MISO_PIN] = { /* SPI1 MISO on PG9 */ + .port = WHAL_STM32H5_GPIO_PORT_G, + .pin = 9, + .mode = WHAL_STM32H5_GPIO_MODE_ALTFN, + .outType = WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32H5_GPIO_SPEED_FAST, + .pull = WHAL_STM32H5_GPIO_PULL_NONE, + .altFn = 5, + }, + [SPI_MOSI_PIN] = { /* SPI1 MOSI on PB5 */ + .port = WHAL_STM32H5_GPIO_PORT_B, + .pin = 5, + .mode = WHAL_STM32H5_GPIO_MODE_ALTFN, + .outType = WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32H5_GPIO_SPEED_FAST, + .pull = WHAL_STM32H5_GPIO_PULL_NONE, + .altFn = 5, + }, + [SPI_CS_PIN] = { /* SPI CS on PD14 */ + .port = WHAL_STM32H5_GPIO_PORT_D, + .pin = 14, + .mode = WHAL_STM32H5_GPIO_MODE_OUT, + .outType = WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32H5_GPIO_SPEED_FAST, + .pull = WHAL_STM32H5_GPIO_PULL_UP, + }, + }, + .pinCount = PIN_COUNT, + }, +}; + +/* Timer */ +whal_Timer g_whalTimer = { + WHAL_CORTEX_M33_SYSTICK_DEVICE, + + .cfg = &(whal_SysTick_Cfg) { + .cyclesPerTick = 168000000 / 1000, /* 168 MHz / 1 kHz = 1 ms tick */ + .clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK, + .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, + }, +}; + +/* UART */ +whal_Uart g_whalUart = { + WHAL_STM32H563_USART2_DEVICE, + + .cfg = &(whal_Stm32h5Uart_Cfg) { + .timeout = &g_whalTimeout, + .brr = WHAL_STM32H5_UART_BRR(168000000, 115200), + }, +}; + +/* SPI */ +whal_Spi g_whalSpi = { + WHAL_STM32H563_SPI1_DEVICE, + + .cfg = &(whal_Stm32h5Spi_Cfg) { + .pclk = 168000000, + .timeout = &g_whalTimeout, + }, +}; + +/* RNG */ +whal_Rng g_whalRng = { + WHAL_STM32H563_RNG_DEVICE, + + .cfg = &(whal_Stm32h5Rng_Cfg) { + .timeout = &g_whalTimeout, + }, +}; + + +/* Flash */ +whal_Flash g_whalFlash = { + WHAL_STM32H563_FLASH_DEVICE, + + .cfg = &(whal_Stm32h5Flash_Cfg) { + .startAddr = 0x08000000, + .size = 0x200000, /* 2 MB */ + .timeout = &g_whalTimeout, + }, +}; + +void Board_WaitMs(size_t ms) +{ + uint32_t startCount = g_tick; + while ((g_tick - startCount) < ms) + ; +} + +/* + * FLASH_ACR: 0x40022000 + * LATENCY[3:0] = 5 wait states for 168 MHz + * WRHIGHFREQ[5:4] = 2 + */ +#define FLASH_ACR_ADDR 0x40022000 +#define FLASH_ACR_LATENCY_168MHZ ((2 << 4) | 5) + +whal_Error Board_Init(void) +{ + whal_Error err; + + /* Set flash latency before increasing clock speed */ + *(volatile uint32_t *)FLASH_ACR_ADDR = FLASH_ACR_LATENCY_168MHZ; + + 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; + } + + /* Enable HSI48 for RNG kernel clock */ + err = whal_Stm32h5Rcc_Ext_EnableHsi48(&g_whalClock, 1); + 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_Rng_Init(&g_whalRng); + 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_Rng_Deinit(&g_whalRng); + 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/stm32h563zi_nucleo/board.h b/boards/stm32h563zi_nucleo/board.h new file mode 100644 index 0000000..013fd16 --- /dev/null +++ b/boards/stm32h563zi_nucleo/board.h @@ -0,0 +1,40 @@ +#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_Rng g_whalRng; +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, + SPI_CS_PIN, + PIN_COUNT, +}; + +#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 + +whal_Error Board_Init(void); +whal_Error Board_Deinit(void); +void Board_WaitMs(size_t ms); + +#endif /* BOARD_H */ diff --git a/boards/stm32h563zi_nucleo/ivt.c b/boards/stm32h563zi_nucleo/ivt.c new file mode 100644 index 0000000..618809e --- /dev/null +++ b/boards/stm32h563zi_nucleo/ivt.c @@ -0,0 +1,340 @@ +#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 MemManage_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void BusFault_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UsageFault_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SecureFault_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SVC_Handler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DebugMon_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"))); + +/* STM32H563 peripheral interrupts */ +void WWDG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void PVD_AVD_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RTC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RTC_S_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TAMP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RAMCFG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FLASH_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FLASH_S_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GTZC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RCC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RCC_S_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI8_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI9_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI10_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI11_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI12_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI13_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI14_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI15_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA1_Channel7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void IWDG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ADC1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DAC1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FDCAN1_IT0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FDCAN1_IT1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_BRK_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_UP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_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 TIM4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C1_EV_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C1_ER_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C2_EV_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C2_ER_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 SPI3_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_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UART4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UART5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LPUART1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LPTIM1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM8_BRK_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM8_UP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM8_TRG_COM_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM8_CC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ADC2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LPTIM2_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 USB_DRD_FS_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void CRS_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UCPD1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FMC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void OCTOSPI1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SDMMC1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C3_EV_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C3_ER_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SPI4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SPI5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SPI6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART10_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART11_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SAI1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SAI2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void GPDMA2_Channel7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UART7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UART8_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UART9_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UART12_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FDCAN2_IT0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FDCAN2_IT1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DTS_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ETH_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ETH_WKUP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RNG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void HASH_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FPU_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ICACHE_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DCACHE1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C4_EV_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void I2C4_ER_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LPTIM3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LPTIM4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LPTIM5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LPTIM6_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, + MemManage_Handler, + BusFault_Handler, + UsageFault_Handler, + SecureFault_Handler, + RESERVED, + RESERVED, + RESERVED, + SVC_Handler, + DebugMon_Handler, + RESERVED, + PendSV_Handler, + SysTick_Handler, + /* STM32H563 peripheral interrupts */ + WWDG_IRQHandler, /* 0 */ + PVD_AVD_IRQHandler, /* 1 */ + RTC_IRQHandler, /* 2 */ + RTC_S_IRQHandler, /* 3 */ + TAMP_IRQHandler, /* 4 */ + RAMCFG_IRQHandler, /* 5 */ + FLASH_IRQHandler, /* 6 */ + FLASH_S_IRQHandler, /* 7 */ + GTZC_IRQHandler, /* 8 */ + RCC_IRQHandler, /* 9 */ + RCC_S_IRQHandler, /* 10 */ + EXTI0_IRQHandler, /* 11 */ + EXTI1_IRQHandler, /* 12 */ + EXTI2_IRQHandler, /* 13 */ + EXTI3_IRQHandler, /* 14 */ + EXTI4_IRQHandler, /* 15 */ + EXTI5_IRQHandler, /* 16 */ + EXTI6_IRQHandler, /* 17 */ + EXTI7_IRQHandler, /* 18 */ + EXTI8_IRQHandler, /* 19 */ + EXTI9_IRQHandler, /* 20 */ + EXTI10_IRQHandler, /* 21 */ + EXTI11_IRQHandler, /* 22 */ + EXTI12_IRQHandler, /* 23 */ + EXTI13_IRQHandler, /* 24 */ + EXTI14_IRQHandler, /* 25 */ + EXTI15_IRQHandler, /* 26 */ + GPDMA1_Channel0_IRQHandler, /* 27 */ + GPDMA1_Channel1_IRQHandler, /* 28 */ + GPDMA1_Channel2_IRQHandler, /* 29 */ + GPDMA1_Channel3_IRQHandler, /* 30 */ + GPDMA1_Channel4_IRQHandler, /* 31 */ + GPDMA1_Channel5_IRQHandler, /* 32 */ + GPDMA1_Channel6_IRQHandler, /* 33 */ + GPDMA1_Channel7_IRQHandler, /* 34 */ + IWDG_IRQHandler, /* 35 */ + RESERVED, /* 36 */ + ADC1_IRQHandler, /* 37 */ + DAC1_IRQHandler, /* 38 */ + FDCAN1_IT0_IRQHandler, /* 39 */ + FDCAN1_IT1_IRQHandler, /* 40 */ + TIM1_BRK_IRQHandler, /* 41 */ + TIM1_UP_IRQHandler, /* 42 */ + TIM1_TRG_COM_IRQHandler, /* 43 */ + TIM1_CC_IRQHandler, /* 44 */ + TIM2_IRQHandler, /* 45 */ + TIM3_IRQHandler, /* 46 */ + TIM4_IRQHandler, /* 47 */ + TIM5_IRQHandler, /* 48 */ + TIM6_IRQHandler, /* 49 */ + TIM7_IRQHandler, /* 50 */ + I2C1_EV_IRQHandler, /* 51 */ + I2C1_ER_IRQHandler, /* 52 */ + I2C2_EV_IRQHandler, /* 53 */ + I2C2_ER_IRQHandler, /* 54 */ + SPI1_IRQHandler, /* 55 */ + SPI2_IRQHandler, /* 56 */ + SPI3_IRQHandler, /* 57 */ + USART1_IRQHandler, /* 58 */ + USART2_IRQHandler, /* 59 */ + USART3_IRQHandler, /* 60 */ + UART4_IRQHandler, /* 61 */ + UART5_IRQHandler, /* 62 */ + LPUART1_IRQHandler, /* 63 */ + LPTIM1_IRQHandler, /* 64 */ + TIM8_BRK_IRQHandler, /* 65 */ + TIM8_UP_IRQHandler, /* 66 */ + TIM8_TRG_COM_IRQHandler, /* 67 */ + TIM8_CC_IRQHandler, /* 68 */ + ADC2_IRQHandler, /* 69 */ + LPTIM2_IRQHandler, /* 70 */ + TIM15_IRQHandler, /* 71 */ + TIM16_IRQHandler, /* 72 */ + TIM17_IRQHandler, /* 73 */ + USB_DRD_FS_IRQHandler, /* 74 */ + CRS_IRQHandler, /* 75 */ + UCPD1_IRQHandler, /* 76 */ + FMC_IRQHandler, /* 77 */ + OCTOSPI1_IRQHandler, /* 78 */ + SDMMC1_IRQHandler, /* 79 */ + I2C3_EV_IRQHandler, /* 80 */ + I2C3_ER_IRQHandler, /* 81 */ + SPI4_IRQHandler, /* 82 */ + SPI5_IRQHandler, /* 83 */ + SPI6_IRQHandler, /* 84 */ + USART6_IRQHandler, /* 85 */ + USART10_IRQHandler, /* 86 */ + USART11_IRQHandler, /* 87 */ + SAI1_IRQHandler, /* 88 */ + SAI2_IRQHandler, /* 89 */ + GPDMA2_Channel0_IRQHandler, /* 90 */ + GPDMA2_Channel1_IRQHandler, /* 91 */ + GPDMA2_Channel2_IRQHandler, /* 92 */ + GPDMA2_Channel3_IRQHandler, /* 93 */ + GPDMA2_Channel4_IRQHandler, /* 94 */ + GPDMA2_Channel5_IRQHandler, /* 95 */ + GPDMA2_Channel6_IRQHandler, /* 96 */ + GPDMA2_Channel7_IRQHandler, /* 97 */ + UART7_IRQHandler, /* 98 */ + UART8_IRQHandler, /* 99 */ + UART9_IRQHandler, /* 100 */ + UART12_IRQHandler, /* 101 */ + RESERVED, /* 102 */ + FDCAN2_IT0_IRQHandler, /* 103 */ + FDCAN2_IT1_IRQHandler, /* 104 */ + RESERVED, /* 105 */ + RESERVED, /* 106 */ + DTS_IRQHandler, /* 107 */ + RESERVED, /* 108 */ + RESERVED, /* 109 */ + RESERVED, /* 110 */ + ETH_IRQHandler, /* 111 */ + ETH_WKUP_IRQHandler, /* 112 */ + RESERVED, /* 113 */ + RESERVED, /* 114 */ + RNG_IRQHandler, /* 115 */ + HASH_IRQHandler, /* 116 */ + RESERVED, /* 117 */ + FPU_IRQHandler, /* 118 */ + ICACHE_IRQHandler, /* 119 */ + DCACHE1_IRQHandler, /* 120 */ + RESERVED, /* 121 */ + RESERVED, /* 122 */ + I2C4_EV_IRQHandler, /* 123 */ + I2C4_ER_IRQHandler, /* 124 */ + LPTIM3_IRQHandler, /* 125 */ + LPTIM4_IRQHandler, /* 126 */ + LPTIM5_IRQHandler, /* 127 */ + LPTIM6_IRQHandler, /* 128 */ +}; + +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/stm32h563zi_nucleo/linker.ld b/boards/stm32h563zi_nucleo/linker.ld new file mode 100644 index 0000000..6417528 --- /dev/null +++ b/boards/stm32h563zi_nucleo/linker.ld @@ -0,0 +1,121 @@ +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x200A0000; /* 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 = 2048K +RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 640K +} + +/* 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/docs/writing_a_driver.md b/docs/writing_a_driver.md index 4910924..7f1ff3f 100644 --- a/docs/writing_a_driver.md +++ b/docs/writing_a_driver.md @@ -204,6 +204,66 @@ clock sources, each with its own initialization logic, you can provide a separate driver for each source. This way users only link the code they actually need, and unused configurations are not compiled into the final binary. +### Reusing a Driver Across Platforms + +Many MCU families share identical peripheral IP blocks. For example, the +STM32WB and STM32H5 have register-compatible GPIO and UART peripherals. +Rather than duplicating driver code, create thin alias files for the new +platform that re-export the existing driver under platform-specific names. + +#### Header + +The alias header `typedef`s the config structs and `#define`s the driver +instance, functions, and any enum constants: + +```c +#ifndef WHAL_STM32H5_GPIO_H +#define WHAL_STM32H5_GPIO_H + +#include + +typedef whal_Stm32wbGpio_Cfg whal_Stm32h5Gpio_Cfg; +typedef whal_Stm32wbGpio_PinCfg whal_Stm32h5Gpio_PinCfg; + +#define whal_Stm32h5Gpio_Driver whal_Stm32wbGpio_Driver +#define whal_Stm32h5Gpio_Init whal_Stm32wbGpio_Init +#define whal_Stm32h5Gpio_Deinit whal_Stm32wbGpio_Deinit +#define whal_Stm32h5Gpio_Get whal_Stm32wbGpio_Get +#define whal_Stm32h5Gpio_Set whal_Stm32wbGpio_Set + +/* Re-export enum constants under the new platform name */ +#define WHAL_STM32H5_GPIO_MODE_OUT WHAL_STM32WB_GPIO_MODE_OUT +/* ... */ + +#endif +``` + +Use `typedef` for types (gives proper type-checking and debugger visibility) +and `#define` for the driver instance and functions (which are values, not +types). + +#### Source + +The source file includes the original implementation directly: + +```c +#include "stm32wb_gpio.c" +``` + +This works because `#include` is textual insertion — the compiler does not +distinguish `.h` from `.c`. The new platform's `Makefile.inc` compiles this +file and does **not** compile the original. The original platform's +`Makefile.inc` still compiles its own file directly. Both must never appear in +the same build. + +#### When to alias vs. write a new driver + +Alias when the register layout is identical — same offsets, same bit positions, +same behavior. If even one register differs (different bit position, extra +field, different reset value that affects behavior), write a new driver. A +partial alias that papers over register differences with workarounds is worse +than a clean separate implementation. + ### Platform Device Macro Add a device macro to your platform header diff --git a/src/clock/stm32h5_rcc.c b/src/clock/stm32h5_rcc.c new file mode 100644 index 0000000..4a9c94d --- /dev/null +++ b/src/clock/stm32h5_rcc.c @@ -0,0 +1,427 @@ +#include +#include +#include +#include +#include + +/* + * STM32H5 RCC Register Definitions + * + * The RCC peripheral manages: + * - Clock source selection and PLL1/PLL2/PLL3 configuration + * - System clock (SYSCLK) routing + * - Bus clock prescalers (AHB, APB1, APB2, APB3) + * - Peripheral clock gating + * + * RCC base address: 0x44020C00 + */ + +/* Clock Control Register */ +#define RCC_CR_REG 0x000 +#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_HSIDIV_Pos 3 +#define RCC_CR_HSIDIV_Msk (WHAL_BITMASK(2) << RCC_CR_HSIDIV_Pos) + +#define RCC_CR_HSIDIVF_Pos 5 +#define RCC_CR_HSIDIVF_Msk (1UL << RCC_CR_HSIDIVF_Pos) + +#define RCC_CR_CSION_Pos 8 +#define RCC_CR_CSION_Msk (1UL << RCC_CR_CSION_Pos) + +#define RCC_CR_CSIRDY_Pos 9 +#define RCC_CR_CSIRDY_Msk (1UL << RCC_CR_CSIRDY_Pos) + +#define RCC_CR_HSI48ON_Pos 12 +#define RCC_CR_HSI48ON_Msk (1UL << RCC_CR_HSI48ON_Pos) + +#define RCC_CR_HSI48RDY_Pos 13 +#define RCC_CR_HSI48RDY_Msk (1UL << RCC_CR_HSI48RDY_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_PLL1ON_Pos 24 +#define RCC_CR_PLL1ON_Msk (1UL << RCC_CR_PLL1ON_Pos) + +#define RCC_CR_PLL1RDY_Pos 25 +#define RCC_CR_PLL1RDY_Msk (1UL << RCC_CR_PLL1RDY_Pos) + +/* Clock Configuration Register 1 */ +#define RCC_CFGR1_REG 0x01C +#define RCC_CFGR1_SW_Pos 0 +#define RCC_CFGR1_SW_Msk (WHAL_BITMASK(2) << RCC_CFGR1_SW_Pos) + +#define RCC_CFGR1_SWS_Pos 3 +#define RCC_CFGR1_SWS_Msk (WHAL_BITMASK(2) << RCC_CFGR1_SWS_Pos) + +/* PLL1 Clock Source Selection Register */ +#define RCC_PLL1CFGR_REG 0x028 +#define RCC_PLL1CFGR_PLL1SRC_Pos 0 +#define RCC_PLL1CFGR_PLL1SRC_Msk (WHAL_BITMASK(2) << RCC_PLL1CFGR_PLL1SRC_Pos) + +#define RCC_PLL1CFGR_PLL1RGE_Pos 2 +#define RCC_PLL1CFGR_PLL1RGE_Msk (WHAL_BITMASK(2) << RCC_PLL1CFGR_PLL1RGE_Pos) + +#define RCC_PLL1CFGR_PLL1VCOSEL_Pos 5 +#define RCC_PLL1CFGR_PLL1VCOSEL_Msk (1UL << RCC_PLL1CFGR_PLL1VCOSEL_Pos) + +#define RCC_PLL1CFGR_PLL1M_Pos 8 +#define RCC_PLL1CFGR_PLL1M_Msk (WHAL_BITMASK(6) << RCC_PLL1CFGR_PLL1M_Pos) + +#define RCC_PLL1CFGR_PLL1PEN_Pos 16 +#define RCC_PLL1CFGR_PLL1PEN_Msk (1UL << RCC_PLL1CFGR_PLL1PEN_Pos) + +#define RCC_PLL1CFGR_PLL1QEN_Pos 17 +#define RCC_PLL1CFGR_PLL1QEN_Msk (1UL << RCC_PLL1CFGR_PLL1QEN_Pos) + +#define RCC_PLL1CFGR_PLL1REN_Pos 18 +#define RCC_PLL1CFGR_PLL1REN_Msk (1UL << RCC_PLL1CFGR_PLL1REN_Pos) + +/* PLL1 Dividers Register */ +#define RCC_PLL1DIVR_REG 0x034 +#define RCC_PLL1DIVR_PLL1N_Pos 0 +#define RCC_PLL1DIVR_PLL1N_Msk (WHAL_BITMASK(9) << RCC_PLL1DIVR_PLL1N_Pos) + +#define RCC_PLL1DIVR_PLL1P_Pos 9 +#define RCC_PLL1DIVR_PLL1P_Msk (WHAL_BITMASK(7) << RCC_PLL1DIVR_PLL1P_Pos) + +#define RCC_PLL1DIVR_PLL1Q_Pos 16 +#define RCC_PLL1DIVR_PLL1Q_Msk (WHAL_BITMASK(7) << RCC_PLL1DIVR_PLL1Q_Pos) + +#define RCC_PLL1DIVR_PLL1R_Pos 24 +#define RCC_PLL1DIVR_PLL1R_Msk (WHAL_BITMASK(7) << RCC_PLL1DIVR_PLL1R_Pos) + +/* HSI base frequency */ +#define HSI_FREQ 64000000UL + +/* + * Compute the input reference frequency for PLL source selection. + * Returns the HSI frequency accounting for the divider if HSI is selected. + */ +static size_t Stm32h5Rcc_GetPllInputFreq(size_t rccBase, + whal_Stm32h5Rcc_PllClockSrc src) +{ + size_t hsidiv; + + switch (src) { + case WHAL_STM32H5_RCC_PLLCLK_SRC_HSI: + whal_Reg_Get(rccBase, RCC_CR_REG, RCC_CR_HSIDIV_Msk, + RCC_CR_HSIDIV_Pos, &hsidiv); + return HSI_FREQ >> hsidiv; + case WHAL_STM32H5_RCC_PLLCLK_SRC_CSI: + return 4000000; + case WHAL_STM32H5_RCC_PLLCLK_SRC_HSE: + return 8000000; /* TODO: Make configurable per board */ + default: + return 0; + } +} + +whal_Error whal_Stm32h5RccPll_Init(whal_Clock *clkDev) +{ + whal_Stm32h5Rcc_Cfg *cfg; + whal_Stm32h5Rcc_PllClkCfg *pllCfg; + size_t base; + + if (!clkDev || !clkDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32h5Rcc_Cfg *)clkDev->cfg; + pllCfg = (whal_Stm32h5Rcc_PllClkCfg *)cfg->sysClkCfg; + base = clkDev->regmap.base; + + /* Set HSI to div1 (64 MHz) if selected as PLL source */ + if (pllCfg->clkSrc == WHAL_STM32H5_RCC_PLLCLK_SRC_HSI) { + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSIDIV_Msk, + whal_SetBits(RCC_CR_HSIDIV_Msk, RCC_CR_HSIDIV_Pos, 0)); + /* Wait for divider to stabilize */ + while (1) { + size_t divf; + whal_Reg_Get(base, RCC_CR_REG, RCC_CR_HSIDIVF_Msk, + RCC_CR_HSIDIVF_Pos, &divf); + if (divf) + break; + } + } + + /* Enable HSE if selected as PLL source */ + if (pllCfg->clkSrc == WHAL_STM32H5_RCC_PLLCLK_SRC_HSE) { + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSEON_Msk, + whal_SetBits(RCC_CR_HSEON_Msk, RCC_CR_HSEON_Pos, 1)); + while (1) { + size_t rdy; + whal_Reg_Get(base, RCC_CR_REG, RCC_CR_HSERDY_Msk, + RCC_CR_HSERDY_Pos, &rdy); + if (rdy) + break; + } + } + + /* Ensure PLL1 is off before configuring */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLL1ON_Msk, + whal_SetBits(RCC_CR_PLL1ON_Msk, RCC_CR_PLL1ON_Pos, 0)); + + /* Configure PLL1 source and prescaler */ + whal_Reg_Update(base, RCC_PLL1CFGR_REG, + RCC_PLL1CFGR_PLL1SRC_Msk | RCC_PLL1CFGR_PLL1M_Msk | + RCC_PLL1CFGR_PLL1PEN_Msk | RCC_PLL1CFGR_PLL1QEN_Msk | + RCC_PLL1CFGR_PLL1REN_Msk, + whal_SetBits(RCC_PLL1CFGR_PLL1SRC_Msk, RCC_PLL1CFGR_PLL1SRC_Pos, pllCfg->clkSrc) | + whal_SetBits(RCC_PLL1CFGR_PLL1M_Msk, RCC_PLL1CFGR_PLL1M_Pos, pllCfg->m) | + whal_SetBits(RCC_PLL1CFGR_PLL1PEN_Msk, RCC_PLL1CFGR_PLL1PEN_Pos, 1) | + whal_SetBits(RCC_PLL1CFGR_PLL1QEN_Msk, RCC_PLL1CFGR_PLL1QEN_Pos, 1) | + whal_SetBits(RCC_PLL1CFGR_PLL1REN_Msk, RCC_PLL1CFGR_PLL1REN_Pos, 1)); + + /* Configure PLL1 multiplier and dividers */ + whal_Reg_Update(base, RCC_PLL1DIVR_REG, + RCC_PLL1DIVR_PLL1N_Msk | RCC_PLL1DIVR_PLL1P_Msk | + RCC_PLL1DIVR_PLL1Q_Msk | RCC_PLL1DIVR_PLL1R_Msk, + whal_SetBits(RCC_PLL1DIVR_PLL1N_Msk, RCC_PLL1DIVR_PLL1N_Pos, pllCfg->n) | + whal_SetBits(RCC_PLL1DIVR_PLL1P_Msk, RCC_PLL1DIVR_PLL1P_Pos, pllCfg->p) | + whal_SetBits(RCC_PLL1DIVR_PLL1Q_Msk, RCC_PLL1DIVR_PLL1Q_Pos, pllCfg->q) | + whal_SetBits(RCC_PLL1DIVR_PLL1R_Msk, RCC_PLL1DIVR_PLL1R_Pos, pllCfg->r)); + + /* Enable PLL1 */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLL1ON_Msk, + whal_SetBits(RCC_CR_PLL1ON_Msk, RCC_CR_PLL1ON_Pos, 1)); + + /* Wait for PLL1 lock */ + while (1) { + size_t rdy; + whal_Reg_Get(base, RCC_CR_REG, RCC_CR_PLL1RDY_Msk, + RCC_CR_PLL1RDY_Pos, &rdy); + if (rdy) + break; + } + + /* Switch system clock to PLL1 */ + whal_Reg_Update(base, RCC_CFGR1_REG, RCC_CFGR1_SW_Msk, + whal_SetBits(RCC_CFGR1_SW_Msk, RCC_CFGR1_SW_Pos, + WHAL_STM32H5_RCC_SYSCLK_SRC_PLL1)); + + /* Wait for switch to complete */ + while (1) { + size_t sws; + whal_Reg_Get(base, RCC_CFGR1_REG, RCC_CFGR1_SWS_Msk, + RCC_CFGR1_SWS_Pos, &sws); + if (sws == WHAL_STM32H5_RCC_SYSCLK_SRC_PLL1) + break; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5RccPll_Deinit(whal_Clock *clkDev) +{ + size_t base; + + if (!clkDev) + return WHAL_EINVAL; + + base = clkDev->regmap.base; + + /* Switch back to HSI before disabling PLL1 */ + whal_Reg_Update(base, RCC_CFGR1_REG, RCC_CFGR1_SW_Msk, + whal_SetBits(RCC_CFGR1_SW_Msk, RCC_CFGR1_SW_Pos, + WHAL_STM32H5_RCC_SYSCLK_SRC_HSI)); + + /* Wait for switch to complete */ + while (1) { + size_t sws; + whal_Reg_Get(base, RCC_CFGR1_REG, RCC_CFGR1_SWS_Msk, + RCC_CFGR1_SWS_Pos, &sws); + if (sws == WHAL_STM32H5_RCC_SYSCLK_SRC_HSI) + break; + } + + /* Disable PLL1 */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLL1ON_Msk, + whal_SetBits(RCC_CR_PLL1ON_Msk, RCC_CR_PLL1ON_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5RccHsi_Init(whal_Clock *clkDev) +{ + whal_Stm32h5Rcc_Cfg *cfg; + whal_Stm32h5Rcc_HsiClkCfg *hsiCfg; + size_t base; + + if (!clkDev || !clkDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32h5Rcc_Cfg *)clkDev->cfg; + hsiCfg = (whal_Stm32h5Rcc_HsiClkCfg *)cfg->sysClkCfg; + base = clkDev->regmap.base; + + /* Enable HSI */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSION_Msk, + whal_SetBits(RCC_CR_HSION_Msk, RCC_CR_HSION_Pos, 1)); + + /* Set HSI divider */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSIDIV_Msk, + whal_SetBits(RCC_CR_HSIDIV_Msk, RCC_CR_HSIDIV_Pos, hsiCfg->div)); + + /* Wait for HSI divider to stabilize */ + while (1) { + size_t divf; + whal_Reg_Get(base, RCC_CR_REG, RCC_CR_HSIDIVF_Msk, + RCC_CR_HSIDIVF_Pos, &divf); + if (divf) + break; + } + + /* Select HSI as system clock */ + whal_Reg_Update(base, RCC_CFGR1_REG, RCC_CFGR1_SW_Msk, + whal_SetBits(RCC_CFGR1_SW_Msk, RCC_CFGR1_SW_Pos, + WHAL_STM32H5_RCC_SYSCLK_SRC_HSI)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5RccHsi_Deinit(whal_Clock *clkDev) +{ + size_t base; + + if (!clkDev) + return WHAL_EINVAL; + + base = clkDev->regmap.base; + + /* Reset HSI divider to default (div1 = 64 MHz) */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSIDIV_Msk, + whal_SetBits(RCC_CR_HSIDIV_Msk, RCC_CR_HSIDIV_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Rcc_Enable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32h5Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32h5Rcc_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_Stm32h5Rcc_Disable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32h5Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32h5Rcc_Clk *)clk; + + whal_Reg_Update(clkDev->regmap.base, stClk->regOffset, stClk->enableMask, + whal_SetBits(stClk->enableMask, stClk->enablePos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5RccPll_GetRate(whal_Clock *clkDev, size_t *rateOut) +{ + whal_Stm32h5Rcc_Cfg *cfg; + whal_Stm32h5Rcc_PllClkCfg *pllCfg; + size_t srcFreq; + size_t pllm; + size_t plln; + size_t pllp; + + if (!clkDev || !clkDev->cfg || !rateOut) + return WHAL_EINVAL; + + cfg = (whal_Stm32h5Rcc_Cfg *)clkDev->cfg; + pllCfg = (whal_Stm32h5Rcc_PllClkCfg *)cfg->sysClkCfg; + + srcFreq = Stm32h5Rcc_GetPllInputFreq(clkDev->regmap.base, pllCfg->clkSrc); + if (srcFreq == 0) + return WHAL_EINVAL; + + /* + * PLL1 output (pll1_p_ck): + * f_vco = (f_src / m) * (n + 1) + * f_pllp = f_vco / (p + 1) + * + * PLL1M: register value is the divisor directly (1-63, 0=disabled) + * PLL1N: register value + 1 is the multiplier (3=4x, 4=5x, ...) + * PLL1P: register value + 1 is the divisor (1=/2, 2=/3, ...) + */ + pllm = pllCfg->m; + plln = pllCfg->n + 1; + pllp = pllCfg->p + 1; + + *rateOut = ((srcFreq / pllm) * plln) / pllp; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5RccHsi_GetRate(whal_Clock *clkDev, size_t *rateOut) +{ + size_t hsidiv; + + if (!clkDev || !rateOut) + return WHAL_EINVAL; + + whal_Reg_Get(clkDev->regmap.base, RCC_CR_REG, RCC_CR_HSIDIV_Msk, + RCC_CR_HSIDIV_Pos, &hsidiv); + + /* HSI divider: 0=div1(64MHz), 1=div2(32MHz), 2=div4(16MHz), 3=div8(8MHz) */ + *rateOut = HSI_FREQ >> hsidiv; + return WHAL_SUCCESS; +} + +const whal_ClockDriver whal_Stm32h5RccPll_Driver = { + .Init = whal_Stm32h5RccPll_Init, + .Deinit = whal_Stm32h5RccPll_Deinit, + .Enable = whal_Stm32h5Rcc_Enable, + .Disable = whal_Stm32h5Rcc_Disable, + .GetRate = whal_Stm32h5RccPll_GetRate, +}; + +const whal_ClockDriver whal_Stm32h5RccHsi_Driver = { + .Init = whal_Stm32h5RccHsi_Init, + .Deinit = whal_Stm32h5RccHsi_Deinit, + .Enable = whal_Stm32h5Rcc_Enable, + .Disable = whal_Stm32h5Rcc_Disable, + .GetRate = whal_Stm32h5RccHsi_GetRate, +}; + +whal_Error whal_Stm32h5Rcc_Ext_EnableHsi48(whal_Clock *clkDev, uint8_t enable) +{ + size_t base; + + if (!clkDev) + return WHAL_EINVAL; + + base = clkDev->regmap.base; + + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSI48ON_Msk, + whal_SetBits(RCC_CR_HSI48ON_Msk, RCC_CR_HSI48ON_Pos, + enable ? 1 : 0)); + + if (enable) { + while (1) { + size_t rdy; + whal_Reg_Get(base, RCC_CR_REG, RCC_CR_HSI48RDY_Msk, + RCC_CR_HSI48RDY_Pos, &rdy); + if (rdy) + break; + } + } + + return WHAL_SUCCESS; +} diff --git a/src/flash/stm32h5_flash.c b/src/flash/stm32h5_flash.c new file mode 100644 index 0000000..5b6e01d --- /dev/null +++ b/src/flash/stm32h5_flash.c @@ -0,0 +1,331 @@ +#include +#include +#include +#include +#include +#include + +/* + * STM32H5 Flash Register Definitions + * + * The STM32H5 flash controller manages dual-bank embedded flash with 8 KB + * sectors and 128-bit (flash-word) programming. Non-secure register variants + * (NS prefix) are used throughout. + */ + +/* Access Control Register */ +#define FLASH_ACR_REG 0x000 + +/* Non-Secure Key Register - unlock sequence */ +#define FLASH_NSKEYR_REG 0x004 + +/* Non-Secure Status Register */ +#define FLASH_NSSR_REG 0x020 +#define FLASH_NSSR_BSY_Pos 0 +#define FLASH_NSSR_BSY_Msk (1UL << FLASH_NSSR_BSY_Pos) + +#define FLASH_NSSR_WBNE_Pos 1 +#define FLASH_NSSR_WBNE_Msk (1UL << FLASH_NSSR_WBNE_Pos) + +#define FLASH_NSSR_EOP_Pos 16 +#define FLASH_NSSR_EOP_Msk (1UL << FLASH_NSSR_EOP_Pos) + +#define FLASH_NSSR_WRPERR_Pos 17 +#define FLASH_NSSR_WRPERR_Msk (1UL << FLASH_NSSR_WRPERR_Pos) + +#define FLASH_NSSR_PGSERR_Pos 18 +#define FLASH_NSSR_PGSERR_Msk (1UL << FLASH_NSSR_PGSERR_Pos) + +#define FLASH_NSSR_STRBERR_Pos 19 +#define FLASH_NSSR_STRBERR_Msk (1UL << FLASH_NSSR_STRBERR_Pos) + +#define FLASH_NSSR_INCERR_Pos 20 +#define FLASH_NSSR_INCERR_Msk (1UL << FLASH_NSSR_INCERR_Pos) + +#define FLASH_NSSR_ALL_ERR (FLASH_NSSR_WRPERR_Msk | FLASH_NSSR_PGSERR_Msk | \ + FLASH_NSSR_STRBERR_Msk | FLASH_NSSR_INCERR_Msk) + +/* Non-Secure Control Register */ +#define FLASH_NSCR_REG 0x028 +#define FLASH_NSCR_LOCK_Pos 0 +#define FLASH_NSCR_LOCK_Msk (1UL << FLASH_NSCR_LOCK_Pos) + +#define FLASH_NSCR_PG_Pos 1 +#define FLASH_NSCR_PG_Msk (1UL << FLASH_NSCR_PG_Pos) + +#define FLASH_NSCR_SER_Pos 2 +#define FLASH_NSCR_SER_Msk (1UL << FLASH_NSCR_SER_Pos) + +#define FLASH_NSCR_BER_Pos 3 +#define FLASH_NSCR_BER_Msk (1UL << FLASH_NSCR_BER_Pos) + +#define FLASH_NSCR_FW_Pos 4 +#define FLASH_NSCR_FW_Msk (1UL << FLASH_NSCR_FW_Pos) + +#define FLASH_NSCR_STRT_Pos 5 +#define FLASH_NSCR_STRT_Msk (1UL << FLASH_NSCR_STRT_Pos) + +#define FLASH_NSCR_SNB_Pos 6 +#define FLASH_NSCR_SNB_Msk (WHAL_BITMASK(7) << FLASH_NSCR_SNB_Pos) + +#define FLASH_NSCR_BKSEL_Pos 31 +#define FLASH_NSCR_BKSEL_Msk (1UL << FLASH_NSCR_BKSEL_Pos) + +/* Non-Secure Clear Control Register - write 1 to clear status flags */ +#define FLASH_NSCCR_REG 0x030 +#define FLASH_NSCCR_CLR_EOP_Pos 16 +#define FLASH_NSCCR_CLR_EOP_Msk (1UL << FLASH_NSCCR_CLR_EOP_Pos) + +#define FLASH_NSCCR_CLR_WRPERR_Pos 17 +#define FLASH_NSCCR_CLR_WRPERR_Msk (1UL << FLASH_NSCCR_CLR_WRPERR_Pos) + +#define FLASH_NSCCR_CLR_PGSERR_Pos 18 +#define FLASH_NSCCR_CLR_PGSERR_Msk (1UL << FLASH_NSCCR_CLR_PGSERR_Pos) + +#define FLASH_NSCCR_CLR_STRBERR_Pos 19 +#define FLASH_NSCCR_CLR_STRBERR_Msk (1UL << FLASH_NSCCR_CLR_STRBERR_Pos) + +#define FLASH_NSCCR_CLR_INCERR_Pos 20 +#define FLASH_NSCCR_CLR_INCERR_Msk (1UL << FLASH_NSCCR_CLR_INCERR_Pos) + +#define FLASH_NSCCR_CLR_ALL (FLASH_NSCCR_CLR_EOP_Msk | \ + FLASH_NSCCR_CLR_WRPERR_Msk | \ + FLASH_NSCCR_CLR_PGSERR_Msk | \ + FLASH_NSCCR_CLR_STRBERR_Msk | \ + FLASH_NSCCR_CLR_INCERR_Msk) + +/* Unlock keys (same as STM32WB) */ +#define FLASH_KEY1 0x45670123UL +#define FLASH_KEY2 0xCDEF89ABUL + +/* Sector size: 8 KB */ +#define FLASH_SECTOR_SIZE 0x2000 +#define FLASH_SECTOR_SHIFT 13 + +/* Sectors per bank */ +#define FLASH_SECTORS_PER_BANK 128 + +/* Bank size: 1 MB */ +#define FLASH_BANK_SIZE (FLASH_SECTORS_PER_BANK * FLASH_SECTOR_SIZE) + +whal_Error whal_Stm32h5Flash_Init(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Flash_Deinit(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Flash_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; + + whal_Reg_Update(regmap->base, FLASH_NSCR_REG, FLASH_NSCR_LOCK_Msk, + whal_SetBits(FLASH_NSCR_LOCK_Msk, FLASH_NSCR_LOCK_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Flash_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; + + whal_Reg_Write(regmap->base, FLASH_NSKEYR_REG, FLASH_KEY1); + whal_Reg_Write(regmap->base, FLASH_NSKEYR_REG, FLASH_KEY2); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Flash_Read(whal_Flash *flashDev, size_t addr, + uint8_t *data, size_t dataSz) +{ + whal_Stm32h5Flash_Cfg *cfg; + + if (!flashDev || !flashDev->cfg || !data) + return WHAL_EINVAL; + + 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) + data[i] = flashAddr[i]; + + return WHAL_SUCCESS; +} + +static whal_Error WaitNotBusy(size_t base, whal_Timeout *timeout) +{ + return whal_Reg_ReadPoll(base, FLASH_NSSR_REG, FLASH_NSSR_BSY_Msk, + 0, timeout); +} + +static whal_Error CheckErrors(size_t base) +{ + size_t sr = whal_Reg_Read(base, FLASH_NSSR_REG); + if (sr & FLASH_NSSR_ALL_ERR) { + /* Clear all error flags */ + whal_Reg_Write(base, FLASH_NSCCR_REG, FLASH_NSCCR_CLR_ALL); + return WHAL_EHARDWARE; + } + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Flash_Write(whal_Flash *flashDev, size_t addr, + const uint8_t *data, size_t dataSz) +{ + whal_Stm32h5Flash_Cfg *cfg; + const whal_Regmap *regmap; + whal_Error err; + + if (!flashDev || !flashDev->cfg || !data) + return WHAL_EINVAL; + + cfg = flashDev->cfg; + regmap = &flashDev->regmap; + + /* Address and size must be 16-byte aligned (128-bit flash-word) */ + if ((addr & 0xF) || (dataSz & 0xF)) + return WHAL_EINVAL; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + /* Wait for any ongoing operation */ + err = WaitNotBusy(regmap->base, cfg->timeout); + if (err) + return err; + + /* Clear all error and status flags */ + whal_Reg_Write(regmap->base, FLASH_NSCCR_REG, FLASH_NSCCR_CLR_ALL); + + /* Enable programming */ + whal_Reg_Update(regmap->base, FLASH_NSCR_REG, FLASH_NSCR_PG_Msk, + whal_SetBits(FLASH_NSCR_PG_Msk, FLASH_NSCR_PG_Pos, 1)); + + /* Program data in 128-bit (16 byte) flash-word chunks */ + for (size_t i = 0; i < dataSz; i += 16) { + uint32_t *flashAddr = (uint32_t *)(addr + i); + const uint32_t *dataAddr = (const uint32_t *)(data + i); + + flashAddr[0] = dataAddr[0]; + flashAddr[1] = dataAddr[1]; + flashAddr[2] = dataAddr[2]; + flashAddr[3] = dataAddr[3]; + + err = WaitNotBusy(regmap->base, cfg->timeout); + if (err) + goto cleanup; + + err = CheckErrors(regmap->base); + if (err) + goto cleanup; + } + +cleanup: + /* Disable programming */ + whal_Reg_Update(regmap->base, FLASH_NSCR_REG, FLASH_NSCR_PG_Msk, 0); + + return err; +} + +whal_Error whal_Stm32h5Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz) +{ + whal_Stm32h5Flash_Cfg *cfg; + const whal_Regmap *regmap; + whal_Error err; + size_t offset; + size_t startSector, endSector; + + if (!flashDev || !flashDev->cfg) + return WHAL_EINVAL; + + cfg = flashDev->cfg; + regmap = &flashDev->regmap; + + if (dataSz == 0) + return WHAL_SUCCESS; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + /* Wait for any ongoing operation */ + err = WaitNotBusy(regmap->base, cfg->timeout); + if (err) + return err; + + /* Clear all error and status flags */ + whal_Reg_Write(regmap->base, FLASH_NSCCR_REG, FLASH_NSCCR_CLR_ALL); + + offset = addr - cfg->startAddr; + startSector = offset >> FLASH_SECTOR_SHIFT; + endSector = (offset + dataSz - 1) >> FLASH_SECTOR_SHIFT; + + for (size_t sector = startSector; sector <= endSector; sector++) { + size_t bank = (sector >= FLASH_SECTORS_PER_BANK) ? 1 : 0; + size_t sectorInBank = sector - (bank * FLASH_SECTORS_PER_BANK); + + /* Configure: sector erase, sector number, bank select */ + whal_Reg_Update(regmap->base, FLASH_NSCR_REG, + FLASH_NSCR_SER_Msk | FLASH_NSCR_SNB_Msk | + FLASH_NSCR_BKSEL_Msk, + whal_SetBits(FLASH_NSCR_SER_Msk, FLASH_NSCR_SER_Pos, 1) | + whal_SetBits(FLASH_NSCR_SNB_Msk, FLASH_NSCR_SNB_Pos, + sectorInBank) | + whal_SetBits(FLASH_NSCR_BKSEL_Msk, FLASH_NSCR_BKSEL_Pos, + bank)); + + /* Start erase */ + whal_Reg_Update(regmap->base, FLASH_NSCR_REG, FLASH_NSCR_STRT_Msk, + whal_SetBits(FLASH_NSCR_STRT_Msk, FLASH_NSCR_STRT_Pos, 1)); + + err = WaitNotBusy(regmap->base, cfg->timeout); + if (err) + goto cleanup; + + err = CheckErrors(regmap->base); + if (err) + goto cleanup; + } + +cleanup: + /* Clear sector erase mode */ + whal_Reg_Update(regmap->base, FLASH_NSCR_REG, FLASH_NSCR_SER_Msk, 0); + + return err; +} + +const whal_FlashDriver whal_Stm32h5Flash_Driver = { + .Init = whal_Stm32h5Flash_Init, + .Deinit = whal_Stm32h5Flash_Deinit, + .Lock = whal_Stm32h5Flash_Lock, + .Unlock = whal_Stm32h5Flash_Unlock, + .Read = whal_Stm32h5Flash_Read, + .Write = whal_Stm32h5Flash_Write, + .Erase = whal_Stm32h5Flash_Erase, +}; diff --git a/src/gpio/stm32h5_gpio.c b/src/gpio/stm32h5_gpio.c new file mode 100644 index 0000000..7ddf812 --- /dev/null +++ b/src/gpio/stm32h5_gpio.c @@ -0,0 +1 @@ +#include "stm32wb_gpio.c" diff --git a/src/gpio/stm32wb_gpio.c b/src/gpio/stm32wb_gpio.c index a2f063b..e77f45b 100644 --- a/src/gpio/stm32wb_gpio.c +++ b/src/gpio/stm32wb_gpio.c @@ -42,16 +42,12 @@ static inline void whal_Stm32wbGpio_InitAltFn(whal_Regmap *portReg, whal_Stm32wbGpio_PinCfg *pinCfg) { uint8_t pin = pinCfg->pin; - uint8_t maskBit; - uint64_t mask; + size_t offset = (pin < 8) ? GPIO_ALTFNL_REG : GPIO_ALTFNH_REG; + uint8_t pos = (pin & 7) << 2; + size_t mask = WHAL_BITMASK(4) << pos; - /* Each pin uses 4 bits: pin 0 = bits 0-3, pin 1 = bits 4-7, etc. */ - maskBit = pin << 2; - mask = (WHAL_BITMASK(4) << maskBit); - - /* Access AFRL and AFRH as a single 64-bit register */ - uint64_t *reg = (uint64_t *)(portReg->base + GPIO_ALTFNL_REG); - *reg = (*reg & ~mask) | (whal_SetBits(mask, maskBit, pinCfg->altFn) & mask); + whal_Reg_Update(portReg->base, offset, mask, + whal_SetBits(mask, pos, pinCfg->altFn)); } /* diff --git a/src/rng/stm32h5_rng.c b/src/rng/stm32h5_rng.c new file mode 100644 index 0000000..2ee4a47 --- /dev/null +++ b/src/rng/stm32h5_rng.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include +#include + +/* + * STM32H5 RNG Register Definitions + * + * The STM32H5 RNG has a 4-word output FIFO and requires a CONDRST + * sequence to apply configuration. NIST-certified values from AN4230 + * are used for the STM32H563/573/562 family. + */ + +/* Control Register */ +#define RNG_CR_REG 0x00 +#define RNG_CR_RNGEN_Pos 2 +#define RNG_CR_RNGEN_Msk (1UL << RNG_CR_RNGEN_Pos) + +#define RNG_CR_CONDRST_Pos 30 +#define RNG_CR_CONDRST_Msk (1UL << RNG_CR_CONDRST_Pos) + +/* + * NIST-certified RNG_CR configuration for STM32H563/573/562 (from AN4230). + * This value encodes CONFIG1=0x0F, CONFIG2=0x0, CONFIG3=0xE, NISTC=1, + * CLKDIV=0, ARDIS=0, CED=0. + */ +#define RNG_CR_NIST_CFG 0x00F01E00UL + +/* Status Register */ +#define RNG_SR_REG 0x04 +#define RNG_SR_DRDY_Pos 0 +#define RNG_SR_DRDY_Msk (1UL << RNG_SR_DRDY_Pos) + +#define RNG_SR_CECS_Pos 1 +#define RNG_SR_CECS_Msk (1UL << RNG_SR_CECS_Pos) + +#define RNG_SR_SECS_Pos 2 +#define RNG_SR_SECS_Msk (1UL << RNG_SR_SECS_Pos) + +/* Data Register - 32-bit random value */ +#define RNG_DR_REG 0x08 + +/* Noise Source Control Register */ +#define RNG_NSCR_REG 0x0C + +/* Health Test Control Register */ +#define RNG_HTCR_REG 0x10 + +/* NIST-certified HTCR and NSCR values for STM32H563/573/562 (from AN4230) */ +#define RNG_HTCR_NIST_VAL 0x00006A91UL +#define RNG_NSCR_NIST_VAL 0x0003AF66UL + +/* Magic value required to unlock HTCR writes */ +#define RNG_HTCR_MAGIC 0x17590ABCUL + +whal_Error whal_Stm32h5Rng_Init(whal_Rng *rngDev) +{ + whal_Stm32h5Rng_Cfg *cfg; + const whal_Regmap *reg; + whal_Error err; + + if (!rngDev || !rngDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32h5Rng_Cfg *)rngDev->cfg; + reg = &rngDev->regmap; + + /* + * Apply NIST-certified configuration via CONDRST sequence: + * 1. Write CONDRST=1 with configuration bits, RNGEN=0 + * 2. Write HTCR magic key then HTCR value (while CONDRST=1) + * 3. Write NSCR value (while CONDRST=1) + * 4. Write CONDRST=0 with RNGEN=1 to start + */ + whal_Reg_Write(reg->base, RNG_CR_REG, + RNG_CR_NIST_CFG | RNG_CR_CONDRST_Msk); + + whal_Reg_Write(reg->base, RNG_HTCR_REG, RNG_HTCR_MAGIC); + whal_Reg_Write(reg->base, RNG_HTCR_REG, RNG_HTCR_NIST_VAL); + whal_Reg_Write(reg->base, RNG_NSCR_REG, RNG_NSCR_NIST_VAL); + + whal_Reg_Write(reg->base, RNG_CR_REG, + RNG_CR_NIST_CFG | RNG_CR_RNGEN_Msk); + + /* Wait for CONDRST to clear (reset complete) */ + err = whal_Reg_ReadPoll(reg->base, RNG_CR_REG, + RNG_CR_CONDRST_Msk, 0, cfg->timeout); + + return err; +} + +whal_Error whal_Stm32h5Rng_Deinit(whal_Rng *rngDev) +{ + if (!rngDev || !rngDev->cfg) + return WHAL_EINVAL; + + /* Disable the RNG peripheral */ + whal_Reg_Update(rngDev->regmap.base, RNG_CR_REG, RNG_CR_RNGEN_Msk, + whal_SetBits(RNG_CR_RNGEN_Msk, RNG_CR_RNGEN_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Rng_Generate(whal_Rng *rngDev, uint8_t *rngData, + size_t rngDataSz) +{ + whal_Error err = WHAL_SUCCESS; + whal_Stm32h5Rng_Cfg *cfg; + const whal_Regmap *reg; + size_t sr; + size_t offset = 0; + + if (!rngDev || !rngDev->cfg || !rngData) + return WHAL_EINVAL; + + cfg = (whal_Stm32h5Rng_Cfg *)rngDev->cfg; + reg = &rngDev->regmap; +#ifdef WHAL_CFG_NO_TIMEOUT + (void)(cfg); +#endif + + while (offset < rngDataSz) { + /* Wait for a random value to be ready */ + WHAL_TIMEOUT_START(cfg->timeout); + while (1) { + if (WHAL_TIMEOUT_EXPIRED(cfg->timeout)) { + err = WHAL_ETIMEOUT; + goto exit; + } + + sr = whal_Reg_Read(reg->base, RNG_SR_REG); + + if (sr & RNG_SR_SECS_Msk) { + err = WHAL_EHARDWARE; + goto exit; + } + if (sr & RNG_SR_CECS_Msk) { + err = WHAL_EHARDWARE; + goto exit; + } + + if (sr & RNG_SR_DRDY_Msk) + break; + } + + /* Read 32-bit random value */ + uint32_t rnd = (uint32_t)whal_Reg_Read(reg->base, RNG_DR_REG); + + /* Copy bytes into output buffer */ + for (size_t i = 0; i < 4 && offset < rngDataSz; i++, offset++) + rngData[offset] = (uint8_t)(rnd >> (i * 8)); + } + +exit: + return err; +} + +const whal_RngDriver whal_Stm32h5Rng_Driver = { + .Init = whal_Stm32h5Rng_Init, + .Deinit = whal_Stm32h5Rng_Deinit, + .Generate = whal_Stm32h5Rng_Generate, +}; diff --git a/src/spi/stm32h5_spi.c b/src/spi/stm32h5_spi.c new file mode 100644 index 0000000..862e2f3 --- /dev/null +++ b/src/spi/stm32h5_spi.c @@ -0,0 +1,276 @@ +#include +#include +#include +#include +#include +#include + +/* + * STM32H5 SPI Register Definitions + * + * The H5 SPI peripheral uses separate configuration registers (CFG1, CFG2) + * and has TX/RX FIFOs with configurable thresholds. Master transfers + * require explicit CSTART to begin clocking. + */ + +/* Control Register 1 */ +#define SPI_CR1_REG 0x000 +#define SPI_CR1_SPE_Pos 0 +#define SPI_CR1_SPE_Msk (1UL << SPI_CR1_SPE_Pos) + +#define SPI_CR1_CSTART_Pos 9 +#define SPI_CR1_CSTART_Msk (1UL << SPI_CR1_CSTART_Pos) + +#define SPI_CR1_SSI_Pos 12 +#define SPI_CR1_SSI_Msk (1UL << SPI_CR1_SSI_Pos) + +/* Control Register 2 */ +#define SPI_CR2_REG 0x004 +#define SPI_CR2_TSIZE_Pos 0 +#define SPI_CR2_TSIZE_Msk (WHAL_BITMASK(16) << SPI_CR2_TSIZE_Pos) + +/* Configuration Register 1 */ +#define SPI_CFG1_REG 0x008 +#define SPI_CFG1_DSIZE_Pos 0 +#define SPI_CFG1_DSIZE_Msk (WHAL_BITMASK(5) << SPI_CFG1_DSIZE_Pos) + +#define SPI_CFG1_FTHLV_Pos 5 +#define SPI_CFG1_FTHLV_Msk (WHAL_BITMASK(4) << SPI_CFG1_FTHLV_Pos) + +#define SPI_CFG1_MBR_Pos 28 +#define SPI_CFG1_MBR_Msk (WHAL_BITMASK(3) << SPI_CFG1_MBR_Pos) + +/* Configuration Register 2 */ +#define SPI_CFG2_REG 0x00C +#define SPI_CFG2_MSSI_Pos 0 +#define SPI_CFG2_MSSI_Msk (WHAL_BITMASK(4) << SPI_CFG2_MSSI_Pos) + +#define SPI_CFG2_COMM_Pos 17 +#define SPI_CFG2_COMM_Msk (WHAL_BITMASK(2) << SPI_CFG2_COMM_Pos) + +#define SPI_CFG2_MASTER_Pos 22 +#define SPI_CFG2_MASTER_Msk (1UL << SPI_CFG2_MASTER_Pos) + +#define SPI_CFG2_LSBFRST_Pos 23 +#define SPI_CFG2_LSBFRST_Msk (1UL << SPI_CFG2_LSBFRST_Pos) + +#define SPI_CFG2_CPHA_Pos 24 +#define SPI_CFG2_CPHA_Msk (1UL << SPI_CFG2_CPHA_Pos) + +#define SPI_CFG2_CPOL_Pos 25 +#define SPI_CFG2_CPOL_Msk (1UL << SPI_CFG2_CPOL_Pos) + +#define SPI_CFG2_SSM_Pos 26 +#define SPI_CFG2_SSM_Msk (1UL << SPI_CFG2_SSM_Pos) + +/* Status Register */ +#define SPI_SR_REG 0x014 +#define SPI_SR_RXP_Pos 0 +#define SPI_SR_RXP_Msk (1UL << SPI_SR_RXP_Pos) + +#define SPI_SR_TXP_Pos 1 +#define SPI_SR_TXP_Msk (1UL << SPI_SR_TXP_Pos) + +#define SPI_SR_EOT_Pos 3 +#define SPI_SR_EOT_Msk (1UL << SPI_SR_EOT_Pos) + +#define SPI_SR_TXC_Pos 12 +#define SPI_SR_TXC_Msk (1UL << SPI_SR_TXC_Pos) + +/* Interrupt/Status Flags Clear Register */ +#define SPI_IFCR_REG 0x018 +#define SPI_IFCR_EOTC_Pos 3 +#define SPI_IFCR_EOTC_Msk (1UL << SPI_IFCR_EOTC_Pos) + +#define SPI_IFCR_TXTFC_Pos 4 +#define SPI_IFCR_TXTFC_Msk (1UL << SPI_IFCR_TXTFC_Pos) + +/* Data Registers - byte accessible */ +#define SPI_TXDR_REG 0x020 +#define SPI_RXDR_REG 0x030 + +/* + * Calculate the baud rate prescaler index for a target baud rate. + * SPI baud rate = fPCLK / (2 ^ (MBR + 1)) + * MBR=0 -> /2, MBR=1 -> /4, ..., MBR=7 -> /256 + */ +static uint32_t Stm32h5Spi_CalcMbr(size_t pclk, uint32_t targetBaud) +{ + uint32_t mbr; + + for (mbr = 0; mbr < 7; mbr++) { + if ((pclk / (2u << mbr)) <= targetBaud) + return mbr; + } + + return 7; +} + +whal_Error whal_Stm32h5Spi_Init(whal_Spi *spiDev) +{ + const whal_Regmap *reg; + + if (!spiDev || !spiDev->cfg) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + + /* Disable SPI before configuring */ + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_SPE_Msk, + whal_SetBits(SPI_CR1_SPE_Msk, SPI_CR1_SPE_Pos, 0)); + + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_SSI_Msk, + whal_SetBits(SPI_CR1_SSI_Msk, SPI_CR1_SSI_Pos, 1)); + + /* Master mode, software slave management, SSI high */ + whal_Reg_Update(reg->base, SPI_CFG2_REG, + SPI_CFG2_MASTER_Msk | SPI_CFG2_SSM_Msk, + whal_SetBits(SPI_CFG2_MASTER_Msk, SPI_CFG2_MASTER_Pos, 1) | + whal_SetBits(SPI_CFG2_SSM_Msk, SPI_CFG2_SSM_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Spi_Deinit(whal_Spi *spiDev) +{ + const whal_Regmap *reg; + + if (!spiDev || !spiDev->cfg) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_SPE_Msk, + whal_SetBits(SPI_CR1_SPE_Msk, SPI_CR1_SPE_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Spi_StartCom(whal_Spi *spiDev, whal_Spi_ComCfg *comCfg) +{ + const whal_Regmap *reg; + whal_Stm32h5Spi_Cfg *cfg; + uint32_t cpol, cpha, mbr, dsize, fthlv; + + if (!spiDev || !spiDev->cfg || !comCfg) + return WHAL_EINVAL; + + if (comCfg->wordSz < 4 || comCfg->wordSz > 32) + return WHAL_EINVAL; + + if (comCfg->mode > 3 || comCfg->dataLines != 1 || comCfg->freq == 0) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + cfg = (whal_Stm32h5Spi_Cfg *)spiDev->cfg; + + /* Disable SPE before reconfiguring */ + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_SPE_Msk, + whal_SetBits(SPI_CR1_SPE_Msk, SPI_CR1_SPE_Pos, 0)); + + mbr = Stm32h5Spi_CalcMbr(cfg->pclk, comCfg->freq); + cpol = (comCfg->mode >> 1) & 1; + cpha = comCfg->mode & 1; + dsize = comCfg->wordSz - 1; + fthlv = 0; /* 1 data frame threshold */ + + /* Set baud rate, data size, FIFO threshold */ + whal_Reg_Update(reg->base, SPI_CFG1_REG, + SPI_CFG1_MBR_Msk | SPI_CFG1_DSIZE_Msk | SPI_CFG1_FTHLV_Msk, + whal_SetBits(SPI_CFG1_MBR_Msk, SPI_CFG1_MBR_Pos, mbr) | + whal_SetBits(SPI_CFG1_DSIZE_Msk, SPI_CFG1_DSIZE_Pos, dsize) | + whal_SetBits(SPI_CFG1_FTHLV_Msk, SPI_CFG1_FTHLV_Pos, fthlv)); + + /* Set CPOL, CPHA */ + whal_Reg_Update(reg->base, SPI_CFG2_REG, + SPI_CFG2_CPOL_Msk | SPI_CFG2_CPHA_Msk, + whal_SetBits(SPI_CFG2_CPOL_Msk, SPI_CFG2_CPOL_Pos, cpol) | + whal_SetBits(SPI_CFG2_CPHA_Msk, SPI_CFG2_CPHA_Pos, cpha)); + + /* Endless transfer mode (TSIZE = 0) */ + whal_Reg_Update(reg->base, SPI_CR2_REG, SPI_CR2_TSIZE_Msk, 0); + + /* Enable SPI */ + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_SPE_Msk, + whal_SetBits(SPI_CR1_SPE_Msk, SPI_CR1_SPE_Pos, 1)); + + /* Start master transfer */ + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_CSTART_Msk, + whal_SetBits(SPI_CR1_CSTART_Msk, SPI_CR1_CSTART_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Spi_EndCom(whal_Spi *spiDev) +{ + const whal_Regmap *reg; + + if (!spiDev || !spiDev->cfg) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + + /* Disable SPI */ + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_SPE_Msk, + whal_SetBits(SPI_CR1_SPE_Msk, SPI_CR1_SPE_Pos, 0)); + + /* Clear EOT and TXTF flags */ + whal_Reg_Write(reg->base, SPI_IFCR_REG, + SPI_IFCR_EOTC_Msk | SPI_IFCR_TXTFC_Msk); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32h5Spi_SendRecv(whal_Spi *spiDev, + const uint8_t *tx, size_t txLen, + uint8_t *rx, size_t rxLen) +{ + const whal_Regmap *reg; + whal_Stm32h5Spi_Cfg *cfg; + size_t totalLen; + whal_Error err; + uint8_t txByte; + + if (!spiDev || !spiDev->cfg || (!tx && txLen) || (!rx && rxLen)) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + cfg = (whal_Stm32h5Spi_Cfg *)spiDev->cfg; + totalLen = txLen > rxLen ? txLen : rxLen; + + for (size_t i = 0; i < totalLen; i++) { + /* Wait for TXP (TX FIFO has space) */ + err = whal_Reg_ReadPoll(reg->base, SPI_SR_REG, + SPI_SR_TXP_Msk, SPI_SR_TXP_Msk, + cfg->timeout); + if (err) + return err; + + /* Write TX data, pad with 0xFF when exhausted */ + txByte = (tx && i < txLen) ? tx[i] : 0xFF; + *(volatile uint8_t *)(reg->base + SPI_TXDR_REG) = txByte; + + /* Wait for RXP (RX FIFO has data) */ + err = whal_Reg_ReadPoll(reg->base, SPI_SR_REG, + SPI_SR_RXP_Msk, SPI_SR_RXP_Msk, + cfg->timeout); + if (err) + return err; + + /* Read RX byte */ + if (rx && i < rxLen) + rx[i] = *(volatile uint8_t *)(reg->base + SPI_RXDR_REG); + else + (void)*(volatile uint8_t *)(reg->base + SPI_RXDR_REG); + } + + return WHAL_SUCCESS; +} + +const whal_SpiDriver whal_Stm32h5Spi_Driver = { + .Init = whal_Stm32h5Spi_Init, + .Deinit = whal_Stm32h5Spi_Deinit, + .StartCom = whal_Stm32h5Spi_StartCom, + .EndCom = whal_Stm32h5Spi_EndCom, + .SendRecv = whal_Stm32h5Spi_SendRecv, +}; diff --git a/src/uart/stm32h5_uart.c b/src/uart/stm32h5_uart.c new file mode 100644 index 0000000..feaed0c --- /dev/null +++ b/src/uart/stm32h5_uart.c @@ -0,0 +1 @@ +#include "stm32wb_uart.c" diff --git a/tests/flash/test_flash.c b/tests/flash/test_flash.c index a13c641..af4ffe8 100644 --- a/tests/flash/test_flash.c +++ b/tests/flash/test_flash.c @@ -30,8 +30,13 @@ static void Test_Flash_EraseBlank(void) static void Test_Flash_WriteRead(void) { - uint8_t pattern[] = "wolfHAL"; - uint8_t readback[sizeof(pattern)] = {0}; + uint8_t pattern[32] = { + 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, + 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, + 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, + 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, + }; + uint8_t readback[32]; WHAL_ASSERT_EQ(whal_Flash_Unlock(g_testFlashDev, g_testFlashAddr, g_testFlashSectorSz), WHAL_SUCCESS); diff --git a/wolfHAL/clock/stm32h5_rcc.h b/wolfHAL/clock/stm32h5_rcc.h new file mode 100644 index 0000000..ca1284b --- /dev/null +++ b/wolfHAL/clock/stm32h5_rcc.h @@ -0,0 +1,230 @@ +#ifndef WHAL_STM32H5_RCC_H +#define WHAL_STM32H5_RCC_H + +#include +#include +#include + +/* + * @file stm32h5_rcc.h + * @brief STM32H5 RCC (Reset and Clock Control) driver configuration. + * + * The STM32H5 RCC peripheral controls: + * - System clock source selection (HSI, CSI, HSE, PLL1) + * - PLL1/PLL2/PLL3 configuration + * - Peripheral clock gating (AHB1, AHB2, APB1, APB2, APB3 buses) + * - Bus clock prescalers + * + * Two driver variants are provided: + * - whal_Stm32h5RccPll_Driver: Uses PLL1 as system clock source + * - whal_Stm32h5RccHsi_Driver: Uses HSI oscillator as system clock source + */ + +/* + * @brief System clock source selection. + * + * Determines which oscillator/PLL drives the system clock (SYSCLK). + */ +typedef enum { + WHAL_STM32H5_RCC_SYSCLK_SRC_HSI, /* 64 MHz High-Speed Internal */ + WHAL_STM32H5_RCC_SYSCLK_SRC_CSI, /* 4 MHz Low-Power Internal */ + WHAL_STM32H5_RCC_SYSCLK_SRC_HSE, /* High-Speed External crystal */ + WHAL_STM32H5_RCC_SYSCLK_SRC_PLL1, /* PLL1 output */ +} whal_Stm32h5Rcc_SysClockSrc; + +/* + * @brief PLL input clock source selection. + * + * Determines which oscillator feeds PLL1/PLL2/PLL3. + */ +typedef enum { + WHAL_STM32H5_RCC_PLLCLK_SRC_NONE, /* No clock (PLL disabled) */ + WHAL_STM32H5_RCC_PLLCLK_SRC_HSI, /* HSI as PLL input */ + WHAL_STM32H5_RCC_PLLCLK_SRC_CSI, /* CSI as PLL input */ + WHAL_STM32H5_RCC_PLLCLK_SRC_HSE, /* HSE as PLL input */ +} whal_Stm32h5Rcc_PllClockSrc; + +/* + * @brief PLL1 configuration parameters. + * + * The PLL1 output frequency is calculated as: + * f_vco = (f_input / m) * (n + 1) + * f_pllp = f_vco / (p + 1) (main PLL output, used for SYSCLK) + * f_pllq = f_vco / (q + 1) (used for USB, RNG, etc.) + * f_pllr = f_vco / (r + 1) (general purpose) + * + * Constraints: + * - PLL input (f_input / m) must be 1-16 MHz + * - VCO frequency must be 192-836 MHz (wide range) or 150-420 MHz (medium) + * - m: 1-63 (divides by m, 0=disabled) + * - n: 3-511 (multiplies by n+1, so 3=4x, 4=5x, ..., 511=512x) + * - p, q, r: 0-127 (divides by value+1, so 1=/2, 2=/3, ...) + */ +typedef struct whal_Stm32h5Rcc_PllClkCfg { + whal_Stm32h5Rcc_PllClockSrc clkSrc; /* PLL input source */ + uint16_t n; /* PLLN multiplier (3-511, VCO = input * (n+1)) */ + uint8_t m; /* PLLM divider (1-63, input / m) */ + uint8_t p; /* PLLP divider (0-127, output / (p+1)) */ + uint8_t q; /* PLLQ divider (0-127, output / (q+1)) */ + uint8_t r; /* PLLR divider (0-127, output / (r+1)) */ +} whal_Stm32h5Rcc_PllClkCfg; + +/* + * @brief HSI clock configuration parameters. + * + * The HSI is a 64 MHz internal RC oscillator with a configurable divider. + * Default after reset is 64 MHz (div1). + */ +typedef struct whal_Stm32h5Rcc_HsiClkCfg { + uint8_t div; /* HSI divider (0=div1, 1=div2, 2=div4, 3=div8) */ +} whal_Stm32h5Rcc_HsiClkCfg; + +/* + * @brief Peripheral clock enable descriptor. + * + * Describes the register offset and bit mask needed to enable/disable + * a peripheral's bus clock. Used with whal_Stm32h5Rcc_Enable/Disable. + * + * Example for GPIOA: + * { .regOffset = 0x088, .enableMask = (1 << 0), .enablePos = 0 } + */ +typedef struct whal_Stm32h5Rcc_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_Stm32h5Rcc_Clk; + +/* + * @brief RCC driver configuration. + * + * Contains all parameters needed to configure the system clock. + */ +typedef struct whal_Stm32h5Rcc_Cfg { + whal_Stm32h5Rcc_SysClockSrc sysClkSrc; /* System clock source */ + void *sysClkCfg; /* Pointer to PllClkCfg or HsiClkCfg based on driver */ +} whal_Stm32h5Rcc_Cfg; + +/* + * @brief Driver instance for PLL1 clock source. + */ +extern const whal_ClockDriver whal_Stm32h5RccPll_Driver; + +/* + * @brief Driver instance for HSI clock source. + */ +extern const whal_ClockDriver whal_Stm32h5RccHsi_Driver; + +/* + * @brief Initialize the RCC peripheral with PLL1 as system clock. + * + * Configures PLL1 with the parameters in the device configuration, + * enables PLL1, and switches SYSCLK to PLL1 output. + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5RccPll_Init(whal_Clock *clkDev); + +/* + * @brief Deinitialize the RCC peripheral from PLL1 mode. + * + * Switches SYSCLK back to HSI and disables PLL1. + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5RccPll_Deinit(whal_Clock *clkDev); + +/* + * @brief Initialize the RCC peripheral with HSI as system clock. + * + * Configures the HSI divider and selects HSI as SYSCLK source. + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5RccHsi_Init(whal_Clock *clkDev); + +/* + * @brief Deinitialize the RCC peripheral from HSI mode. + * + * Resets HSI divider to default (div1, 64 MHz). + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5RccHsi_Deinit(whal_Clock *clkDev); + +/* + * @brief Enable a peripheral clock gate. + * + * @param clkDev Clock device instance. + * @param clk Pointer to a whal_Stm32h5Rcc_Clk descriptor. + * + * @retval WHAL_SUCCESS Clock enabled. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Rcc_Enable(whal_Clock *clkDev, const void *clk); + +/* + * @brief Disable a peripheral clock gate. + * + * @param clkDev Clock device instance. + * @param clk Pointer to a whal_Stm32h5Rcc_Clk descriptor. + * + * @retval WHAL_SUCCESS Clock disabled. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Rcc_Disable(whal_Clock *clkDev, const void *clk); + +/* + * @brief Compute the current system clock rate (PLL1 mode). + * + * Calculates the PLL1 output frequency from the configured source, + * multiplier, and dividers. + * + * @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_Stm32h5RccPll_GetRate(whal_Clock *clkDev, size_t *rateOut); + +/* + * @brief Compute the current system clock rate (HSI mode). + * + * Returns 64 MHz divided by the configured HSI divider. + * + * @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_Stm32h5RccHsi_GetRate(whal_Clock *clkDev, size_t *rateOut); + +/* + * @brief Enable or disable the HSI48 oscillator. + * + * The HSI48 provides a 48 MHz clock used as kernel clock for the RNG + * and USB peripherals. When enabling, this function waits for the + * oscillator to stabilize. + * + * @param clkDev Clock device instance (RCC regmap). + * @param enable 1 to enable, 0 to disable. + * + * @retval WHAL_SUCCESS HSI48 state changed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Rcc_Ext_EnableHsi48(whal_Clock *clkDev, uint8_t enable); + +#endif /* WHAL_STM32H5_RCC_H */ diff --git a/wolfHAL/flash/stm32h5_flash.h b/wolfHAL/flash/stm32h5_flash.h new file mode 100644 index 0000000..2f6765e --- /dev/null +++ b/wolfHAL/flash/stm32h5_flash.h @@ -0,0 +1,125 @@ +#ifndef WHAL_STM32H5_FLASH_H +#define WHAL_STM32H5_FLASH_H + +#include +#include + +/* + * @file stm32h5_flash.h + * @brief STM32H5 flash driver configuration. + * + * The STM32H5 embedded flash provides: + * - Up to 2 MB organized in dual banks of 8 KB sectors + * - 128-bit (flash-word) programming with write buffer + * - Sector erase and bank/mass erase operations + * - Non-secure and secure register variants (this driver uses non-secure) + */ + +/* + * @brief Flash device configuration. + */ +typedef struct whal_Stm32h5Flash_Cfg { + size_t startAddr; /* Flash base address (typically 0x08000000) */ + size_t size; /* Flash size in bytes */ + whal_Timeout *timeout; +} whal_Stm32h5Flash_Cfg; + +/* + * @brief Driver instance for STM32H5 flash. + */ +extern const whal_FlashDriver whal_Stm32h5Flash_Driver; + +/* + * @brief Initialize the STM32H5 flash interface. + * + * @param flashDev Flash device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Flash_Init(whal_Flash *flashDev); + +/* + * @brief Deinitialize the STM32H5 flash interface. + * + * @param flashDev Flash device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Flash_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_Stm32h5Flash_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_Stm32h5Flash_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. + */ +whal_Error whal_Stm32h5Flash_Read(whal_Flash *flashDev, size_t addr, + uint8_t *data, size_t dataSz); + +/* + * @brief Write data to flash. + * + * Data is programmed in 128-bit (16 byte) flash-word chunks. + * Address and size must be 16-byte aligned. + * + * @param flashDev Flash device instance. + * @param addr Flash address to program (16-byte aligned). + * @param data Buffer to program. + * @param dataSz Number of bytes to program (multiple of 16). + * + * @retval WHAL_SUCCESS Program completed. + * @retval WHAL_EINVAL Invalid arguments or alignment. + * @retval WHAL_EHARDWARE Flash error during programming. + */ +whal_Error whal_Stm32h5Flash_Write(whal_Flash *flashDev, size_t addr, + const uint8_t *data, size_t dataSz); + +/* + * @brief Erase flash sectors covering the given range. + * + * Erases 8 KB sectors. 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. + * @retval WHAL_EHARDWARE Flash error during erase. + */ +whal_Error whal_Stm32h5Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz); + +#endif /* WHAL_STM32H5_FLASH_H */ diff --git a/wolfHAL/gpio/stm32h5_gpio.h b/wolfHAL/gpio/stm32h5_gpio.h new file mode 100644 index 0000000..edc49e9 --- /dev/null +++ b/wolfHAL/gpio/stm32h5_gpio.h @@ -0,0 +1,66 @@ +#ifndef WHAL_STM32H5_GPIO_H +#define WHAL_STM32H5_GPIO_H + +/* + * @file stm32h5_gpio.h + * @brief STM32H5 GPIO driver (alias for STM32WB GPIO). + * + * The STM32H5 GPIO peripheral is register-compatible with the STM32WB GPIO. + * This header re-exports the STM32WB GPIO driver types and symbols under + * STM32H5-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbGpio_Cfg whal_Stm32h5Gpio_Cfg; +typedef whal_Stm32wbGpio_PinCfg whal_Stm32h5Gpio_PinCfg; + +#define whal_Stm32h5Gpio_Driver whal_Stm32wbGpio_Driver +#define whal_Stm32h5Gpio_Init whal_Stm32wbGpio_Init +#define whal_Stm32h5Gpio_Deinit whal_Stm32wbGpio_Deinit +#define whal_Stm32h5Gpio_Get whal_Stm32wbGpio_Get +#define whal_Stm32h5Gpio_Set whal_Stm32wbGpio_Set + +/* + * @brief GPIO mode selection (re-exported from STM32WB). + */ +#define WHAL_STM32H5_GPIO_MODE_IN WHAL_STM32WB_GPIO_MODE_IN +#define WHAL_STM32H5_GPIO_MODE_OUT WHAL_STM32WB_GPIO_MODE_OUT +#define WHAL_STM32H5_GPIO_MODE_ALTFN WHAL_STM32WB_GPIO_MODE_ALTFN +#define WHAL_STM32H5_GPIO_MODE_ANALOG WHAL_STM32WB_GPIO_MODE_ANALOG + +/* + * @brief GPIO output type (re-exported from STM32WB). + */ +#define WHAL_STM32H5_GPIO_OUTTYPE_PUSHPULL WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL +#define WHAL_STM32H5_GPIO_OUTTYPE_OPENDRAIN WHAL_STM32WB_GPIO_OUTTYPE_OPENDRAIN + +/* + * @brief GPIO speed selection (re-exported from STM32WB). + */ +#define WHAL_STM32H5_GPIO_SPEED_LOW WHAL_STM32WB_GPIO_SPEED_LOW +#define WHAL_STM32H5_GPIO_SPEED_MEDIUM WHAL_STM32WB_GPIO_SPEED_MEDIUM +#define WHAL_STM32H5_GPIO_SPEED_FAST WHAL_STM32WB_GPIO_SPEED_FAST +#define WHAL_STM32H5_GPIO_SPEED_HIGH WHAL_STM32WB_GPIO_SPEED_HIGH + +/* + * @brief GPIO pull-up/pull-down selection (re-exported from STM32WB). + */ +#define WHAL_STM32H5_GPIO_PULL_NONE WHAL_STM32WB_GPIO_PULL_NONE +#define WHAL_STM32H5_GPIO_PULL_UP WHAL_STM32WB_GPIO_PULL_UP +#define WHAL_STM32H5_GPIO_PULL_DOWN WHAL_STM32WB_GPIO_PULL_DOWN + +/* + * @brief GPIO port selection (re-exported from STM32WB). + */ +#define WHAL_STM32H5_GPIO_PORT_A WHAL_STM32WB_GPIO_PORT_A +#define WHAL_STM32H5_GPIO_PORT_B WHAL_STM32WB_GPIO_PORT_B +#define WHAL_STM32H5_GPIO_PORT_C WHAL_STM32WB_GPIO_PORT_C +#define WHAL_STM32H5_GPIO_PORT_D WHAL_STM32WB_GPIO_PORT_D +#define WHAL_STM32H5_GPIO_PORT_E WHAL_STM32WB_GPIO_PORT_E +#define WHAL_STM32H5_GPIO_PORT_F WHAL_STM32WB_GPIO_PORT_F +#define WHAL_STM32H5_GPIO_PORT_G WHAL_STM32WB_GPIO_PORT_G +#define WHAL_STM32H5_GPIO_PORT_H WHAL_STM32WB_GPIO_PORT_H +#define WHAL_STM32H5_GPIO_PORT_I WHAL_STM32WB_GPIO_PORT_I + +#endif /* WHAL_STM32H5_GPIO_H */ diff --git a/wolfHAL/platform/arm/cortex_m33.h b/wolfHAL/platform/arm/cortex_m33.h new file mode 100644 index 0000000..50c6312 --- /dev/null +++ b/wolfHAL/platform/arm/cortex_m33.h @@ -0,0 +1,13 @@ +#ifndef WHAL_CORTEX_M33_H +#define WHAL_CORTEX_M33_H + +#include + +#define WHAL_CORTEX_M33_SYSTICK_DEVICE \ + .regmap = { \ + .base = 0xE000E010, \ + .size = 0x400, \ + }, \ + .driver = &whal_SysTick_Driver + +#endif /* WHAL_CORTEX_M33_H */ diff --git a/wolfHAL/platform/st/stm32h563xx.h b/wolfHAL/platform/st/stm32h563xx.h new file mode 100644 index 0000000..dd23bb5 --- /dev/null +++ b/wolfHAL/platform/st/stm32h563xx.h @@ -0,0 +1,182 @@ +#ifndef WHAL_STM32H563XX_H +#define WHAL_STM32H563XX_H + +#include + +#include +#include +#include +#include +#include +#include + +/* + * @file stm32h563xx.h + * @brief Convenience initializers for STM32H563xx device instances. + * + * Base addresses from RM0481 Table 2 (memory map). + * RCC: 0x44020C00 + * GPIO: 0x42020000 (port A), 0x400 spacing per port + * USART1: 0x40013800 + * USART2: 0x40004400 + * USART3: 0x40004800 + * SysTick: ARM core peripheral (0xE000E010) + */ + +/* --- Device macros --- */ + +#define WHAL_STM32H563_RCC_PLL_DEVICE \ + .regmap = { \ + .base = 0x44020C00, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5RccPll_Driver + +#define WHAL_STM32H563_RCC_HSI_DEVICE \ + .regmap = { \ + .base = 0x44020C00, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5RccHsi_Driver + +#define WHAL_STM32H563_GPIO_DEVICE \ + .regmap = { \ + .base = 0x42020000, \ + .size = 0x2400, \ + }, \ + .driver = &whal_Stm32h5Gpio_Driver + +#define WHAL_STM32H563_USART1_DEVICE \ + .regmap = { \ + .base = 0x40013800, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5Uart_Driver + +#define WHAL_STM32H563_USART2_DEVICE \ + .regmap = { \ + .base = 0x40004400, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5Uart_Driver + +#define WHAL_STM32H563_USART3_DEVICE \ + .regmap = { \ + .base = 0x40004800, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5Uart_Driver + +/* --- Clock gate macros --- */ +/* RCC_AHB2ENR (offset 0x08C) */ + +#define WHAL_STM32H563_GPIOA_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32H563_GPIOB_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +#define WHAL_STM32H563_GPIOC_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 2), \ + .enablePos = 2 + +#define WHAL_STM32H563_GPIOD_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 3), \ + .enablePos = 3 + +#define WHAL_STM32H563_GPIOE_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32H563_GPIOF_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 5), \ + .enablePos = 5 + +#define WHAL_STM32H563_GPIOG_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 6), \ + .enablePos = 6 + +#define WHAL_STM32H563_GPIOH_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 7), \ + .enablePos = 7 + +#define WHAL_STM32H563_GPIOI_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 8), \ + .enablePos = 8 + +/* RCC_AHB1ENR (offset 0x088) */ + +#define WHAL_STM32H563_FLASH_CLOCK \ + .regOffset = 0x088, \ + .enableMask = (1UL << 8), \ + .enablePos = 8 + +/* RCC_APB1LENR (offset 0x09C) */ + +#define WHAL_STM32H563_USART2_CLOCK \ + .regOffset = 0x09C, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +#define WHAL_STM32H563_USART3_CLOCK \ + .regOffset = 0x09C, \ + .enableMask = (1UL << 18), \ + .enablePos = 18 + +/* RCC_APB2ENR (offset 0x0A4) */ + +#define WHAL_STM32H563_USART1_CLOCK \ + .regOffset = 0x0A4, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +#define WHAL_STM32H563_SPI1_CLOCK \ + .regOffset = 0x0A4, \ + .enableMask = (1UL << 12), \ + .enablePos = 12 + +/* SPI device macros */ + +#define WHAL_STM32H563_SPI1_DEVICE \ + .regmap = { \ + .base = 0x40013000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5Spi_Driver + +/* RNG device macros */ + +#define WHAL_STM32H563_RNG_DEVICE \ + .regmap = { \ + .base = 0x420C0800, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5Rng_Driver + +/* RCC_AHB2ENR (offset 0x08C), bit 18 */ +#define WHAL_STM32H563_RNG_CLOCK \ + .regOffset = 0x08C, \ + .enableMask = (1UL << 18), \ + .enablePos = 18 + +/* Flash device macros */ + +#define WHAL_STM32H563_FLASH_DEVICE \ + .regmap = { \ + .base = 0x40022000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32h5Flash_Driver + +#endif /* WHAL_STM32H563XX_H */ diff --git a/wolfHAL/rng/stm32h5_rng.h b/wolfHAL/rng/stm32h5_rng.h new file mode 100644 index 0000000..531107d --- /dev/null +++ b/wolfHAL/rng/stm32h5_rng.h @@ -0,0 +1,68 @@ +#ifndef WHAL_STM32H5_RNG_H +#define WHAL_STM32H5_RNG_H + +#include +#include +#include + +/* + * @file stm32h5_rng.h + * @brief STM32H5 RNG driver configuration. + * + * The STM32H5 true random number generator provides 32-bit random values + * from an analog noise source with NIST SP800-90B conditioning. It features + * a 4-word output FIFO and requires a CONDRST sequence to apply configuration + * changes. This driver uses the NIST-certified configuration from AN4230. + */ + +/* + * @brief RNG device configuration. + */ +typedef struct whal_Stm32h5Rng_Cfg { + whal_Timeout *timeout; +} whal_Stm32h5Rng_Cfg; + +/* + * @brief Driver instance for STM32H5 RNG peripheral. + */ +extern const whal_RngDriver whal_Stm32h5Rng_Driver; + +/* + * @brief Initialize the STM32H5 RNG peripheral. + * + * @param rngDev RNG device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Rng_Init(whal_Rng *rngDev); + +/* + * @brief Deinitialize the STM32H5 RNG peripheral. + * + * @param rngDev RNG device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Rng_Deinit(whal_Rng *rngDev); + +/* + * @brief Generate random data. + * + * Polls for DRDY and fills the output buffer. The RNG must be + * initialized via Init() before calling this function. + * + * @param rngDev RNG device instance. + * @param rngData Destination buffer. + * @param rngDataSz Number of random bytes to generate. + * + * @retval WHAL_SUCCESS Buffer filled with random data. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_EHARDWARE Seed or clock error detected. + * @retval WHAL_ETIMEOUT Timed out waiting for random data. + */ +whal_Error whal_Stm32h5Rng_Generate(whal_Rng *rngDev, uint8_t *rngData, + size_t rngDataSz); + +#endif /* WHAL_STM32H5_RNG_H */ diff --git a/wolfHAL/spi/stm32h5_spi.h b/wolfHAL/spi/stm32h5_spi.h new file mode 100644 index 0000000..f8a7cd9 --- /dev/null +++ b/wolfHAL/spi/stm32h5_spi.h @@ -0,0 +1,100 @@ +#ifndef WHAL_STM32H5_SPI_H +#define WHAL_STM32H5_SPI_H + +#include +#include + +/* + * @file stm32h5_spi.h + * @brief STM32H5 SPI driver configuration. + * + * The STM32H5 SPI peripheral differs significantly from the STM32WB SPI: + * - Separate configuration registers (SPI_CFG1, SPI_CFG2) instead of CR1/CR2 + * - Configurable data size up to 32 bits (DSIZE field) + * - TX/RX FIFOs with configurable threshold (FTHLV) + * - Transfer size counter (TSIZE in SPI_CR2) + * - Explicit CSTART bit to begin master transfers + * - Byte-accessible TXDR/RXDR at different offsets (0x020, 0x030) + */ + +/* + * @brief STM32H5 SPI configuration parameters. + */ +typedef struct whal_Stm32h5Spi_Cfg { + size_t pclk; /* Peripheral clock frequency in Hz */ + whal_Timeout *timeout; +} whal_Stm32h5Spi_Cfg; + +/* + * @brief Driver instance for STM32H5 SPI peripheral. + */ +extern const whal_SpiDriver whal_Stm32h5Spi_Driver; + +/* + * @brief Initialize the STM32H5 SPI peripheral. + * + * Configures the SPI as master with software slave management. + * + * @param spiDev SPI device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Spi_Init(whal_Spi *spiDev); + +/* + * @brief Deinitialize the STM32H5 SPI peripheral. + * + * Disables the SPI peripheral. + * + * @param spiDev SPI device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Spi_Deinit(whal_Spi *spiDev); + +/* + * @brief Begin a communication session with the given parameters. + * + * Configures CPOL, CPHA, baud rate, and data size. Enables the SPI. + * + * @param spiDev SPI device instance. + * @param comCfg Per-session communication parameters. + * + * @retval WHAL_SUCCESS Session started. + * @retval WHAL_EINVAL Invalid parameters. + */ +whal_Error whal_Stm32h5Spi_StartCom(whal_Spi *spiDev, whal_Spi_ComCfg *comCfg); + +/* + * @brief End the current communication session. + * + * Disables the SPI peripheral. + * + * @param spiDev SPI device instance. + * + * @retval WHAL_SUCCESS Session ended. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Spi_EndCom(whal_Spi *spiDev); + +/* + * @brief Perform a bidirectional SPI transfer. + * + * Clocks max(txLen, rxLen) bytes. Pads TX with 0xFF when exhausted, + * discards RX when exhausted or NULL. + * + * @param spiDev SPI device instance. + * @param tx Buffer to transmit (NULL to send 0xFF). + * @param txLen Number of bytes to transmit. + * @param rx Buffer to receive (NULL to discard). + * @param rxLen Number of bytes to receive. + * + * @retval WHAL_SUCCESS Transfer completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32h5Spi_SendRecv(whal_Spi *spiDev, const uint8_t *tx, + size_t txLen, uint8_t *rx, size_t rxLen); + +#endif /* WHAL_STM32H5_SPI_H */ diff --git a/wolfHAL/uart/stm32h5_uart.h b/wolfHAL/uart/stm32h5_uart.h new file mode 100644 index 0000000..ebaa139 --- /dev/null +++ b/wolfHAL/uart/stm32h5_uart.h @@ -0,0 +1,39 @@ +#ifndef WHAL_STM32H5_UART_H +#define WHAL_STM32H5_UART_H + +/* + * @file stm32h5_uart.h + * @brief STM32H5 UART driver (alias for STM32WB UART). + * + * The STM32H5 USART peripheral is register-compatible with the STM32WB USART. + * This header re-exports the STM32WB UART driver types and symbols under + * STM32H5-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbUart_Cfg whal_Stm32h5Uart_Cfg; + +/* + * @brief Compute UART BRR register value. + * + * @param clk Peripheral clock frequency in Hz. + * @param baud Desired baud rate. + */ +#define WHAL_STM32H5_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_STM32H5_LPUART_BRR(clk, baud) WHAL_STM32WB_LPUART_BRR(clk, baud) + +#define whal_Stm32h5Uart_Driver whal_Stm32wbUart_Driver +#define whal_Stm32h5Uart_Init whal_Stm32wbUart_Init +#define whal_Stm32h5Uart_Deinit whal_Stm32wbUart_Deinit +#define whal_Stm32h5Uart_Send whal_Stm32wbUart_Send +#define whal_Stm32h5Uart_Recv whal_Stm32wbUart_Recv + +#endif /* WHAL_STM32H5_UART_H */