From 2775cb797104191b501d59e707e9d643c39ffbef Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Mon, 30 Mar 2026 10:32:31 -0400 Subject: [PATCH] [stm32f4, stm32f411_blackpill] Initial stm32f4 implementation --- .github/workflows/ci.yml | 2 +- boards/stm32f411_blackpill/Makefile.inc | 37 +++ boards/stm32f411_blackpill/board.c | 278 ++++++++++++++++++++++ boards/stm32f411_blackpill/board.h | 39 +++ boards/stm32f411_blackpill/ivt.c | 236 ++++++++++++++++++ boards/stm32f411_blackpill/linker.ld | 121 ++++++++++ boards/stm32h563zi_nucleo/board.c | 8 +- src/clock/stm32f4_rcc.c | 249 +++++++++++++++++++ src/flash/stm32f4_flash.c | 302 ++++++++++++++++++++++++ src/gpio/stm32f4_gpio.c | 1 + src/spi/stm32f4_spi.c | 226 ++++++++++++++++++ src/uart/stm32f4_uart.c | 165 +++++++++++++ wolfHAL/clock/stm32f4_rcc.h | 163 +++++++++++++ wolfHAL/flash/stm32f4_flash.h | 174 ++++++++++++++ wolfHAL/gpio/stm32f4_gpio.h | 65 +++++ wolfHAL/platform/st/stm32f411xx.h | 160 +++++++++++++ wolfHAL/spi/stm32f4_spi.h | 101 ++++++++ wolfHAL/uart/stm32f4_uart.h | 94 ++++++++ 18 files changed, 2413 insertions(+), 8 deletions(-) create mode 100644 boards/stm32f411_blackpill/Makefile.inc create mode 100644 boards/stm32f411_blackpill/board.c create mode 100644 boards/stm32f411_blackpill/board.h create mode 100644 boards/stm32f411_blackpill/ivt.c create mode 100644 boards/stm32f411_blackpill/linker.ld create mode 100644 src/clock/stm32f4_rcc.c create mode 100644 src/flash/stm32f4_flash.c create mode 100644 src/gpio/stm32f4_gpio.c create mode 100644 src/spi/stm32f4_spi.c create mode 100644 src/uart/stm32f4_uart.c create mode 100644 wolfHAL/clock/stm32f4_rcc.h create mode 100644 wolfHAL/flash/stm32f4_flash.h create mode 100644 wolfHAL/gpio/stm32f4_gpio.h create mode 100644 wolfHAL/platform/st/stm32f411xx.h create mode 100644 wolfHAL/spi/stm32f4_spi.h create mode 100644 wolfHAL/uart/stm32f4_uart.h diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd0feaf..90f8f20 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] + board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill] extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"] steps: - uses: actions/checkout@v4 diff --git a/boards/stm32f411_blackpill/Makefile.inc b/boards/stm32f411_blackpill/Makefile.inc new file mode 100644 index 0000000..cf5025d --- /dev/null +++ b/boards/stm32f411_blackpill/Makefile.inc @@ -0,0 +1,37 @@ +_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +PLATFORM = stm32f4 +TESTS ?= clock gpio timer flash + +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-m4 -mfloat-abi=hard \ + -mfpu=fpv4-sp-d16 -mthumb \ + -DPLATFORM_STM32F4 -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/*/stm32f4_*.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c) + +# Peripheral devices +include $(WHAL_DIR)/boards/peripheral/Makefile.inc diff --git a/boards/stm32f411_blackpill/board.c b/boards/stm32f411_blackpill/board.c new file mode 100644 index 0000000..5de2c25 --- /dev/null +++ b/boards/stm32f411_blackpill/board.c @@ -0,0 +1,278 @@ +/* Board configuration for the WeAct BlackPill STM32F411CEU6 */ + +#include +#include +#include "board.h" +#include +#include "peripheral.h" + +/* SysTick timing */ +volatile uint32_t g_tick = 0; + +void SysTick_Handler() +{ + g_tick++; +} + +uint32_t Board_GetTick(void) +{ + return g_tick; +} + +whal_Timeout g_whalTimeout = { + .timeoutTicks = 1000, /* 1s timeout */ + .GetTick = Board_GetTick, +}; + +/* STM32F411CE sector layout (512 KB) */ +static const whal_Stm32f4Flash_Sector g_flashSectors[] = { + { .addr = 0x08000000, .size = 0x04000 }, /* Sector 0: 16 KB */ + { .addr = 0x08004000, .size = 0x04000 }, /* Sector 1: 16 KB */ + { .addr = 0x08008000, .size = 0x04000 }, /* Sector 2: 16 KB */ + { .addr = 0x0800C000, .size = 0x04000 }, /* Sector 3: 16 KB */ + { .addr = 0x08010000, .size = 0x10000 }, /* Sector 4: 64 KB */ + { .addr = 0x08020000, .size = 0x20000 }, /* Sector 5: 128 KB */ + { .addr = 0x08040000, .size = 0x20000 }, /* Sector 6: 128 KB */ + { .addr = 0x08060000, .size = 0x20000 }, /* Sector 7: 128 KB */ +}; +#define FLASH_SECTOR_COUNT (sizeof(g_flashSectors) / sizeof(g_flashSectors[0])) + +/* Clock */ +whal_Clock g_whalClock = { + WHAL_STM32F411_RCC_PLL_DEVICE, + + .cfg = &(whal_Stm32f4Rcc_Cfg) { + .sysClkSrc = WHAL_STM32F4_RCC_SYSCLK_SRC_PLL, + .sysClkCfg = &(whal_Stm32f4Rcc_PllClkCfg) { + .clkSrc = WHAL_STM32F4_RCC_PLLCLK_SRC_HSE, + /* HSE = 25 MHz, PLL: (25 / 25) * 200 / 2 = 100 MHz */ + .m = 25, + .n = 200, + .p = 0, /* 0 = div by 2 */ + .q = 4, /* 200 / 4 = 50 MHz (not valid for USB, which needs 48 MHz) */ + }, + .ppre1 = 4, /* APB1 = SYSCLK / 2 = 50 MHz (APB1 max is 50 MHz) */ + .ppre2 = 0, /* APB2 = SYSCLK / 1 = 100 MHz */ + }, +}; + +static const whal_Stm32f4Rcc_Clk g_clocks[] = { + {WHAL_STM32F411_GPIOA_CLOCK}, + {WHAL_STM32F411_GPIOC_CLOCK}, + {WHAL_STM32F411_USART2_CLOCK}, + {WHAL_STM32F411_SPI1_CLOCK}, +}; +#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0])) + +/* GPIO */ +whal_Gpio g_whalGpio = { + WHAL_STM32F411_GPIO_DEVICE, + + .cfg = &(whal_Stm32f4Gpio_Cfg) { + .pinCfg = (whal_Stm32f4Gpio_PinCfg[PIN_COUNT]) { + [LED_PIN] = { /* LED on PC13 (active low) */ + .port = WHAL_STM32F4_GPIO_PORT_C, + .pin = 13, + .mode = WHAL_STM32F4_GPIO_MODE_OUT, + .outType = WHAL_STM32F4_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32F4_GPIO_SPEED_LOW, + .pull = WHAL_STM32F4_GPIO_PULL_NONE, + .altFn = 0, + }, + [UART_TX_PIN] = { /* USART2 TX on PA2 (AF7) */ + .port = WHAL_STM32F4_GPIO_PORT_A, + .pin = 2, + .mode = WHAL_STM32F4_GPIO_MODE_ALTFN, + .outType = WHAL_STM32F4_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32F4_GPIO_SPEED_FAST, + .pull = WHAL_STM32F4_GPIO_PULL_UP, + .altFn = 7, + }, + [UART_RX_PIN] = { /* USART2 RX on PA3 (AF7) */ + .port = WHAL_STM32F4_GPIO_PORT_A, + .pin = 3, + .mode = WHAL_STM32F4_GPIO_MODE_ALTFN, + .outType = WHAL_STM32F4_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32F4_GPIO_SPEED_FAST, + .pull = WHAL_STM32F4_GPIO_PULL_UP, + .altFn = 7, + }, + [SPI_SCK_PIN] = { /* SPI1 SCK on PA5 (AF5) */ + .port = WHAL_STM32F4_GPIO_PORT_A, + .pin = 5, + .mode = WHAL_STM32F4_GPIO_MODE_ALTFN, + .outType = WHAL_STM32F4_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32F4_GPIO_SPEED_FAST, + .pull = WHAL_STM32F4_GPIO_PULL_NONE, + .altFn = 5, + }, + [SPI_MISO_PIN] = { /* SPI1 MISO on PA6 (AF5) */ + .port = WHAL_STM32F4_GPIO_PORT_A, + .pin = 6, + .mode = WHAL_STM32F4_GPIO_MODE_ALTFN, + .outType = WHAL_STM32F4_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32F4_GPIO_SPEED_FAST, + .pull = WHAL_STM32F4_GPIO_PULL_NONE, + .altFn = 5, + }, + [SPI_MOSI_PIN] = { /* SPI1 MOSI on PA7 (AF5) */ + .port = WHAL_STM32F4_GPIO_PORT_A, + .pin = 7, + .mode = WHAL_STM32F4_GPIO_MODE_ALTFN, + .outType = WHAL_STM32F4_GPIO_OUTTYPE_PUSHPULL, + .speed = WHAL_STM32F4_GPIO_SPEED_FAST, + .pull = WHAL_STM32F4_GPIO_PULL_NONE, + .altFn = 5, + }, + }, + .pinCount = PIN_COUNT, + }, +}; + +/* Timer */ +whal_Timer g_whalTimer = { + WHAL_CORTEX_M4_SYSTICK_DEVICE, + + .cfg = &(whal_SysTick_Cfg) { + .cyclesPerTick = 100000000 / 1000, /* 100 MHz / 1 kHz = 1 ms tick */ + .clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK, + .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, + }, +}; + +/* UART */ +whal_Uart g_whalUart = { + WHAL_STM32F411_USART2_DEVICE, + + .cfg = &(whal_Stm32f4Uart_Cfg) { + .timeout = &g_whalTimeout, + .brr = WHAL_STM32F4_UART_BRR(50000000, 115200), + }, +}; + +/* SPI */ +whal_Spi g_whalSpi = { + WHAL_STM32F411_SPI1_DEVICE, + + .cfg = &(whal_Stm32f4Spi_Cfg) { + .pclk = 100000000, + .timeout = &g_whalTimeout, + }, +}; + +/* Flash */ +whal_Flash g_whalFlash = { + WHAL_STM32F411_FLASH_DEVICE, + + .cfg = &(whal_Stm32f4Flash_Cfg) { + .startAddr = 0x08000000, + .size = 0x80000, /* 512 KB */ + .sectors = g_flashSectors, + .sectorCount = FLASH_SECTOR_COUNT, + .timeout = &g_whalTimeout, + }, +}; + +void Board_WaitMs(size_t ms) +{ + uint32_t startCount = g_tick; + while ((g_tick - startCount) < ms) + ; +} + +/* + * Flash latency for 100 MHz at 2.7-3.6V: 3 wait states (Table 5 in RM0383) + * + * RCC_CFGR APB1 prescaler (PPRE1[2:0], bits 12:10): + * 100 = AHB clock divided by 2 => APB1 = 50 MHz + * APB2 prescaler (PPRE2[2:0], bits 15:13): + * 0xx = AHB clock not divided => APB2 = 100 MHz + */ + +whal_Error Board_Init(void) +{ + whal_Error err; + + /* Set flash latency before increasing clock speed */ + err = whal_Stm32f4Flash_Ext_SetLatency(&g_whalFlash, + WHAL_STM32F4_FLASH_LATENCY_3); + if (err) + return err; + + err = whal_Clock_Init(&g_whalClock); + + /* 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/stm32f411_blackpill/board.h b/boards/stm32f411_blackpill/board.h new file mode 100644 index 0000000..98f2da3 --- /dev/null +++ b/boards/stm32f411_blackpill/board.h @@ -0,0 +1,39 @@ +#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 + +/* Flash test address: last sector (sector 7, 128KB at 0x08060000) */ +#define BOARD_FLASH_TEST_ADDR 0x08060000 +#define BOARD_FLASH_SECTOR_SZ 0x20000 +#define BOARD_FLASH_WRITE_SZ 4 + +whal_Error Board_Init(void); +whal_Error Board_Deinit(void); +void Board_WaitMs(size_t ms); + +#endif /* BOARD_H */ diff --git a/boards/stm32f411_blackpill/ivt.c b/boards/stm32f411_blackpill/ivt.c new file mode 100644 index 0000000..a002c66 --- /dev/null +++ b/boards/stm32f411_blackpill/ivt.c @@ -0,0 +1,236 @@ +#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 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"))); + +/* STM32F411 peripheral interrupts */ +void WWDG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void PVD_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TAMP_STAMP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RTC_WKUP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void FLASH_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RCC_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 DMA1_Stream0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Stream1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Stream2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Stream3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Stream4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Stream5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Stream6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ADC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI9_5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_BRK_TIM9_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_UP_TIM10_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM1_TRG_COM_TIM11_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 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 USART1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI15_10_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void RTC_Alarm_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void OTG_FS_WKUP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Stream7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SDIO_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void SPI3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream0_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void OTG_FS_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Stream7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USART6_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 FPU_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"))); + +#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, + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + RESERVED, /* Reserved */ + SVC_Handler, + DebugMon_Handler, + RESERVED, /* Reserved */ + PendSV_Handler, + SysTick_Handler, + /* STM32F411 peripheral interrupts */ + WWDG_IRQHandler, /* 0 */ + PVD_IRQHandler, /* 1 */ + TAMP_STAMP_IRQHandler, /* 2 */ + RTC_WKUP_IRQHandler, /* 3 */ + FLASH_IRQHandler, /* 4 */ + RCC_IRQHandler, /* 5 */ + EXTI0_IRQHandler, /* 6 */ + EXTI1_IRQHandler, /* 7 */ + EXTI2_IRQHandler, /* 8 */ + EXTI3_IRQHandler, /* 9 */ + EXTI4_IRQHandler, /* 10 */ + DMA1_Stream0_IRQHandler, /* 11 */ + DMA1_Stream1_IRQHandler, /* 12 */ + DMA1_Stream2_IRQHandler, /* 13 */ + DMA1_Stream3_IRQHandler, /* 14 */ + DMA1_Stream4_IRQHandler, /* 15 */ + DMA1_Stream5_IRQHandler, /* 16 */ + DMA1_Stream6_IRQHandler, /* 17 */ + ADC_IRQHandler, /* 18 */ + RESERVED, /* 19 */ + RESERVED, /* 20 */ + RESERVED, /* 21 */ + RESERVED, /* 22 */ + EXTI9_5_IRQHandler, /* 23 */ + TIM1_BRK_TIM9_IRQHandler, /* 24 */ + TIM1_UP_TIM10_IRQHandler, /* 25 */ + TIM1_TRG_COM_TIM11_IRQHandler, /* 26 */ + TIM1_CC_IRQHandler, /* 27 */ + TIM2_IRQHandler, /* 28 */ + TIM3_IRQHandler, /* 29 */ + TIM4_IRQHandler, /* 30 */ + I2C1_EV_IRQHandler, /* 31 */ + I2C1_ER_IRQHandler, /* 32 */ + I2C2_EV_IRQHandler, /* 33 */ + I2C2_ER_IRQHandler, /* 34 */ + SPI1_IRQHandler, /* 35 */ + SPI2_IRQHandler, /* 36 */ + USART1_IRQHandler, /* 37 */ + USART2_IRQHandler, /* 38 */ + RESERVED, /* 39 */ + EXTI15_10_IRQHandler, /* 40 */ + RTC_Alarm_IRQHandler, /* 41 */ + OTG_FS_WKUP_IRQHandler, /* 42 */ + RESERVED, /* 43 */ + RESERVED, /* 44 */ + RESERVED, /* 45 */ + RESERVED, /* 46 */ + DMA1_Stream7_IRQHandler, /* 47 */ + RESERVED, /* 48 */ + SDIO_IRQHandler, /* 49 */ + TIM5_IRQHandler, /* 50 */ + SPI3_IRQHandler, /* 51 */ + RESERVED, /* 52 */ + RESERVED, /* 53 */ + RESERVED, /* 54 */ + RESERVED, /* 55 */ + DMA2_Stream0_IRQHandler, /* 56 */ + DMA2_Stream1_IRQHandler, /* 57 */ + DMA2_Stream2_IRQHandler, /* 58 */ + DMA2_Stream3_IRQHandler, /* 59 */ + DMA2_Stream4_IRQHandler, /* 60 */ + RESERVED, /* 61 */ + RESERVED, /* 62 */ + RESERVED, /* 63 */ + RESERVED, /* 64 */ + RESERVED, /* 65 */ + RESERVED, /* 66 */ + OTG_FS_IRQHandler, /* 67 */ + DMA2_Stream5_IRQHandler, /* 68 */ + DMA2_Stream6_IRQHandler, /* 69 */ + DMA2_Stream7_IRQHandler, /* 70 */ + USART6_IRQHandler, /* 71 */ + I2C3_EV_IRQHandler, /* 72 */ + I2C3_ER_IRQHandler, /* 73 */ + RESERVED, /* 74 */ + RESERVED, /* 75 */ + RESERVED, /* 76 */ + RESERVED, /* 77 */ + RESERVED, /* 78 */ + RESERVED, /* 79 */ + RESERVED, /* 80 */ + FPU_IRQHandler, /* 81 */ + RESERVED, /* 82 */ + RESERVED, /* 83 */ + SPI4_IRQHandler, /* 84 */ + SPI5_IRQHandler, /* 85 */ +}; + +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/stm32f411_blackpill/linker.ld b/boards/stm32f411_blackpill/linker.ld new file mode 100644 index 0000000..48d3e21 --- /dev/null +++ b/boards/stm32f411_blackpill/linker.ld @@ -0,0 +1,121 @@ +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20020000; /* end of RAM (128 KB) */ +/* 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 = 512K +RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +/* 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.c b/boards/stm32h563zi_nucleo/board.c index 5171fdf..a70ac89 100644 --- a/boards/stm32h563zi_nucleo/board.c +++ b/boards/stm32h563zi_nucleo/board.c @@ -8,16 +8,10 @@ /* 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; - } + g_tick++; } uint32_t Board_GetTick(void) diff --git a/src/clock/stm32f4_rcc.c b/src/clock/stm32f4_rcc.c new file mode 100644 index 0000000..924ca50 --- /dev/null +++ b/src/clock/stm32f4_rcc.c @@ -0,0 +1,249 @@ +#include +#include +#include +#include +#include + +/* + * STM32F4 RCC Register Definitions + * + * The RCC peripheral manages: + * - Clock source selection and PLL configuration + * - System clock (SYSCLK) routing + * - Bus clock prescalers (AHB, APB1, APB2) + * - Peripheral clock gating + * + * RCC base address: 0x40023800 + */ + +/* 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_HSEON_Pos 16 +#define RCC_CR_HSEON_Msk (1UL << RCC_CR_HSEON_Pos) + +#define RCC_CR_HSERDY_Pos 17 +#define RCC_CR_HSERDY_Msk (1UL << RCC_CR_HSERDY_Pos) + +#define RCC_CR_PLLON_Pos 24 +#define RCC_CR_PLLON_Msk (1UL << RCC_CR_PLLON_Pos) + +#define RCC_CR_PLLRDY_Pos 25 +#define RCC_CR_PLLRDY_Msk (1UL << RCC_CR_PLLRDY_Pos) + +/* PLL Configuration Register */ +#define RCC_PLLCFGR_REG 0x004 +#define RCC_PLLCFGR_PLLM_Pos 0 +#define RCC_PLLCFGR_PLLM_Msk (WHAL_BITMASK(6) << RCC_PLLCFGR_PLLM_Pos) + +#define RCC_PLLCFGR_PLLN_Pos 6 +#define RCC_PLLCFGR_PLLN_Msk (WHAL_BITMASK(9) << RCC_PLLCFGR_PLLN_Pos) + +#define RCC_PLLCFGR_PLLP_Pos 16 +#define RCC_PLLCFGR_PLLP_Msk (WHAL_BITMASK(2) << RCC_PLLCFGR_PLLP_Pos) + +#define RCC_PLLCFGR_PLLSRC_Pos 22 +#define RCC_PLLCFGR_PLLSRC_Msk (1UL << RCC_PLLCFGR_PLLSRC_Pos) + +#define RCC_PLLCFGR_PLLQ_Pos 24 +#define RCC_PLLCFGR_PLLQ_Msk (WHAL_BITMASK(4) << RCC_PLLCFGR_PLLQ_Pos) + +#define RCC_PLLCFGR_Msk \ + (RCC_PLLCFGR_PLLM_Msk | RCC_PLLCFGR_PLLN_Msk | \ + RCC_PLLCFGR_PLLP_Msk | RCC_PLLCFGR_PLLSRC_Msk | \ + RCC_PLLCFGR_PLLQ_Msk) + +/* Clock Configuration Register */ +#define RCC_CFGR_REG 0x008 +#define RCC_CFGR_SW_Pos 0 +#define RCC_CFGR_SW_Msk (WHAL_BITMASK(2) << RCC_CFGR_SW_Pos) + +#define RCC_CFGR_SWS_Pos 2 +#define RCC_CFGR_SWS_Msk (WHAL_BITMASK(2) << RCC_CFGR_SWS_Pos) + +#define RCC_CFGR_PPRE1_Pos 10 +#define RCC_CFGR_PPRE1_Msk (WHAL_BITMASK(3) << RCC_CFGR_PPRE1_Pos) + +#define RCC_CFGR_PPRE2_Pos 13 +#define RCC_CFGR_PPRE2_Msk (WHAL_BITMASK(3) << RCC_CFGR_PPRE2_Pos) + +/* PLLP register value to actual divider: 0->2, 1->4, 2->6, 3->8 */ +static const uint8_t pllp_div[] = { 2, 4, 6, 8 }; + +whal_Error whal_Stm32f4RccPll_Init(whal_Clock *clkDev) +{ + whal_Stm32f4Rcc_Cfg *cfg; + whal_Stm32f4Rcc_PllClkCfg *pllCfg; + size_t base; + + if (!clkDev || !clkDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32f4Rcc_Cfg *)clkDev->cfg; + pllCfg = (whal_Stm32f4Rcc_PllClkCfg *)cfg->sysClkCfg; + base = clkDev->regmap.base; + + /* Enable HSE if selected as PLL source */ + if (pllCfg->clkSrc == WHAL_STM32F4_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 PLL is off before configuring */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 0)); + + /* Configure PLL: source, M, N, P, Q */ + whal_Reg_Update(base, RCC_PLLCFGR_REG, RCC_PLLCFGR_Msk, + whal_SetBits(RCC_PLLCFGR_PLLM_Msk, RCC_PLLCFGR_PLLM_Pos, pllCfg->m) | + whal_SetBits(RCC_PLLCFGR_PLLN_Msk, RCC_PLLCFGR_PLLN_Pos, pllCfg->n) | + whal_SetBits(RCC_PLLCFGR_PLLP_Msk, RCC_PLLCFGR_PLLP_Pos, pllCfg->p) | + whal_SetBits(RCC_PLLCFGR_PLLSRC_Msk, RCC_PLLCFGR_PLLSRC_Pos, pllCfg->clkSrc) | + whal_SetBits(RCC_PLLCFGR_PLLQ_Msk, RCC_PLLCFGR_PLLQ_Pos, pllCfg->q)); + + /* Enable PLL */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 1)); + + /* Wait for PLL lock */ + while (1) { + size_t rdy; + whal_Reg_Get(base, RCC_CR_REG, RCC_CR_PLLRDY_Msk, + RCC_CR_PLLRDY_Pos, &rdy); + if (rdy) + break; + } + + /* Set APB1 and APB2 prescalers before switching to higher speed */ + whal_Reg_Update(base, RCC_CFGR_REG, + RCC_CFGR_PPRE1_Msk | RCC_CFGR_PPRE2_Msk, + whal_SetBits(RCC_CFGR_PPRE1_Msk, RCC_CFGR_PPRE1_Pos, + cfg->ppre1) | + whal_SetBits(RCC_CFGR_PPRE2_Msk, RCC_CFGR_PPRE2_Pos, + cfg->ppre2)); + + /* Switch system clock to PLL */ + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_SW_Msk, + whal_SetBits(RCC_CFGR_SW_Msk, RCC_CFGR_SW_Pos, + WHAL_STM32F4_RCC_SYSCLK_SRC_PLL)); + + /* Wait for switch to complete */ + while (1) { + size_t sws; + whal_Reg_Get(base, RCC_CFGR_REG, RCC_CFGR_SWS_Msk, + RCC_CFGR_SWS_Pos, &sws); + if (sws == WHAL_STM32F4_RCC_SYSCLK_SRC_PLL) + break; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4RccPll_Deinit(whal_Clock *clkDev) +{ + size_t base; + + if (!clkDev) + return WHAL_EINVAL; + + base = clkDev->regmap.base; + + /* Switch back to HSI before disabling PLL */ + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_SW_Msk, + whal_SetBits(RCC_CFGR_SW_Msk, RCC_CFGR_SW_Pos, + WHAL_STM32F4_RCC_SYSCLK_SRC_HSI)); + + /* Wait for switch to complete */ + while (1) { + size_t sws; + whal_Reg_Get(base, RCC_CFGR_REG, RCC_CFGR_SWS_Msk, + RCC_CFGR_SWS_Pos, &sws); + if (sws == WHAL_STM32F4_RCC_SYSCLK_SRC_HSI) + break; + } + + /* Disable PLL */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Rcc_Enable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32f4Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32f4Rcc_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_Stm32f4Rcc_Disable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32f4Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32f4Rcc_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_Stm32f4RccPll_GetRate(whal_Clock *clkDev, size_t *rateOut) +{ + whal_Stm32f4Rcc_Cfg *cfg; + whal_Stm32f4Rcc_PllClkCfg *pllCfg; + size_t srcFreq; + size_t pllm; + size_t plln; + size_t pllp; + + if (!clkDev || !clkDev->cfg || !rateOut) + return WHAL_EINVAL; + + cfg = (whal_Stm32f4Rcc_Cfg *)clkDev->cfg; + pllCfg = (whal_Stm32f4Rcc_PllClkCfg *)cfg->sysClkCfg; + + /* Determine source frequency */ + if (pllCfg->clkSrc == WHAL_STM32F4_RCC_PLLCLK_SRC_HSI) + srcFreq = 16000000; + else + srcFreq = 25000000; + + pllm = pllCfg->m; + plln = pllCfg->n; + pllp = pllp_div[pllCfg->p & 0x3]; + + *rateOut = ((srcFreq / pllm) * plln) / pllp; + return WHAL_SUCCESS; +} + +const whal_ClockDriver whal_Stm32f4RccPll_Driver = { + .Init = whal_Stm32f4RccPll_Init, + .Deinit = whal_Stm32f4RccPll_Deinit, + .Enable = whal_Stm32f4Rcc_Enable, + .Disable = whal_Stm32f4Rcc_Disable, + .GetRate = whal_Stm32f4RccPll_GetRate, +}; diff --git a/src/flash/stm32f4_flash.c b/src/flash/stm32f4_flash.c new file mode 100644 index 0000000..2cf5434 --- /dev/null +++ b/src/flash/stm32f4_flash.c @@ -0,0 +1,302 @@ +#include +#include +#include +#include +#include +#include + +/* + * STM32F4 Flash Register Definitions + * + * The STM32F4 flash controller manages embedded flash with variable-size + * sectors and 32-bit word programming (at 2.7-3.6V with PSIZE=10). + * + * Flash interface base: 0x40023C00 + */ + +/* Access Control Register - configures latency and caches */ +#define FLASH_ACR_REG 0x00 +#define FLASH_ACR_LATENCY_Pos 0 +#define FLASH_ACR_LATENCY_Msk (WHAL_BITMASK(4) << FLASH_ACR_LATENCY_Pos) + +/* Key Register - unlock sequence */ +#define FLASH_KEYR_REG 0x04 + +/* Status Register */ +#define FLASH_SR_REG 0x0C +#define FLASH_SR_EOP_Pos 0 +#define FLASH_SR_EOP_Msk (1UL << FLASH_SR_EOP_Pos) + +#define FLASH_SR_OPERR_Pos 1 +#define FLASH_SR_OPERR_Msk (1UL << FLASH_SR_OPERR_Pos) + +#define FLASH_SR_WRPERR_Pos 4 +#define FLASH_SR_WRPERR_Msk (1UL << FLASH_SR_WRPERR_Pos) + +#define FLASH_SR_PGAERR_Pos 5 +#define FLASH_SR_PGAERR_Msk (1UL << FLASH_SR_PGAERR_Pos) + +#define FLASH_SR_PGPERR_Pos 6 +#define FLASH_SR_PGPERR_Msk (1UL << FLASH_SR_PGPERR_Pos) + +#define FLASH_SR_PGSERR_Pos 7 +#define FLASH_SR_PGSERR_Msk (1UL << FLASH_SR_PGSERR_Pos) + +#define FLASH_SR_RDERR_Pos 8 +#define FLASH_SR_RDERR_Msk (1UL << FLASH_SR_RDERR_Pos) + +#define FLASH_SR_BSY_Pos 16 +#define FLASH_SR_BSY_Msk (1UL << FLASH_SR_BSY_Pos) + +#define FLASH_SR_ALL_ERR (FLASH_SR_OPERR_Msk | FLASH_SR_WRPERR_Msk | \ + FLASH_SR_PGAERR_Msk | FLASH_SR_PGPERR_Msk | \ + FLASH_SR_PGSERR_Msk | FLASH_SR_RDERR_Msk) + +/* Control Register */ +#define FLASH_CR_REG 0x10 +#define FLASH_CR_PG_Pos 0 +#define FLASH_CR_PG_Msk (1UL << FLASH_CR_PG_Pos) + +#define FLASH_CR_SER_Pos 1 +#define FLASH_CR_SER_Msk (1UL << FLASH_CR_SER_Pos) + +#define FLASH_CR_SNB_Pos 3 +#define FLASH_CR_SNB_Msk (WHAL_BITMASK(4) << FLASH_CR_SNB_Pos) + +#define FLASH_CR_PSIZE_Pos 8 +#define FLASH_CR_PSIZE_Msk (WHAL_BITMASK(2) << FLASH_CR_PSIZE_Pos) + +#define FLASH_CR_STRT_Pos 16 +#define FLASH_CR_STRT_Msk (1UL << FLASH_CR_STRT_Pos) + +#define FLASH_CR_LOCK_Pos 31 +#define FLASH_CR_LOCK_Msk (1UL << FLASH_CR_LOCK_Pos) + +/* PSIZE values: 00=x8, 01=x16, 10=x32, 11=x64 */ +#define FLASH_PSIZE_WORD 2 + +/* Unlock keys */ +#define FLASH_KEY1 0x45670123UL +#define FLASH_KEY2 0xCDEF89ABUL + +whal_Error whal_Stm32f4Flash_Init(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Flash_Deinit(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Flash_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_CR_REG, FLASH_CR_LOCK_Msk, + whal_SetBits(FLASH_CR_LOCK_Msk, FLASH_CR_LOCK_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Flash_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_KEYR_REG, FLASH_KEY1); + whal_Reg_Write(regmap->base, FLASH_KEYR_REG, FLASH_KEY2); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Flash_Read(whal_Flash *flashDev, size_t addr, + uint8_t *data, size_t dataSz) +{ + whal_Stm32f4Flash_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; +} + +whal_Error whal_Stm32f4Flash_Write(whal_Flash *flashDev, size_t addr, + const uint8_t *data, size_t dataSz) +{ + whal_Stm32f4Flash_Cfg *cfg; + const whal_Regmap *regmap; + whal_Error err = WHAL_SUCCESS; + + if (!flashDev || !flashDev->cfg || !data) + return WHAL_EINVAL; + + cfg = flashDev->cfg; + regmap = &flashDev->regmap; + + /* Address and size must be 4-byte aligned for word programming */ + if ((addr & 0x3) || (dataSz & 0x3)) + return WHAL_EINVAL; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + /* Wait for any ongoing operation */ + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, FLASH_SR_BSY_Msk, + 0, cfg->timeout); + if (err) + return err; + + /* Clear all error flags */ + whal_Reg_Update(regmap->base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + + /* Set programming mode with word-size parallelism */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, + FLASH_CR_PG_Msk | FLASH_CR_PSIZE_Msk, + whal_SetBits(FLASH_CR_PG_Msk, FLASH_CR_PG_Pos, 1) | + whal_SetBits(FLASH_CR_PSIZE_Msk, FLASH_CR_PSIZE_Pos, FLASH_PSIZE_WORD)); + + /* Program data in 32-bit word chunks */ + for (size_t i = 0; i < dataSz; i += 4) { + uint32_t *flashAddr = (uint32_t *)(addr + i); + const uint32_t *dataAddr = (const uint32_t *)(data + i); + + *flashAddr = *dataAddr; + + /* Wait for programming to complete */ + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, FLASH_SR_BSY_Msk, + 0, cfg->timeout); + if (err) + goto cleanup; + + /* Check for errors */ + if (whal_Reg_Read(regmap->base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(regmap->base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } + } + +cleanup: + /* Disable programming mode */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PG_Msk, 0); + + return err; +} + +whal_Error whal_Stm32f4Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz) +{ + whal_Stm32f4Flash_Cfg *cfg; + const whal_Regmap *regmap; + whal_Error err = WHAL_SUCCESS; + + 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 = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, FLASH_SR_BSY_Msk, + 0, cfg->timeout); + if (err) + return err; + + /* Clear all error flags */ + whal_Reg_Update(regmap->base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + + /* Find and erase sectors that overlap with the address range */ + for (size_t s = 0; s < cfg->sectorCount; s++) { + size_t sectStart = cfg->sectors[s].addr; + size_t sectEnd = sectStart + cfg->sectors[s].size; + + /* Check if this sector overlaps with the erase range */ + if (sectStart >= addr + dataSz || sectEnd <= addr) + continue; + + /* Set sector erase with word parallelism */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, + FLASH_CR_SER_Msk | FLASH_CR_SNB_Msk | FLASH_CR_PSIZE_Msk, + whal_SetBits(FLASH_CR_SER_Msk, FLASH_CR_SER_Pos, 1) | + whal_SetBits(FLASH_CR_SNB_Msk, FLASH_CR_SNB_Pos, s) | + whal_SetBits(FLASH_CR_PSIZE_Msk, FLASH_CR_PSIZE_Pos, FLASH_PSIZE_WORD)); + + /* Start erase */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_STRT_Msk, + whal_SetBits(FLASH_CR_STRT_Msk, FLASH_CR_STRT_Pos, 1)); + + /* Wait for erase to complete */ + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, FLASH_SR_BSY_Msk, + 0, cfg->timeout); + if (err) + goto cleanup; + + /* Check for errors */ + if (whal_Reg_Read(regmap->base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + whal_Reg_Update(regmap->base, FLASH_SR_REG, FLASH_SR_ALL_ERR, FLASH_SR_ALL_ERR); + err = WHAL_EHARDWARE; + goto cleanup; + } + } + +cleanup: + /* Clear sector erase mode */ + whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_SER_Msk, 0); + + return err; +} + +whal_Error whal_Stm32f4Flash_Ext_SetLatency(whal_Flash *flashDev, + enum whal_Stm32f4Flash_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, + whal_SetBits(FLASH_ACR_LATENCY_Msk, FLASH_ACR_LATENCY_Pos, latency)); + return WHAL_SUCCESS; +} + +const whal_FlashDriver whal_Stm32f4Flash_Driver = { + .Init = whal_Stm32f4Flash_Init, + .Deinit = whal_Stm32f4Flash_Deinit, + .Lock = whal_Stm32f4Flash_Lock, + .Unlock = whal_Stm32f4Flash_Unlock, + .Read = whal_Stm32f4Flash_Read, + .Write = whal_Stm32f4Flash_Write, + .Erase = whal_Stm32f4Flash_Erase, +}; diff --git a/src/gpio/stm32f4_gpio.c b/src/gpio/stm32f4_gpio.c new file mode 100644 index 0000000..7ddf812 --- /dev/null +++ b/src/gpio/stm32f4_gpio.c @@ -0,0 +1 @@ +#include "stm32wb_gpio.c" diff --git a/src/spi/stm32f4_spi.c b/src/spi/stm32f4_spi.c new file mode 100644 index 0000000..f376aec --- /dev/null +++ b/src/spi/stm32f4_spi.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include + +/* + * STM32F4 SPI Register Definitions + * + * The SPI peripheral provides full-duplex synchronous serial communication. + * This driver configures it in master mode with software slave management + * and 8-bit data frames. + * + * Key difference from STM32WB: data frame size is controlled by DFF bit + * in CR1 (bit 11), not by DS field in CR2. + */ + +/* Control Register 1 - master config, clock, enable */ +#define SPI_CR1_REG 0x00 +#define SPI_CR1_CPHA_Pos 0 /* Clock phase */ +#define SPI_CR1_CPHA_Msk (1UL << SPI_CR1_CPHA_Pos) + +#define SPI_CR1_CPOL_Pos 1 /* Clock polarity */ +#define SPI_CR1_CPOL_Msk (1UL << SPI_CR1_CPOL_Pos) + +#define SPI_CR1_MSTR_Pos 2 /* Master selection */ +#define SPI_CR1_MSTR_Msk (1UL << SPI_CR1_MSTR_Pos) + +#define SPI_CR1_BR_Pos 3 /* Baud rate prescaler */ +#define SPI_CR1_BR_Msk (WHAL_BITMASK(3) << SPI_CR1_BR_Pos) + +#define SPI_CR1_SPE_Pos 6 /* SPI enable */ +#define SPI_CR1_SPE_Msk (1UL << SPI_CR1_SPE_Pos) + +#define SPI_CR1_SSI_Pos 8 /* Internal slave select */ +#define SPI_CR1_SSI_Msk (1UL << SPI_CR1_SSI_Pos) + +#define SPI_CR1_SSM_Pos 9 /* Software slave management */ +#define SPI_CR1_SSM_Msk (1UL << SPI_CR1_SSM_Pos) + +#define SPI_CR1_DFF_Pos 11 /* Data frame format (0=8bit, 1=16bit) */ +#define SPI_CR1_DFF_Msk (1UL << SPI_CR1_DFF_Pos) + +/* Status Register */ +#define SPI_SR_REG 0x08 +#define SPI_SR_RXNE_Pos 0 /* Receive buffer not empty */ +#define SPI_SR_RXNE_Msk (1UL << SPI_SR_RXNE_Pos) + +#define SPI_SR_TXE_Pos 1 /* Transmit buffer empty */ +#define SPI_SR_TXE_Msk (1UL << SPI_SR_TXE_Pos) + +#define SPI_SR_BSY_Pos 7 /* Busy flag */ +#define SPI_SR_BSY_Msk (1UL << SPI_SR_BSY_Pos) + +/* Data Register - 8/16-bit access */ +#define SPI_DR_REG 0x0C + +/* + * Calculate the baud rate prescaler index for a target baud rate. + * + * SPI baud rate = fPCLK / (2 ^ (BR + 1)) + * BR=0 -> /2, BR=1 -> /4, BR=2 -> /8, ... BR=7 -> /256 + * + * Returns the smallest prescaler that does not exceed the target baud. + */ +static uint32_t whal_Stm32f4Spi_CalcBr(size_t pclk, uint32_t targetBaud) +{ + uint32_t br; + + for (br = 0; br < 7; br++) { + if ((pclk / (2u << br)) <= targetBaud) + return br; + } + + return 7; +} + +whal_Error whal_Stm32f4Spi_Init(whal_Spi *spiDev) +{ + const whal_Regmap *reg; + + if (!spiDev || !spiDev->cfg) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + + /* Master mode with software slave management */ + whal_Reg_Update(reg->base, SPI_CR1_REG, + SPI_CR1_MSTR_Msk | SPI_CR1_SSM_Msk | SPI_CR1_SSI_Msk, + whal_SetBits(SPI_CR1_MSTR_Msk, SPI_CR1_MSTR_Pos, 1) | + whal_SetBits(SPI_CR1_SSM_Msk, SPI_CR1_SSM_Pos, 1) | + whal_SetBits(SPI_CR1_SSI_Msk, SPI_CR1_SSI_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Spi_Deinit(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)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Spi_StartCom(whal_Spi *spiDev, whal_Spi_ComCfg *comCfg) +{ + const whal_Regmap *reg; + whal_Stm32f4Spi_Cfg *cfg; + uint32_t cpol, cpha, br; + + if (!spiDev || !spiDev->cfg || !comCfg) + return WHAL_EINVAL; + + /* Only 8-bit frames supported */ + if (comCfg->wordSz != 8) + return WHAL_EINVAL; + + if (comCfg->mode > 3 || comCfg->dataLines != 1 || comCfg->freq == 0) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + cfg = (whal_Stm32f4Spi_Cfg *)spiDev->cfg; + + br = whal_Stm32f4Spi_CalcBr(cfg->pclk, comCfg->freq); + + cpol = (comCfg->mode >> 1) & 1; + cpha = comCfg->mode & 1; + + /* 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)); + + /* Set mode and baud rate (DFF=0 for 8-bit) */ + whal_Reg_Update(reg->base, SPI_CR1_REG, + SPI_CR1_CPOL_Msk | SPI_CR1_CPHA_Msk | SPI_CR1_BR_Msk | SPI_CR1_DFF_Msk, + whal_SetBits(SPI_CR1_CPOL_Msk, SPI_CR1_CPOL_Pos, cpol) | + whal_SetBits(SPI_CR1_CPHA_Msk, SPI_CR1_CPHA_Pos, cpha) | + whal_SetBits(SPI_CR1_BR_Msk, SPI_CR1_BR_Pos, br)); + + /* Enable SPE */ + whal_Reg_Update(reg->base, SPI_CR1_REG, SPI_CR1_SPE_Msk, + whal_SetBits(SPI_CR1_SPE_Msk, SPI_CR1_SPE_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Spi_EndCom(whal_Spi *spiDev) +{ + const whal_Regmap *reg; + + if (!spiDev || !spiDev->cfg) + return WHAL_EINVAL; + + reg = &spiDev->regmap; + + /* Disable SPE */ + 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_Stm32f4Spi_SendRecv(whal_Spi *spiDev, + const uint8_t *tx, size_t txLen, + uint8_t *rx, size_t rxLen) +{ + const whal_Regmap *reg; + whal_Stm32f4Spi_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_Stm32f4Spi_Cfg *)spiDev->cfg; + totalLen = txLen > rxLen ? txLen : rxLen; + + for (size_t i = 0; i < totalLen; i++) { + /* Wait for TX buffer empty */ + err = whal_Reg_ReadPoll(reg->base, SPI_SR_REG, + SPI_SR_TXE_Msk, SPI_SR_TXE_Msk, + cfg->timeout); + if (err) + return err; + + /* Write TX data, pad with 0xFF when tx is exhausted or NULL */ + txByte = (tx && i < txLen) ? tx[i] : 0xFF; + *(volatile uint8_t *)(reg->base + SPI_DR_REG) = txByte; + + /* Wait for RX byte */ + err = whal_Reg_ReadPoll(reg->base, SPI_SR_REG, + SPI_SR_RXNE_Msk, SPI_SR_RXNE_Msk, + cfg->timeout); + if (err) + return err; + + /* Store or discard received byte */ + if (rx && i < rxLen) + rx[i] = *(volatile uint8_t *)(reg->base + SPI_DR_REG); + else + (void)*(volatile uint8_t *)(reg->base + SPI_DR_REG); + } + + /* Wait for not busy */ + return whal_Reg_ReadPoll(reg->base, SPI_SR_REG, SPI_SR_BSY_Msk, 0, + cfg->timeout); +} + +const whal_SpiDriver whal_Stm32f4Spi_Driver = { + .Init = whal_Stm32f4Spi_Init, + .Deinit = whal_Stm32f4Spi_Deinit, + .StartCom = whal_Stm32f4Spi_StartCom, + .EndCom = whal_Stm32f4Spi_EndCom, + .SendRecv = whal_Stm32f4Spi_SendRecv, +}; diff --git a/src/uart/stm32f4_uart.c b/src/uart/stm32f4_uart.c new file mode 100644 index 0000000..f5905b4 --- /dev/null +++ b/src/uart/stm32f4_uart.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include +#include +#include +#include + +/* + * STM32F4 USART Register Definitions (USARTv1) + * + * The STM32F4 USART uses SR/DR style registers which differ from the + * ISR/TDR/RDR layout on newer STM32 families. + */ + +/* Status Register */ +#define UART_SR_REG 0x00 +#define UART_SR_RXNE_Pos 5 /* Receive data register not empty */ +#define UART_SR_RXNE_Msk (1UL << UART_SR_RXNE_Pos) + +#define UART_SR_TC_Pos 6 /* Transmission complete */ +#define UART_SR_TC_Msk (1UL << UART_SR_TC_Pos) + +#define UART_SR_TXE_Pos 7 /* Transmit data register empty */ +#define UART_SR_TXE_Msk (1UL << UART_SR_TXE_Pos) + +/* Data Register - shared TX/RX */ +#define UART_DR_REG 0x04 +#define UART_DR_Pos 0 +#define UART_DR_Msk (WHAL_BITMASK(9) << UART_DR_Pos) + +/* Baud Rate Register */ +#define UART_BRR_REG 0x08 +#define UART_BRR_Pos 0 +#define UART_BRR_Msk (WHAL_BITMASK(16) << UART_BRR_Pos) + +/* Control Register 1 */ +#define UART_CR1_REG 0x0C +#define UART_CR1_RE_Pos 2 /* Receiver enable */ +#define UART_CR1_RE_Msk (1UL << UART_CR1_RE_Pos) + +#define UART_CR1_TE_Pos 3 /* Transmitter enable */ +#define UART_CR1_TE_Msk (1UL << UART_CR1_TE_Pos) + +#define UART_CR1_UE_Pos 13 /* USART enable */ +#define UART_CR1_UE_Msk (1UL << UART_CR1_UE_Pos) + +whal_Error whal_Stm32f4Uart_Init(whal_Uart *uartDev) +{ + whal_Stm32f4Uart_Cfg *cfg; + const whal_Regmap *reg; + uint32_t brr; + + if (!uartDev || !uartDev->cfg) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + cfg = (whal_Stm32f4Uart_Cfg *)uartDev->cfg; + + brr = cfg->brr; + + /* Set baud rate */ + whal_Reg_Update(reg->base, UART_BRR_REG, + UART_BRR_Msk, + whal_SetBits(UART_BRR_Msk, UART_BRR_Pos, brr)); + + /* Enable USART, transmitter, and receiver */ + whal_Reg_Update(reg->base, UART_CR1_REG, + UART_CR1_UE_Msk | UART_CR1_RE_Msk | UART_CR1_TE_Msk, + whal_SetBits(UART_CR1_UE_Msk, UART_CR1_UE_Pos, 1) | + whal_SetBits(UART_CR1_RE_Msk, UART_CR1_RE_Pos, 1) | + whal_SetBits(UART_CR1_TE_Msk, UART_CR1_TE_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Uart_Deinit(whal_Uart *uartDev) +{ + const whal_Regmap *reg; + + if (!uartDev) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + + /* Disable USART, transmitter, and receiver */ + whal_Reg_Update(reg->base, UART_CR1_REG, + UART_CR1_UE_Msk | UART_CR1_RE_Msk | UART_CR1_TE_Msk, + whal_SetBits(UART_CR1_UE_Msk, UART_CR1_UE_Pos, 0) | + whal_SetBits(UART_CR1_RE_Msk, UART_CR1_RE_Pos, 0) | + whal_SetBits(UART_CR1_TE_Msk, UART_CR1_TE_Pos, 0)); + + /* Clear baud rate */ + whal_Reg_Update(reg->base, UART_BRR_REG, + UART_BRR_Msk, + whal_SetBits(UART_BRR_Msk, UART_BRR_Pos, 0)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Uart_Send(whal_Uart *uartDev, const void *data, size_t dataSz) +{ + const whal_Regmap *reg; + whal_Stm32f4Uart_Cfg *cfg; + const uint8_t *buf = data; + + if (!uartDev || !uartDev->cfg || !data) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + cfg = (whal_Stm32f4Uart_Cfg *)uartDev->cfg; + + for (size_t i = 0; i < dataSz; ++i) { + whal_Error err; + + /* Wait for transmit data register empty */ + err = whal_Reg_ReadPoll(reg->base, UART_SR_REG, UART_SR_TXE_Msk, + UART_SR_TXE_Msk, cfg->timeout); + if (err) + return err; + + /* Write byte to data register (must not read DR — use pure write) */ + whal_Reg_Write(reg->base, UART_DR_REG, buf[i]); + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32f4Uart_Recv(whal_Uart *uartDev, void *data, size_t dataSz) +{ + const whal_Regmap *reg; + whal_Stm32f4Uart_Cfg *cfg; + uint8_t *buf = data; + + if (!uartDev || !uartDev->cfg || !data) + return WHAL_EINVAL; + + reg = &uartDev->regmap; + cfg = (whal_Stm32f4Uart_Cfg *)uartDev->cfg; + size_t d; + + for (size_t i = 0; i < dataSz; ++i) { + /* Wait for receive data register not empty */ + whal_Error err = whal_Reg_ReadPoll(reg->base, UART_SR_REG, + UART_SR_RXNE_Msk, + UART_SR_RXNE_Msk, cfg->timeout); + if (err) + return err; + + /* Read received byte */ + whal_Reg_Get(reg->base, UART_DR_REG, + UART_DR_Msk, UART_DR_Pos, &d); + + buf[i] = d; + } + + return WHAL_SUCCESS; +} + +const whal_UartDriver whal_Stm32f4Uart_Driver = { + .Init = whal_Stm32f4Uart_Init, + .Deinit = whal_Stm32f4Uart_Deinit, + .Send = whal_Stm32f4Uart_Send, + .Recv = whal_Stm32f4Uart_Recv, +}; diff --git a/wolfHAL/clock/stm32f4_rcc.h b/wolfHAL/clock/stm32f4_rcc.h new file mode 100644 index 0000000..fa8fe13 --- /dev/null +++ b/wolfHAL/clock/stm32f4_rcc.h @@ -0,0 +1,163 @@ +#ifndef WHAL_STM32F4_RCC_H +#define WHAL_STM32F4_RCC_H + +#include +#include +#include + +/* + * @file stm32f4_rcc.h + * @brief STM32F4 RCC (Reset and Clock Control) driver configuration. + * + * The STM32F4 RCC peripheral controls: + * - System clock source selection (HSI, HSE, PLL) + * - PLL configuration (M, N, P, Q dividers) + * - Peripheral clock gating (AHB1, APB1, APB2 buses) + * - Bus clock prescalers + * + * PLL output frequency: + * f_vco = (f_input / PLLM) * PLLN + * f_pll = f_vco / PLLP + * f_usb = f_vco / PLLQ + * + * One driver variant is provided: + * - whal_Stm32f4RccPll_Driver: Uses PLL as system clock source + */ + +/* + * @brief System clock source selection. + * + * Determines which oscillator/PLL drives the system clock (SYSCLK). + */ +typedef enum { + WHAL_STM32F4_RCC_SYSCLK_SRC_HSI, /* 16 MHz High-Speed Internal */ + WHAL_STM32F4_RCC_SYSCLK_SRC_HSE, /* High-Speed External crystal */ + WHAL_STM32F4_RCC_SYSCLK_SRC_PLL, /* PLL output */ +} whal_Stm32f4Rcc_SysClockSrc; + +/* + * @brief PLL input clock source selection. + * + * Bit 22 of RCC_PLLCFGR selects the PLL input. + */ +typedef enum { + WHAL_STM32F4_RCC_PLLCLK_SRC_HSI, /* HSI (16 MHz) as PLL input */ + WHAL_STM32F4_RCC_PLLCLK_SRC_HSE, /* HSE as PLL input */ +} whal_Stm32f4Rcc_PllClockSrc; + +/* + * @brief PLL configuration parameters. + * + * The PLL output frequency is calculated as: + * f_vco = (f_input / m) * n + * f_pll = f_vco / p (main PLL output, used for SYSCLK) + * f_usb = f_vco / q (used for USB OTG FS, SDIO) + * + * Constraints: + * - m: 2-63 (VCO input should be 1-2 MHz) + * - n: 50-432 (VCO output must be 100-432 MHz) + * - p: 2, 4, 6, or 8 (register value 0-3 maps to 2/4/6/8) + * - q: 2-15 (USB OTG FS requires 48 MHz) + */ +typedef struct whal_Stm32f4Rcc_PllClkCfg { + whal_Stm32f4Rcc_PllClockSrc clkSrc; /* PLL input source */ + uint16_t n; /* PLLN multiplier (50-432) */ + uint8_t m; /* PLLM divider (2-63) */ + uint8_t p; /* PLLP divider (0=div2, 1=div4, 2=div6, 3=div8) */ + uint8_t q; /* PLLQ divider (2-15) */ +} whal_Stm32f4Rcc_PllClkCfg; + +/* + * @brief Peripheral clock enable descriptor. + * + * Describes the register offset and bit mask needed to enable/disable + * a peripheral's bus clock. Used with whal_Stm32f4Rcc_Enable/Disable. + * + * Example for GPIOA: + * { .regOffset = 0x030, .enableMask = (1 << 0), .enablePos = 0 } + */ +typedef struct whal_Stm32f4Rcc_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_Stm32f4Rcc_Clk; + +/* + * @brief RCC driver configuration. + * + * Contains all parameters needed to configure the system clock. + */ +typedef struct whal_Stm32f4Rcc_Cfg { + whal_Stm32f4Rcc_SysClockSrc sysClkSrc; /* System clock source */ + void *sysClkCfg; /* Pointer to PllClkCfg based on driver */ + uint8_t ppre1; /* APB1 prescaler (0=/1, 4=/2, 5=/4, 6=/8, 7=/16) */ + uint8_t ppre2; /* APB2 prescaler (0=/1, 4=/2, 5=/4, 6=/8, 7=/16) */ +} whal_Stm32f4Rcc_Cfg; + +/* + * @brief Driver instance for the STM32F4 RCC PLL clock controller. + */ +extern const whal_ClockDriver whal_Stm32f4RccPll_Driver; + +/* + * @brief Initialize the RCC peripheral with PLL as system clock. + * + * Enables HSE if needed, configures PLL with the parameters in the + * device configuration, enables PLL, and switches SYSCLK to PLL output. + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4RccPll_Init(whal_Clock *clkDev); + +/* + * @brief Deinitialize the RCC peripheral from PLL mode. + * + * Switches SYSCLK back to HSI and disables PLL. + * + * @param clkDev Clock device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4RccPll_Deinit(whal_Clock *clkDev); + +/* + * @brief Enable a peripheral clock gate. + * + * @param clkDev Clock device instance. + * @param clk Pointer to a whal_Stm32f4Rcc_Clk descriptor. + * + * @retval WHAL_SUCCESS Clock enabled. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Rcc_Enable(whal_Clock *clkDev, const void *clk); + +/* + * @brief Disable a peripheral clock gate. + * + * @param clkDev Clock device instance. + * @param clk Pointer to a whal_Stm32f4Rcc_Clk descriptor. + * + * @retval WHAL_SUCCESS Clock disabled. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Rcc_Disable(whal_Clock *clkDev, const void *clk); + +/* + * @brief Compute the current system clock rate (PLL mode). + * + * Calculates the PLL 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_Stm32f4RccPll_GetRate(whal_Clock *clkDev, size_t *rateOut); + +#endif /* WHAL_STM32F4_RCC_H */ diff --git a/wolfHAL/flash/stm32f4_flash.h b/wolfHAL/flash/stm32f4_flash.h new file mode 100644 index 0000000..8002958 --- /dev/null +++ b/wolfHAL/flash/stm32f4_flash.h @@ -0,0 +1,174 @@ +#ifndef WHAL_STM32F4_FLASH_H +#define WHAL_STM32F4_FLASH_H + +#include +#include + +/* + * @file stm32f4_flash.h + * @brief STM32F4 flash driver configuration. + * + * The STM32F4 embedded flash provides: + * - Up to 512 KB organized in variable-size sectors + * - Byte, half-word, word, and double-word programming + * - Sector erase and mass erase operations + * - Configurable wait states based on CPU frequency and voltage + * + * Sector layout for STM32F411xE (512 KB): + * Sectors 0-3: 16 KB each + * Sector 4: 64 KB + * Sectors 5-7: 128 KB each + * + * Flash must be unlocked before write/erase operations and locked + * afterward for protection. + */ + +/* + * @brief Flash sector descriptor. + * + * Describes a flash sector's base address and size for the sector-based + * erase mechanism used by the STM32F4 flash controller. + */ +typedef struct whal_Stm32f4Flash_Sector { + size_t addr; /* Sector base address */ + size_t size; /* Sector size in bytes */ +} whal_Stm32f4Flash_Sector; + +/* + * @brief Flash device configuration. + */ +typedef struct whal_Stm32f4Flash_Cfg { + size_t startAddr; /* Flash base address (0x08000000) */ + size_t size; /* Flash size in bytes */ + const whal_Stm32f4Flash_Sector *sectors; /* Sector descriptor array */ + size_t sectorCount; /* Number of sectors */ + whal_Timeout *timeout; +} whal_Stm32f4Flash_Cfg; + +/* + * @brief Flash access latency (wait states). + * + * At 2.7-3.6V supply: + * 0 WS: up to 30 MHz + * 1 WS: up to 64 MHz + * 2 WS: up to 90 MHz + * 3 WS: up to 100 MHz + */ +typedef enum whal_Stm32f4Flash_Latency { + WHAL_STM32F4_FLASH_LATENCY_0, /* 0 wait states */ + WHAL_STM32F4_FLASH_LATENCY_1, /* 1 wait state */ + WHAL_STM32F4_FLASH_LATENCY_2, /* 2 wait states */ + WHAL_STM32F4_FLASH_LATENCY_3, /* 3 wait states */ +} whal_Stm32f4Flash_Latency; + +/* + * @brief Driver instance for STM32F4 flash. + */ +extern const whal_FlashDriver whal_Stm32f4Flash_Driver; + +/* + * @brief Initialize the STM32F4 flash interface. + * + * @param flashDev Flash device instance. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Flash_Init(whal_Flash *flashDev); + +/* + * @brief Deinitialize the STM32F4 flash interface. + * + * @param flashDev Flash device instance. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Flash_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_Stm32f4Flash_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_Stm32f4Flash_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_Stm32f4Flash_Read(whal_Flash *flashDev, size_t addr, + uint8_t *data, size_t dataSz); + +/* + * @brief Write data to flash. + * + * Data is programmed in 32-bit word chunks. Address and size must be + * 4-byte aligned. + * + * @param flashDev Flash device instance. + * @param addr Flash address to program (4-byte aligned). + * @param data Buffer to program. + * @param dataSz Number of bytes to program (multiple of 4). + * + * @retval WHAL_SUCCESS Program completed. + * @retval WHAL_EINVAL Invalid arguments or alignment. + * @retval WHAL_EHARDWARE Flash error during programming. + */ +whal_Error whal_Stm32f4Flash_Write(whal_Flash *flashDev, size_t addr, + const uint8_t *data, size_t dataSz); + +/* + * @brief Erase flash sectors covering the given range. + * + * Erases variable-size 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_Stm32f4Flash_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_Stm32f4Flash_Ext_SetLatency(whal_Flash *flashDev, + enum whal_Stm32f4Flash_Latency latency); + +#endif /* WHAL_STM32F4_FLASH_H */ diff --git a/wolfHAL/gpio/stm32f4_gpio.h b/wolfHAL/gpio/stm32f4_gpio.h new file mode 100644 index 0000000..be6564c --- /dev/null +++ b/wolfHAL/gpio/stm32f4_gpio.h @@ -0,0 +1,65 @@ +#ifndef WHAL_STM32F4_GPIO_H +#define WHAL_STM32F4_GPIO_H + +/* + * @file stm32f4_gpio.h + * @brief STM32F4 GPIO driver (alias for STM32WB GPIO). + * + * The STM32F4 GPIO peripheral is register-compatible with the STM32WB GPIO. + * This header re-exports the STM32WB GPIO driver types and symbols under + * STM32F4-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbGpio_Cfg whal_Stm32f4Gpio_Cfg; +typedef whal_Stm32wbGpio_PinCfg whal_Stm32f4Gpio_PinCfg; + +#define whal_Stm32f4Gpio_Driver whal_Stm32wbGpio_Driver +#define whal_Stm32f4Gpio_Init whal_Stm32wbGpio_Init +#define whal_Stm32f4Gpio_Deinit whal_Stm32wbGpio_Deinit +#define whal_Stm32f4Gpio_Get whal_Stm32wbGpio_Get +#define whal_Stm32f4Gpio_Set whal_Stm32wbGpio_Set + +/* + * @brief GPIO mode selection (re-exported from STM32WB). + */ +#define WHAL_STM32F4_GPIO_MODE_IN WHAL_STM32WB_GPIO_MODE_IN +#define WHAL_STM32F4_GPIO_MODE_OUT WHAL_STM32WB_GPIO_MODE_OUT +#define WHAL_STM32F4_GPIO_MODE_ALTFN WHAL_STM32WB_GPIO_MODE_ALTFN +#define WHAL_STM32F4_GPIO_MODE_ANALOG WHAL_STM32WB_GPIO_MODE_ANALOG + +/* + * @brief GPIO output type (re-exported from STM32WB). + */ +#define WHAL_STM32F4_GPIO_OUTTYPE_PUSHPULL WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL +#define WHAL_STM32F4_GPIO_OUTTYPE_OPENDRAIN WHAL_STM32WB_GPIO_OUTTYPE_OPENDRAIN + +/* + * @brief GPIO speed selection (re-exported from STM32WB). + */ +#define WHAL_STM32F4_GPIO_SPEED_LOW WHAL_STM32WB_GPIO_SPEED_LOW +#define WHAL_STM32F4_GPIO_SPEED_MEDIUM WHAL_STM32WB_GPIO_SPEED_MEDIUM +#define WHAL_STM32F4_GPIO_SPEED_FAST WHAL_STM32WB_GPIO_SPEED_FAST +#define WHAL_STM32F4_GPIO_SPEED_HIGH WHAL_STM32WB_GPIO_SPEED_HIGH + +/* + * @brief GPIO pull-up/pull-down selection (re-exported from STM32WB). + */ +#define WHAL_STM32F4_GPIO_PULL_NONE WHAL_STM32WB_GPIO_PULL_NONE +#define WHAL_STM32F4_GPIO_PULL_UP WHAL_STM32WB_GPIO_PULL_UP +#define WHAL_STM32F4_GPIO_PULL_DOWN WHAL_STM32WB_GPIO_PULL_DOWN + +/* + * @brief GPIO port selection (re-exported from STM32WB). + */ +#define WHAL_STM32F4_GPIO_PORT_A WHAL_STM32WB_GPIO_PORT_A +#define WHAL_STM32F4_GPIO_PORT_B WHAL_STM32WB_GPIO_PORT_B +#define WHAL_STM32F4_GPIO_PORT_C WHAL_STM32WB_GPIO_PORT_C +#define WHAL_STM32F4_GPIO_PORT_D WHAL_STM32WB_GPIO_PORT_D +#define WHAL_STM32F4_GPIO_PORT_E WHAL_STM32WB_GPIO_PORT_E +#define WHAL_STM32F4_GPIO_PORT_F WHAL_STM32WB_GPIO_PORT_F +#define WHAL_STM32F4_GPIO_PORT_G WHAL_STM32WB_GPIO_PORT_G +#define WHAL_STM32F4_GPIO_PORT_H WHAL_STM32WB_GPIO_PORT_H + +#endif /* WHAL_STM32F4_GPIO_H */ diff --git a/wolfHAL/platform/st/stm32f411xx.h b/wolfHAL/platform/st/stm32f411xx.h new file mode 100644 index 0000000..1b36b7c --- /dev/null +++ b/wolfHAL/platform/st/stm32f411xx.h @@ -0,0 +1,160 @@ +#ifndef WHAL_STM32F411XX_H +#define WHAL_STM32F411XX_H + +#include + +#include +#include +#include +#include +#include + +/* + * @file stm32f411xx.h + * @brief Convenience initializers for STM32F411xx device instances. + * + * Base addresses from RM0383 Table 1 (memory map). + * RCC: 0x40023800 + * GPIO: 0x40020000 (port A), 0x400 spacing per port + * USART1: 0x40011000 + * USART2: 0x40004400 + * USART6: 0x40011400 + * SPI1: 0x40013000 + * SPI2: 0x40003800 + * SPI3: 0x40003C00 + * Flash interface: 0x40023C00 + * SysTick: ARM core peripheral (0xE000E010) + */ + +/* --- Device macros --- */ + +#define WHAL_STM32F411_RCC_PLL_DEVICE \ + .regmap = { \ + .base = 0x40023800, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32f4RccPll_Driver + +#define WHAL_STM32F411_GPIO_DEVICE \ + .regmap = { \ + .base = 0x40020000, \ + .size = 0x2000, \ + }, \ + .driver = &whal_Stm32f4Gpio_Driver + +#define WHAL_STM32F411_USART1_DEVICE \ + .regmap = { \ + .base = 0x40011000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32f4Uart_Driver + +#define WHAL_STM32F411_USART2_DEVICE \ + .regmap = { \ + .base = 0x40004400, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32f4Uart_Driver + +#define WHAL_STM32F411_USART6_DEVICE \ + .regmap = { \ + .base = 0x40011400, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32f4Uart_Driver + +/* --- Clock gate macros --- */ +/* RCC_AHB1ENR (offset 0x030) */ + +#define WHAL_STM32F411_GPIOA_CLOCK \ + .regOffset = 0x030, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32F411_GPIOB_CLOCK \ + .regOffset = 0x030, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +#define WHAL_STM32F411_GPIOC_CLOCK \ + .regOffset = 0x030, \ + .enableMask = (1UL << 2), \ + .enablePos = 2 + +#define WHAL_STM32F411_GPIOD_CLOCK \ + .regOffset = 0x030, \ + .enableMask = (1UL << 3), \ + .enablePos = 3 + +#define WHAL_STM32F411_GPIOE_CLOCK \ + .regOffset = 0x030, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32F411_GPIOH_CLOCK \ + .regOffset = 0x030, \ + .enableMask = (1UL << 7), \ + .enablePos = 7 + +/* RCC_APB1ENR (offset 0x040) */ + +#define WHAL_STM32F411_USART2_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +/* RCC_APB2ENR (offset 0x044) */ + +#define WHAL_STM32F411_USART1_CLOCK \ + .regOffset = 0x044, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32F411_USART6_CLOCK \ + .regOffset = 0x044, \ + .enableMask = (1UL << 5), \ + .enablePos = 5 + +#define WHAL_STM32F411_SPI1_CLOCK \ + .regOffset = 0x044, \ + .enableMask = (1UL << 12), \ + .enablePos = 12 + +/* RCC_APB1ENR (offset 0x040) */ + +#define WHAL_STM32F411_SPI2_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +#define WHAL_STM32F411_SPI3_CLOCK \ + .regOffset = 0x040, \ + .enableMask = (1UL << 15), \ + .enablePos = 15 + +/* SPI device macros */ + +#define WHAL_STM32F411_SPI1_DEVICE \ + .regmap = { \ + .base = 0x40013000, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32f4Spi_Driver + +#define WHAL_STM32F411_SPI2_DEVICE \ + .regmap = { \ + .base = 0x40003800, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32f4Spi_Driver + +/* Flash device macros */ + +#define WHAL_STM32F411_FLASH_DEVICE \ + .regmap = { \ + .base = 0x40023C00, \ + .size = 0x400, \ + }, \ + .driver = &whal_Stm32f4Flash_Driver + +#endif /* WHAL_STM32F411XX_H */ diff --git a/wolfHAL/spi/stm32f4_spi.h b/wolfHAL/spi/stm32f4_spi.h new file mode 100644 index 0000000..990f30b --- /dev/null +++ b/wolfHAL/spi/stm32f4_spi.h @@ -0,0 +1,101 @@ +#ifndef WHAL_STM32F4_SPI_H +#define WHAL_STM32F4_SPI_H + +#include +#include +#include +#include + +/* + * @file stm32f4_spi.h + * @brief STM32F4 SPI driver configuration. + * + * The STM32F4 SPI peripheral provides: + * - Full-duplex synchronous serial communication + * - Master and slave modes (this driver supports master only) + * - Configurable clock polarity and phase (SPI modes 0-3) + * - Programmable baud rate prescaler (fPCLK/2 to fPCLK/256) + * - 8 or 16-bit data frame (DFF bit in CR1) + * - Software slave management (chip select via GPIO) + * + * Unlike the STM32WB SPI which has a configurable data size (DS) field + * in CR2 and FIFO threshold (FRXTH), the STM32F4 uses a single DFF bit + * in CR1 for 8/16-bit selection. + */ + +/* + * @brief SPI device configuration. + */ +typedef struct whal_Stm32f4Spi_Cfg { + uint32_t pclk; /* Peripheral clock frequency in Hz */ + whal_Timeout *timeout; +} whal_Stm32f4Spi_Cfg; + +/* + * @brief Driver instance for STM32F4 SPI peripheral. + */ +extern const whal_SpiDriver whal_Stm32f4Spi_Driver; + +/* + * @brief Initialize the STM32F4 SPI peripheral. + * + * @param spiDev SPI device instance to initialize. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Spi_Init(whal_Spi *spiDev); + +/* + * @brief Deinitialize the STM32F4 SPI peripheral. + * + * @param spiDev SPI device instance to deinitialize. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Spi_Deinit(whal_Spi *spiDev); + +/* + * @brief Begin a communication session on the STM32F4 SPI peripheral. + * + * Configures clock polarity, phase, baud rate, and data frame format + * from comCfg, then enables the peripheral. + * + * @param spiDev SPI device instance. + * @param comCfg Per-session communication parameters. + * + * @retval WHAL_SUCCESS Communication session started. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Spi_StartCom(whal_Spi *spiDev, whal_Spi_ComCfg *comCfg); + +/* + * @brief End the current communication session on the STM32F4 SPI peripheral. + * + * Disables SPE. + * + * @param spiDev SPI device instance. + * + * @retval WHAL_SUCCESS Communication session ended. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Spi_EndCom(whal_Spi *spiDev); + +/* + * @brief Perform a full-duplex SPI transfer. + * + * @param spiDev SPI device instance. + * @param tx Data to transmit (may be NULL). + * @param txLen Number of bytes to transmit. + * @param rx Receive buffer (may be NULL). + * @param rxLen Number of bytes to receive. + * + * @retval WHAL_SUCCESS Transfer completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Spi_SendRecv(whal_Spi *spiDev, + const uint8_t *tx, size_t txLen, + uint8_t *rx, size_t rxLen); + +#endif /* WHAL_STM32F4_SPI_H */ diff --git a/wolfHAL/uart/stm32f4_uart.h b/wolfHAL/uart/stm32f4_uart.h new file mode 100644 index 0000000..bc123f8 --- /dev/null +++ b/wolfHAL/uart/stm32f4_uart.h @@ -0,0 +1,94 @@ +#ifndef WHAL_STM32F4_UART_H +#define WHAL_STM32F4_UART_H + +#include +#include +#include +#include + +/* + * @file stm32f4_uart.h + * @brief STM32F4 UART driver configuration. + * + * The STM32F4 USART uses the older USARTv1 register layout with + * SR (Status Register) and DR (Data Register) at offsets 0x00 and 0x04, + * which differs from the USARTv2 ISR/TDR/RDR layout used by STM32WB/H5. + * + * Register layout: + * SR at 0x00 - Status register (TXE, RXNE, TC flags) + * DR at 0x04 - Data register (shared TX/RX) + * BRR at 0x08 - Baud rate register + * CR1 at 0x0C - Control register 1 (UE, TE, RE) + * CR2 at 0x10 - Control register 2 + * CR3 at 0x14 - Control register 3 + */ + +/* + * @brief Compute UART BRR register value for STM32F4. + * + * For oversampling by 16 (OVER8=0): + * BRR = fPCLK / baudrate + * + * @param clk Peripheral clock frequency in Hz. + * @param baud Desired baud rate. + */ +#define WHAL_STM32F4_UART_BRR(clk, baud) ((clk) / (baud)) + +/* + * @brief STM32F4 UART configuration parameters. + */ +typedef struct whal_Stm32f4Uart_Cfg { + uint32_t brr; + whal_Timeout *timeout; +} whal_Stm32f4Uart_Cfg; + +/* + * @brief Driver instance for STM32F4 UART peripheral. + */ +extern const whal_UartDriver whal_Stm32f4Uart_Driver; + +/* + * @brief Initialize the STM32F4 UART peripheral. + * + * @param uartDev UART device instance to initialize. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Uart_Init(whal_Uart *uartDev); + +/* + * @brief Deinitialize the STM32F4 UART peripheral. + * + * @param uartDev UART device instance to deinitialize. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Uart_Deinit(whal_Uart *uartDev); + +/* + * @brief Transmit a buffer over UART. + * + * @param uartDev UART device instance. + * @param data Buffer to transmit. + * @param dataSz Number of bytes to transmit. + * + * @retval WHAL_SUCCESS Transfer completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Uart_Send(whal_Uart *uartDev, const void *data, size_t dataSz); + +/* + * @brief Receive a buffer over UART. + * + * @param uartDev UART device instance. + * @param data Receive buffer. + * @param dataSz Number of bytes to receive. + * + * @retval WHAL_SUCCESS Transfer completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32f4Uart_Recv(whal_Uart *uartDev, void *data, size_t dataSz); + +#endif /* WHAL_STM32F4_UART_H */