From 620a21cc40e00cbfaa81f1cb7a823189ff18f193 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Wed, 22 Apr 2026 22:03:02 -0400 Subject: [PATCH] [stm32l1] Implement initial support for stm32l1 --- .github/workflows/boards.yml | 2 +- boards/README.md | 1 + boards/stm32c031_nucleo/board.h | 2 - boards/stm32f091rc_nucleo/board.h | 2 - boards/stm32f302r8_nucleo/board.h | 2 - boards/stm32l152re_nucleo/Makefile.inc | 43 +++ boards/stm32l152re_nucleo/board.c | 332 ++++++++++++++++++++ boards/stm32l152re_nucleo/board.h | 44 +++ boards/stm32l152re_nucleo/ivt.c | 207 ++++++++++++ boards/stm32l152re_nucleo/linker.ld | 121 +++++++ boards/stm32wb55xx_nucleo/board.h | 2 - boards/stm32wba55cg_nucleo/board.h | 2 - src/clock/stm32l1_rcc.c | 285 +++++++++++++++++ src/flash/stm32l1_flash.c | 328 +++++++++++++++++++ src/gpio/stm32l1_gpio.c | 1 + src/gpio/stm32wb_gpio.c | 6 +- src/i2c/stm32l1_i2c.c | 418 +++++++++++++++++++++++++ src/spi/stm32f4_spi.c | 8 +- src/spi/stm32l1_spi.c | 1 + src/supply/stm32l1_pwr.c | 72 +++++ src/uart/stm32f4_uart.c | 8 +- src/uart/stm32l1_uart.c | 1 + src/watchdog/stm32f0_wwdg.c | 6 +- src/watchdog/stm32l1_iwdg.c | 1 + src/watchdog/stm32l1_wwdg.c | 1 + src/watchdog/stm32wb_iwdg.c | 6 +- tests/flash/test_flash.c | 67 +--- tests/gpio/test_stm32l1_gpio.c | 1 + tests/gpio/test_stm32wb_gpio.c | 38 ++- tests/test.h | 16 + wolfHAL/clock/stm32l1_rcc.h | 118 +++++++ wolfHAL/flash/stm32l1_flash.h | 77 +++++ wolfHAL/gpio/stm32l1_gpio.h | 54 ++++ wolfHAL/i2c/stm32l1_i2c.h | 105 +++++++ wolfHAL/platform/arm/cortex_m3.h | 17 + wolfHAL/platform/st/stm32l152re.h | 272 ++++++++++++++++ wolfHAL/spi/stm32l1_spi.h | 25 ++ wolfHAL/supply/stm32l1_pwr.h | 79 +++++ wolfHAL/uart/stm32l1_uart.h | 28 ++ wolfHAL/watchdog/stm32l1_iwdg.h | 30 ++ wolfHAL/watchdog/stm32l1_wwdg.h | 23 ++ 41 files changed, 2762 insertions(+), 90 deletions(-) create mode 100644 boards/stm32l152re_nucleo/Makefile.inc create mode 100644 boards/stm32l152re_nucleo/board.c create mode 100644 boards/stm32l152re_nucleo/board.h create mode 100644 boards/stm32l152re_nucleo/ivt.c create mode 100644 boards/stm32l152re_nucleo/linker.ld create mode 100644 src/clock/stm32l1_rcc.c create mode 100644 src/flash/stm32l1_flash.c create mode 100644 src/gpio/stm32l1_gpio.c create mode 100644 src/i2c/stm32l1_i2c.c create mode 100644 src/spi/stm32l1_spi.c create mode 100644 src/supply/stm32l1_pwr.c create mode 100644 src/uart/stm32l1_uart.c create mode 100644 src/watchdog/stm32l1_iwdg.c create mode 100644 src/watchdog/stm32l1_wwdg.c create mode 100644 tests/gpio/test_stm32l1_gpio.c create mode 100644 wolfHAL/clock/stm32l1_rcc.h create mode 100644 wolfHAL/flash/stm32l1_flash.h create mode 100644 wolfHAL/gpio/stm32l1_gpio.h create mode 100644 wolfHAL/i2c/stm32l1_i2c.h create mode 100644 wolfHAL/platform/arm/cortex_m3.h create mode 100644 wolfHAL/platform/st/stm32l152re.h create mode 100644 wolfHAL/spi/stm32l1_spi.h create mode 100644 wolfHAL/supply/stm32l1_pwr.h create mode 100644 wolfHAL/uart/stm32l1_uart.h create mode 100644 wolfHAL/watchdog/stm32l1_iwdg.h create mode 100644 wolfHAL/watchdog/stm32l1_wwdg.h diff --git a/.github/workflows/boards.yml b/.github/workflows/boards.yml index 2ebc41b..a951546 100644 --- a/.github/workflows/boards.yml +++ b/.github/workflows/boards.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - board: [stm32wb55xx_nucleo, stm32wba55cg_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo, stm32f091rc_nucleo, stm32f302r8_nucleo] + board: [stm32wb55xx_nucleo, stm32wba55cg_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo, stm32f091rc_nucleo, stm32f302r8_nucleo, stm32l152re_nucleo] extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"] include: - board: stm32wb55xx_nucleo diff --git a/boards/README.md b/boards/README.md index 2d0b3e3..75902bb 100644 --- a/boards/README.md +++ b/boards/README.md @@ -21,6 +21,7 @@ build configuration. | WeAct BlackPill STM32F411 | STM32F4 | Cortex-M4 | `stm32f411_blackpill/` | | ST NUCLEO-H563ZI | STM32H5 | Cortex-M33 | `stm32h563zi_nucleo/` | | ST NUCLEO-WB55RG | STM32WB | Cortex-M4 | `stm32wb55xx_nucleo/` | +| ST NUCLEO-L152RE | STM32L1 | Cortex-M3 | `stm32l152re_nucleo/` | | ST NUCLEO-WBA55CG | STM32WBA | Cortex-M33 | `stm32wba55cg_nucleo/` | ## Board Directory Contents diff --git a/boards/stm32c031_nucleo/board.h b/boards/stm32c031_nucleo/board.h index 68d6678..d504dc0 100644 --- a/boards/stm32c031_nucleo/board.h +++ b/boards/stm32c031_nucleo/board.h @@ -26,8 +26,6 @@ enum { }; #define BOARD_LED_PIN 0 -#define BOARD_LED_PORT_OFFSET 0x000 /* GPIOA */ -#define BOARD_LED_PIN_NUM 5 #define BOARD_FLASH_START_ADDR 0x08000000 #define BOARD_FLASH_SIZE 0x8000 diff --git a/boards/stm32f091rc_nucleo/board.h b/boards/stm32f091rc_nucleo/board.h index f35c752..9cf108e 100644 --- a/boards/stm32f091rc_nucleo/board.h +++ b/boards/stm32f091rc_nucleo/board.h @@ -31,8 +31,6 @@ enum { }; #define BOARD_LED_PIN 0 -#define BOARD_LED_PORT_OFFSET 0x000 /* GPIOA */ -#define BOARD_LED_PIN_NUM 5 #define BOARD_FLASH_START_ADDR 0x08000000 #define BOARD_FLASH_SIZE 0x40000 diff --git a/boards/stm32f302r8_nucleo/board.h b/boards/stm32f302r8_nucleo/board.h index 01469c0..346ffb3 100644 --- a/boards/stm32f302r8_nucleo/board.h +++ b/boards/stm32f302r8_nucleo/board.h @@ -31,8 +31,6 @@ enum { }; #define BOARD_LED_PIN 0 -#define BOARD_LED_PORT_OFFSET 0x400 /* GPIOB */ -#define BOARD_LED_PIN_NUM 13 #define BOARD_FLASH_START_ADDR 0x08000000 #define BOARD_FLASH_SIZE 0x10000 diff --git a/boards/stm32l152re_nucleo/Makefile.inc b/boards/stm32l152re_nucleo/Makefile.inc new file mode 100644 index 0000000..e8a2bdd --- /dev/null +++ b/boards/stm32l152re_nucleo/Makefile.inc @@ -0,0 +1,43 @@ +_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST)))) + +PLATFORM = stm32l1 +TESTS ?= clock gpio timer flash uart spi i2c + +GCC = $(GCC_PATH)arm-none-eabi-gcc +LD = $(GCC_PATH)arm-none-eabi-gcc +OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy + +CFLAGS += -Wall -Werror $(INCLUDE) -g3 \ + -ffreestanding -nostdlib \ + -mcpu=cortex-m3 -mthumb \ + -DPLATFORM_STM32L1 -MMD -MP \ + -DWHAL_CFG_GPIO_API_MAPPING_STM32L1 \ + -DWHAL_CFG_CLOCK_API_MAPPING_STM32L1 \ + -DWHAL_CFG_UART_API_MAPPING_STM32L1 \ + -DWHAL_CFG_SPI_API_MAPPING_STM32L1 \ + -DWHAL_CFG_I2C_API_MAPPING_STM32L1 \ + $(if $(filter iwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_IWDG) \ + $(if $(filter wwdg,$(WATCHDOG)),-DBOARD_WATCHDOG_WWDG) +LDFLAGS = -mcpu=cortex-m3 -mthumb \ + -ffreestanding -nostartfiles -Wl,--omagic -static + +LINKER_SCRIPT ?= $(_BOARD_DIR)/linker.ld + +INCLUDE += -I$(_BOARD_DIR) -I$(WHAL_DIR)/boards/peripheral + +BOARD_SOURCE = $(_BOARD_DIR)/ivt.c +BOARD_SOURCE += $(_BOARD_DIR)/board.c +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/timer.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/supply.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/flash.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/sensor.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/block.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/watchdog.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32l1_*.c) +BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c) + +# Peripheral devices +include $(WHAL_DIR)/boards/peripheral/Makefile.inc diff --git a/boards/stm32l152re_nucleo/board.c b/boards/stm32l152re_nucleo/board.c new file mode 100644 index 0000000..c5ec4c7 --- /dev/null +++ b/boards/stm32l152re_nucleo/board.c @@ -0,0 +1,332 @@ +#include +#include +#include "board.h" +#include +#include "peripheral.h" + +volatile uint32_t g_tick = 0; +volatile uint8_t g_waiting = 0; +volatile uint8_t g_tickOverflow = 0; + +void SysTick_Handler() +{ + uint32_t tickBefore = g_tick++; + if (g_waiting) { + if (tickBefore > g_tick) + g_tickOverflow = 1; + } +} + +uint32_t Board_GetTick(void) +{ + return g_tick; +} + +whal_Timeout g_whalTimeout = { + .timeoutTicks = 1000, + .GetTick = Board_GetTick, +}; + +/* + * Clock -- PLL at 32 MHz (HSI 16 MHz * 4 / 2) + * + * PLLVCO = HSI * PLLMUL = 16 MHz * 4 = 64 MHz + * SYSCLK = PLLVCO / PLLDIV = 64 MHz / 2 = 32 MHz + */ +whal_Clock g_whalClock = { + .regmap = { WHAL_STM32L152_RCC_REGMAP }, + + .cfg = &(whal_Stm32l1Rcc_Cfg) { + .sysClkSrc = WHAL_STM32L1_RCC_SYSCLK_SRC_PLL, + .pllCfg = &(whal_Stm32l1Rcc_PllCfg) { + .clkSrc = WHAL_STM32L1_RCC_PLLSRC_HSI, + .pllmul = WHAL_STM32L1_RCC_PLLMUL_4, + .plldiv = WHAL_STM32L1_RCC_PLLDIV_2, + }, + }, +}; + +static const whal_Stm32l1Rcc_Clk g_pwrClock = {WHAL_STM32L152_PWR_CLOCK}; + +static const whal_Stm32l1Rcc_Clk g_clocks[] = { + {WHAL_STM32L152_GPIOA_CLOCK}, + {WHAL_STM32L152_GPIOB_CLOCK}, + {WHAL_STM32L152_GPIOC_CLOCK}, + {WHAL_STM32L152_USART2_CLOCK}, + {WHAL_STM32L152_SPI3_CLOCK}, + {WHAL_STM32L152_I2C1_CLOCK}, +#ifdef BOARD_WATCHDOG_WWDG + {WHAL_STM32L152_WWDG_CLOCK}, +#endif +}; +#define CLOCK_COUNT (sizeof(g_clocks) / sizeof(g_clocks[0])) + +/* PWR -- Range 1 (1.8 V) to allow SYSCLK up to 32 MHz. */ +whal_Supply g_whalSupply = { + .regmap = { WHAL_STM32L152_PWR_REGMAP }, + .driver = WHAL_STM32L152_PWR_DRIVER, + + .cfg = &(whal_Stm32l1Pwr_Cfg) { + .vosRange = WHAL_STM32L1_PWR_VOS_RANGE_1, + .timeout = &g_whalTimeout, + }, +}; + +/* GPIO */ +whal_Gpio g_whalGpio = { + .regmap = { WHAL_STM32L152_GPIO_REGMAP }, + + .cfg = &(whal_Stm32l1Gpio_Cfg) { + .pinCfg = (whal_Stm32l1Gpio_PinCfg[PIN_COUNT]) { + /* LD2 Green LED on PA5 (per UM1724, NUCLEO-L152RE) */ + [LED_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_A, 5, WHAL_STM32L1_GPIO_MODE_OUT, + WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32L1_GPIO_SPEED_LOW, + WHAL_STM32L1_GPIO_PULL_NONE, 0), + /* USART2 TX on PA2, AF7 */ + [UART_TX_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_A, 2, WHAL_STM32L1_GPIO_MODE_ALTFN, + WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_UP, 7), + /* USART2 RX on PA3, AF7 */ + [UART_RX_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_A, 3, WHAL_STM32L1_GPIO_MODE_ALTFN, + WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_UP, 7), + /* SPI3 SCK on PB3, AF6 (avoids LD2 conflict on PA5) */ + [SPI_SCK_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_B, 3, WHAL_STM32L1_GPIO_MODE_ALTFN, + WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_NONE, 6), + /* SPI3 MISO on PB4, AF6 */ + [SPI_MISO_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_B, 4, WHAL_STM32L1_GPIO_MODE_ALTFN, + WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_NONE, 6), + /* SPI3 MOSI on PB5, AF6 */ + [SPI_MOSI_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_B, 5, WHAL_STM32L1_GPIO_MODE_ALTFN, + WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_NONE, 6), + /* SPI CS on PB12, output, push-pull */ + [SPI_CS_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_B, 12, WHAL_STM32L1_GPIO_MODE_OUT, + WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_UP, 0), + /* I2C1 SCL on PB8, AF4, open-drain */ + [I2C_SCL_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_B, 8, WHAL_STM32L1_GPIO_MODE_ALTFN, + WHAL_STM32L1_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_UP, 4), + /* I2C1 SDA on PB9, AF4, open-drain */ + [I2C_SDA_PIN] = WHAL_STM32L1_GPIO_PIN( + WHAL_STM32L1_GPIO_PORT_B, 9, WHAL_STM32L1_GPIO_MODE_ALTFN, + WHAL_STM32L1_GPIO_OUTTYPE_OPENDRAIN, WHAL_STM32L1_GPIO_SPEED_FAST, + WHAL_STM32L1_GPIO_PULL_UP, 4), + }, + .pinCount = PIN_COUNT, + }, +}; + +/* Timer -- SysTick at 1 ms (32 MHz / 1000) */ +whal_Timer g_whalTimer = { + .regmap = { WHAL_CORTEX_M3_SYSTICK_REGMAP }, + .driver = WHAL_CORTEX_M3_SYSTICK_DRIVER, + + .cfg = &(whal_SysTick_Cfg) { + .cyclesPerTick = 32000000 / 1000, + .clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK, + .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, + }, +}; + +/* UART -- USART2 at 115200 baud */ +whal_Uart g_whalUart = { + .regmap = { WHAL_STM32L152_USART2_REGMAP }, + + .cfg = &(whal_Stm32l1Uart_Cfg) { + .timeout = &g_whalTimeout, + .brr = WHAL_STM32L1_UART_BRR(32000000, 115200), + }, +}; + +/* SPI -- SPI3 */ +whal_Spi g_whalSpi = { + .regmap = { WHAL_STM32L152_SPI3_REGMAP }, + + .cfg = &(whal_Stm32l1Spi_Cfg) { + .pclk = 32000000, + .timeout = &g_whalTimeout, + }, +}; + +/* I2C -- I2C1 */ +whal_I2c g_whalI2c = { + .regmap = { WHAL_STM32L152_I2C1_REGMAP }, + + .cfg = &(whal_Stm32l1I2c_Cfg) { + .pclk = 32000000, + .timeout = &g_whalTimeout, + }, +}; + +/* Flash -- 512 KB */ +whal_Flash g_whalFlash = { + .regmap = { WHAL_STM32L152_FLASH_REGMAP }, + .driver = WHAL_STM32L152_FLASH_DRIVER, + + .cfg = &(whal_Stm32l1Flash_Cfg) { + .startAddr = 0x08000000, + .size = 0x80000, + .timeout = &g_whalTimeout, + }, +}; + +#ifdef BOARD_WATCHDOG_IWDG +whal_Watchdog g_whalWatchdog = { + .regmap = { WHAL_STM32L152_IWDG_REGMAP }, + .driver = WHAL_STM32L152_IWDG_DRIVER, + + .cfg = &(whal_Stm32l1Iwdg_Cfg) { + .prescaler = WHAL_STM32L1_IWDG_PR_64, + .reload = 500, + .timeout = &g_whalTimeout, + }, +}; +#elif defined(BOARD_WATCHDOG_WWDG) +whal_Watchdog g_whalWatchdog = { + .regmap = { WHAL_STM32L152_WWDG_REGMAP }, + .driver = WHAL_STM32L152_WWDG_DRIVER, + + .cfg = &(whal_Stm32l1Wwdg_Cfg) { + .prescaler = 3, + .window = 0x7F, + .counter = 0x7F, + }, +}; +#endif + +void Board_WaitMs(size_t ms) +{ + uint32_t startCount = g_tick; + while ((g_tick - startCount) < ms) + ; +} + +whal_Error Board_Init(void) +{ + whal_Error err; + + /* Enable PWR peripheral clock so the supply driver can program VOS. + * The RCC device only uses regmap.base for clock gating, so calling + * Enable before Init is safe. */ + err = whal_Clock_Enable(&g_whalClock, &g_pwrClock); + if (err) + return err; + + /* Switch regulator to range 1 (1.8 V) so the PLL can reach 32 MHz. + * Reset default is range 2, which caps PLL VCO at 48 MHz and SYSCLK at + * 16 MHz. */ + err = whal_Supply_Init(&g_whalSupply); + if (err) + return err; + + /* Set flash latency before increasing clock speed. + * STM32L1: 0 WS for HCLK <= 16 MHz, 1 WS for 16 < HCLK <= 32 MHz. */ + err = whal_Stm32l1Flash_Ext_SetLatency(WHAL_STM32L1_FLASH_LATENCY_1); + if (err) + return err; + + err = whal_Clock_Init(&g_whalClock); + if (err) + return err; + + for (size_t i = 0; i < CLOCK_COUNT; i++) { + err = whal_Clock_Enable(&g_whalClock, &g_clocks[i]); + if (err) + return err; + } + + err = whal_Gpio_Init(&g_whalGpio); + if (err) + return err; + + err = whal_Uart_Init(&g_whalUart); + if (err) + return err; + + err = whal_Spi_Init(&g_whalSpi); + if (err) + return err; + + err = whal_I2c_Init(&g_whalI2c); + if (err) + return err; + + err = whal_Timer_Init(&g_whalTimer); + if (err) + return err; + + err = whal_Timer_Start(&g_whalTimer); + if (err) + return err; + + err = Peripheral_Init(); + if (err) + return err; + + return WHAL_SUCCESS; +} + +whal_Error Board_Deinit(void) +{ + whal_Error err; + + err = Peripheral_Deinit(); + if (err) + return err; + + err = whal_Timer_Stop(&g_whalTimer); + if (err) + return err; + + err = whal_Timer_Deinit(&g_whalTimer); + if (err) + return err; + + err = whal_Spi_Deinit(&g_whalSpi); + if (err) + return err; + + err = whal_I2c_Deinit(&g_whalI2c); + if (err) + return err; + + err = whal_Uart_Deinit(&g_whalUart); + if (err) + return err; + + err = whal_Gpio_Deinit(&g_whalGpio); + if (err) + return err; + + for (size_t i = 0; i < CLOCK_COUNT; i++) { + err = whal_Clock_Disable(&g_whalClock, &g_clocks[i]); + if (err) + return err; + } + + err = whal_Supply_Deinit(&g_whalSupply); + if (err) + return err; + + err = whal_Clock_Disable(&g_whalClock, &g_pwrClock); + if (err) + return err; + + err = whal_Clock_Deinit(&g_whalClock); + if (err) + return err; + + return WHAL_SUCCESS; +} diff --git a/boards/stm32l152re_nucleo/board.h b/boards/stm32l152re_nucleo/board.h new file mode 100644 index 0000000..665d431 --- /dev/null +++ b/boards/stm32l152re_nucleo/board.h @@ -0,0 +1,44 @@ +#ifndef BOARD_H +#define BOARD_H + +#include +#include +#include + +extern whal_Clock g_whalClock; +extern whal_Gpio g_whalGpio; +extern whal_Timer g_whalTimer; +extern whal_Uart g_whalUart; +extern whal_Spi g_whalSpi; +extern whal_I2c g_whalI2c; +extern whal_Flash g_whalFlash; +extern whal_Watchdog g_whalWatchdog; + +extern whal_Timeout g_whalTimeout; +extern volatile uint32_t g_tick; + +enum { + LED_PIN, + UART_TX_PIN, + UART_RX_PIN, + SPI_SCK_PIN, + SPI_MISO_PIN, + SPI_MOSI_PIN, + SPI_CS_PIN, + I2C_SCL_PIN, + I2C_SDA_PIN, + PIN_COUNT, +}; + +#define BOARD_LED_PIN 0 + +#define BOARD_FLASH_START_ADDR 0x08000000 +#define BOARD_FLASH_SIZE 0x80000 +#define BOARD_FLASH_TEST_ADDR 0x0807FF00 +#define BOARD_FLASH_SECTOR_SZ 0x100 + +whal_Error Board_Init(void); +whal_Error Board_Deinit(void); +void Board_WaitMs(size_t ms); + +#endif /* BOARD_H */ diff --git a/boards/stm32l152re_nucleo/ivt.c b/boards/stm32l152re_nucleo/ivt.c new file mode 100644 index 0000000..adac400 --- /dev/null +++ b/boards/stm32l152re_nucleo/ivt.c @@ -0,0 +1,207 @@ +#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"))); + +/* STM32L1xx peripheral interrupts (RM0038 Table 51, Cat.4/5/6) */ +void WWDG_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void PVD_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TAMPER_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_Channel1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel6_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA1_Channel7_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void ADC1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USB_HP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void USB_LP_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DAC_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void COMP_CA_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void EXTI9_5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void LCD_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM9_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM10_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void TIM11_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 USART3_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 USB_FS_WKUP_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 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 UART4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void UART5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Channel1_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Channel2_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Channel3_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Channel4_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void DMA2_Channel5_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void AES_IRQHandler() __attribute__((weak, noreturn, alias("Default_Handler"))); +void COMP_ACQ_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, + /* STM32L1xx peripheral interrupts (position 0-56) */ + WWDG_IRQHandler, /* 0 */ + PVD_IRQHandler, /* 1 */ + TAMPER_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_Channel1_IRQHandler, /* 11 */ + DMA1_Channel2_IRQHandler, /* 12 */ + DMA1_Channel3_IRQHandler, /* 13 */ + DMA1_Channel4_IRQHandler, /* 14 */ + DMA1_Channel5_IRQHandler, /* 15 */ + DMA1_Channel6_IRQHandler, /* 16 */ + DMA1_Channel7_IRQHandler, /* 17 */ + ADC1_IRQHandler, /* 18 */ + USB_HP_IRQHandler, /* 19 */ + USB_LP_IRQHandler, /* 20 */ + DAC_IRQHandler, /* 21 */ + COMP_CA_IRQHandler, /* 22 */ + EXTI9_5_IRQHandler, /* 23 */ + LCD_IRQHandler, /* 24 */ + TIM9_IRQHandler, /* 25 */ + TIM10_IRQHandler, /* 26 */ + TIM11_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 */ + USART3_IRQHandler, /* 39 */ + EXTI15_10_IRQHandler, /* 40 */ + RTC_Alarm_IRQHandler, /* 41 */ + USB_FS_WKUP_IRQHandler, /* 42 */ + TIM6_IRQHandler, /* 43 */ + TIM7_IRQHandler, /* 44 */ + SDIO_IRQHandler, /* 45 */ + TIM5_IRQHandler, /* 46 */ + SPI3_IRQHandler, /* 47 */ + UART4_IRQHandler, /* 48 */ + UART5_IRQHandler, /* 49 */ + DMA2_Channel1_IRQHandler, /* 50 */ + DMA2_Channel2_IRQHandler, /* 51 */ + DMA2_Channel3_IRQHandler, /* 52 */ + DMA2_Channel4_IRQHandler, /* 53 */ + DMA2_Channel5_IRQHandler, /* 54 */ + AES_IRQHandler, /* 55 */ + COMP_ACQ_IRQHandler, /* 56 */ +}; + +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/stm32l152re_nucleo/linker.ld b/boards/stm32l152re_nucleo/linker.ld new file mode 100644 index 0000000..e8a116b --- /dev/null +++ b/boards/stm32l152re_nucleo/linker.ld @@ -0,0 +1,121 @@ +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20014000; /* end of 80 KB RAM */ +/* Generate a link error if the stack don't fit into RAM */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K +RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 80K +} + +/* 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/stm32wb55xx_nucleo/board.h b/boards/stm32wb55xx_nucleo/board.h index 404c872..e3ae039 100644 --- a/boards/stm32wb55xx_nucleo/board.h +++ b/boards/stm32wb55xx_nucleo/board.h @@ -34,8 +34,6 @@ enum { }; #define BOARD_LED_PIN 0 -#define BOARD_LED_PORT_OFFSET 0x400 /* GPIOB */ -#define BOARD_LED_PIN_NUM 5 #define BOARD_FLASH_START_ADDR 0x08000000 #define BOARD_FLASH_SIZE 0x80000 /* 512 KB (upper half reserved for BLE stack) */ #define BOARD_FLASH_TEST_ADDR 0x0807F000 diff --git a/boards/stm32wba55cg_nucleo/board.h b/boards/stm32wba55cg_nucleo/board.h index a6068df..b520446 100644 --- a/boards/stm32wba55cg_nucleo/board.h +++ b/boards/stm32wba55cg_nucleo/board.h @@ -39,8 +39,6 @@ enum { /* LD2 (Green) on PA9 -- avoids conflict with SPI1_SCK on PB4 (LD1) */ #define BOARD_LED_PIN 0 -#define BOARD_LED_PORT_OFFSET 0x000 /* GPIOA */ -#define BOARD_LED_PIN_NUM 9 #define BOARD_FLASH_START_ADDR 0x08000000 #define BOARD_FLASH_SIZE 0x100000 /* 1 MB */ #define BOARD_FLASH_TEST_ADDR 0x080FE000 diff --git a/src/clock/stm32l1_rcc.c b/src/clock/stm32l1_rcc.c new file mode 100644 index 0000000..f58e5c5 --- /dev/null +++ b/src/clock/stm32l1_rcc.c @@ -0,0 +1,285 @@ +#include +#include +#include +#include +#include + +/* + * STM32L1 RCC register offsets and bit definitions. + * From RM0038 Section 6.3 (RCC registers). + * + * RCC_CR (0x00): + * Bit 0 HSION, Bit 1 HSIRDY + * Bit 8 MSION, Bit 9 MSIRDY + * Bit 16 HSEON, Bit 17 HSERDY + * Bit 24 PLLON, Bit 25 PLLRDY + * + * RCC_CFGR (0x08): + * Bits 1:0 SW (system clock switch) + * Bits 3:2 SWS (system clock switch status) + * Bits 7:4 HPRE (AHB prescaler) + * Bits 10:8 PPRE1 (APB1 prescaler) + * Bits 13:11 PPRE2 (APB2 prescaler) + * Bit 16 PLLSRC (0=HSI, 1=HSE) + * Bits 21:18 PLLMUL + * Bits 23:22 PLLDIV + */ + +#define RCC_CR_REG 0x00 +#define RCC_CR_HSION_Pos 0 +#define RCC_CR_HSION_Msk (1UL << RCC_CR_HSION_Pos) +#define RCC_CR_HSIRDY_Pos 1 +#define RCC_CR_HSIRDY_Msk (1UL << RCC_CR_HSIRDY_Pos) +#define RCC_CR_MSION_Pos 8 +#define RCC_CR_MSION_Msk (1UL << RCC_CR_MSION_Pos) +#define RCC_CR_MSIRDY_Pos 9 +#define RCC_CR_MSIRDY_Msk (1UL << RCC_CR_MSIRDY_Pos) +#define RCC_CR_HSEON_Pos 16 +#define RCC_CR_HSEON_Msk (1UL << RCC_CR_HSEON_Pos) +#define RCC_CR_HSERDY_Pos 17 +#define RCC_CR_HSERDY_Msk (1UL << RCC_CR_HSERDY_Pos) +#define RCC_CR_PLLON_Pos 24 +#define RCC_CR_PLLON_Msk (1UL << RCC_CR_PLLON_Pos) +#define RCC_CR_PLLRDY_Pos 25 +#define RCC_CR_PLLRDY_Msk (1UL << RCC_CR_PLLRDY_Pos) + +#define RCC_CFGR_REG 0x08 +#define RCC_CFGR_SW_Pos 0 +#define RCC_CFGR_SW_Msk (WHAL_BITMASK(2) << RCC_CFGR_SW_Pos) +#define RCC_CFGR_SWS_Pos 2 +#define RCC_CFGR_SWS_Msk (WHAL_BITMASK(2) << RCC_CFGR_SWS_Pos) +#define RCC_CFGR_PLLSRC_Pos 16 +#define RCC_CFGR_PLLSRC_Msk (1UL << RCC_CFGR_PLLSRC_Pos) +#define RCC_CFGR_PLLMUL_Pos 18 +#define RCC_CFGR_PLLMUL_Msk (WHAL_BITMASK(4) << RCC_CFGR_PLLMUL_Pos) +#define RCC_CFGR_PLLDIV_Pos 22 +#define RCC_CFGR_PLLDIV_Msk (WHAL_BITMASK(2) << RCC_CFGR_PLLDIV_Pos) + +#define RCC_CFGR_SW_MSI 0 +#define RCC_CFGR_SW_HSI 1 +#define RCC_CFGR_SW_HSE 2 +#define RCC_CFGR_SW_PLL 3 + +#ifdef WHAL_CFG_CLOCK_API_MAPPING_STM32L1 +#define whal_Stm32l1Rcc_Init whal_Clock_Init +#define whal_Stm32l1Rcc_Deinit whal_Clock_Deinit +#define whal_Stm32l1Rcc_Enable whal_Clock_Enable +#define whal_Stm32l1Rcc_Disable whal_Clock_Disable +#endif /* WHAL_CFG_CLOCK_API_MAPPING_STM32L1 */ + +static whal_Error Stm32l1Rcc_EnablePllSource(size_t base, + whal_Stm32l1Rcc_PllCfg *pll) +{ + size_t rdy; + + switch (pll->clkSrc) { + case WHAL_STM32L1_RCC_PLLSRC_HSI: + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSION_Msk, + whal_SetBits(RCC_CR_HSION_Msk, RCC_CR_HSION_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSIRDY_Msk, RCC_CR_HSIRDY_Pos, &rdy); + } while (!rdy); + break; + + case WHAL_STM32L1_RCC_PLLSRC_HSE: + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSEON_Msk, + whal_SetBits(RCC_CR_HSEON_Msk, RCC_CR_HSEON_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSERDY_Msk, RCC_CR_HSERDY_Pos, &rdy); + } while (!rdy); + break; + } + + return WHAL_SUCCESS; +} + +static void Stm32l1Rcc_ConfigurePll(size_t base, whal_Stm32l1Rcc_PllCfg *pll) +{ + uint32_t pllsrc; + + /* Disable PLL before reconfiguring */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 0)); + + /* Wait for PLL to stop */ + size_t rdy; + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_PLLRDY_Msk, RCC_CR_PLLRDY_Pos, &rdy); + } while (rdy); + + /* Set PLL source: 0 = HSI, 1 = HSE */ + pllsrc = (pll->clkSrc == WHAL_STM32L1_RCC_PLLSRC_HSE) ? 1 : 0; + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_PLLSRC_Msk, + whal_SetBits(RCC_CFGR_PLLSRC_Msk, RCC_CFGR_PLLSRC_Pos, + pllsrc)); + + /* Set PLLMUL */ + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_PLLMUL_Msk, + whal_SetBits(RCC_CFGR_PLLMUL_Msk, RCC_CFGR_PLLMUL_Pos, + pll->pllmul)); + + /* Set PLLDIV */ + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_PLLDIV_Msk, + whal_SetBits(RCC_CFGR_PLLDIV_Msk, RCC_CFGR_PLLDIV_Pos, + pll->plldiv)); + + /* Enable PLL and wait for lock */ + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_PLLON_Msk, + whal_SetBits(RCC_CR_PLLON_Msk, RCC_CR_PLLON_Pos, 1)); + + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_PLLRDY_Msk, RCC_CR_PLLRDY_Pos, &rdy); + } while (!rdy); +} + +whal_Error whal_Stm32l1Rcc_Init(whal_Clock *clkDev) +{ + whal_Stm32l1Rcc_Cfg *cfg; + size_t base; + uint32_t sw; + size_t sws; + + if (!clkDev || !clkDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32l1Rcc_Cfg *)clkDev->cfg; + base = clkDev->regmap.base; + + switch (cfg->sysClkSrc) { + case WHAL_STM32L1_RCC_SYSCLK_SRC_MSI: { + size_t rdy; + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_MSION_Msk, + whal_SetBits(RCC_CR_MSION_Msk, RCC_CR_MSION_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_MSIRDY_Msk, RCC_CR_MSIRDY_Pos, &rdy); + } while (!rdy); + sw = RCC_CFGR_SW_MSI; + break; + } + + case WHAL_STM32L1_RCC_SYSCLK_SRC_HSI: { + size_t rdy; + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSION_Msk, + whal_SetBits(RCC_CR_HSION_Msk, RCC_CR_HSION_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSIRDY_Msk, RCC_CR_HSIRDY_Pos, &rdy); + } while (!rdy); + sw = RCC_CFGR_SW_HSI; + break; + } + + case WHAL_STM32L1_RCC_SYSCLK_SRC_HSE: { + size_t rdy; + whal_Reg_Update(base, RCC_CR_REG, RCC_CR_HSEON_Msk, + whal_SetBits(RCC_CR_HSEON_Msk, RCC_CR_HSEON_Pos, 1)); + do { + whal_Reg_Get(base, RCC_CR_REG, + RCC_CR_HSERDY_Msk, RCC_CR_HSERDY_Pos, &rdy); + } while (!rdy); + sw = RCC_CFGR_SW_HSE; + break; + } + + case WHAL_STM32L1_RCC_SYSCLK_SRC_PLL: + if (!cfg->pllCfg) + return WHAL_EINVAL; + + Stm32l1Rcc_EnablePllSource(base, cfg->pllCfg); + Stm32l1Rcc_ConfigurePll(base, cfg->pllCfg); + sw = RCC_CFGR_SW_PLL; + break; + + default: + return WHAL_EINVAL; + } + + /* Switch system clock */ + whal_Reg_Update(base, RCC_CFGR_REG, RCC_CFGR_SW_Msk, + whal_SetBits(RCC_CFGR_SW_Msk, RCC_CFGR_SW_Pos, sw)); + + /* Wait for switch status to confirm */ + do { + whal_Reg_Get(base, RCC_CFGR_REG, + RCC_CFGR_SWS_Msk, RCC_CFGR_SWS_Pos, &sws); + } while (sws != sw); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Rcc_Deinit(whal_Clock *clkDev) +{ + size_t sws; + + if (!clkDev) + return WHAL_EINVAL; + + /* Switch back to MSI (default after reset) */ + whal_Reg_Update(clkDev->regmap.base, RCC_CR_REG, RCC_CR_MSION_Msk, + whal_SetBits(RCC_CR_MSION_Msk, RCC_CR_MSION_Pos, 1)); + + size_t rdy; + do { + whal_Reg_Get(clkDev->regmap.base, RCC_CR_REG, + RCC_CR_MSIRDY_Msk, RCC_CR_MSIRDY_Pos, &rdy); + } while (!rdy); + + whal_Reg_Update(clkDev->regmap.base, RCC_CFGR_REG, RCC_CFGR_SW_Msk, + whal_SetBits(RCC_CFGR_SW_Msk, RCC_CFGR_SW_Pos, + RCC_CFGR_SW_MSI)); + + do { + whal_Reg_Get(clkDev->regmap.base, RCC_CFGR_REG, + RCC_CFGR_SWS_Msk, RCC_CFGR_SWS_Pos, &sws); + } while (sws != RCC_CFGR_SW_MSI); + + /* Disable PLL */ + whal_Reg_Update(clkDev->regmap.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_Stm32l1Rcc_Enable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32l1Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32l1Rcc_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_Stm32l1Rcc_Disable(whal_Clock *clkDev, const void *clk) +{ + whal_Stm32l1Rcc_Clk *stClk; + + if (!clkDev || !clk) + return WHAL_EINVAL; + + stClk = (whal_Stm32l1Rcc_Clk *)clk; + + whal_Reg_Update(clkDev->regmap.base, stClk->regOffset, stClk->enableMask, + whal_SetBits(stClk->enableMask, stClk->enablePos, 0)); + + return WHAL_SUCCESS; +} + +#ifndef WHAL_CFG_CLOCK_API_MAPPING_STM32L1 +const whal_ClockDriver whal_Stm32l1Rcc_Driver = { + .Init = whal_Stm32l1Rcc_Init, + .Deinit = whal_Stm32l1Rcc_Deinit, + .Enable = whal_Stm32l1Rcc_Enable, + .Disable = whal_Stm32l1Rcc_Disable, +}; +#endif /* !WHAL_CFG_CLOCK_API_MAPPING_STM32L1 */ diff --git a/src/flash/stm32l1_flash.c b/src/flash/stm32l1_flash.c new file mode 100644 index 0000000..da6e0f9 --- /dev/null +++ b/src/flash/stm32l1_flash.c @@ -0,0 +1,328 @@ +#include +#include +#include +#include +#include +#include +#include + +/* + * STM32L1 Flash Register Definitions (RM0038 Section 3.9) + * + * The STM32L1 flash uses a PECR-based access model that differs from + * other STM32 families. All program/erase operations are controlled + * through FLASH_PECR bits, and unlocking requires a two-stage key + * sequence (PEKEYR then PRGKEYR). + */ + +#define FLASH_ACR_REG 0x00 +#define FLASH_ACR_LATENCY_Pos 0 +#define FLASH_ACR_LATENCY_Msk (1UL << FLASH_ACR_LATENCY_Pos) +#define FLASH_ACR_PRFTEN_Pos 1 +#define FLASH_ACR_PRFTEN_Msk (1UL << FLASH_ACR_PRFTEN_Pos) +#define FLASH_ACR_ACC64_Pos 2 +#define FLASH_ACR_ACC64_Msk (1UL << FLASH_ACR_ACC64_Pos) + +#define FLASH_BASE_ADDR 0x40023C00 + +#define FLASH_PECR_REG 0x04 +#define FLASH_PECR_PELOCK_Pos 0 +#define FLASH_PECR_PELOCK_Msk (1UL << FLASH_PECR_PELOCK_Pos) +#define FLASH_PECR_PRGLOCK_Pos 1 +#define FLASH_PECR_PRGLOCK_Msk (1UL << FLASH_PECR_PRGLOCK_Pos) +#define FLASH_PECR_PROG_Pos 3 +#define FLASH_PECR_PROG_Msk (1UL << FLASH_PECR_PROG_Pos) +#define FLASH_PECR_ERASE_Pos 9 +#define FLASH_PECR_ERASE_Msk (1UL << FLASH_PECR_ERASE_Pos) + +#define FLASH_PEKEYR_REG 0x0C +#define FLASH_PRGKEYR_REG 0x10 + +#define FLASH_SR_REG 0x18 +#define FLASH_SR_BSY_Pos 0 +#define FLASH_SR_BSY_Msk (1UL << FLASH_SR_BSY_Pos) +#define FLASH_SR_EOP_Pos 1 +#define FLASH_SR_EOP_Msk (1UL << FLASH_SR_EOP_Pos) +#define FLASH_SR_WRPERR_Pos 8 +#define FLASH_SR_WRPERR_Msk (1UL << FLASH_SR_WRPERR_Pos) +#define FLASH_SR_PGAERR_Pos 9 +#define FLASH_SR_PGAERR_Msk (1UL << FLASH_SR_PGAERR_Pos) +#define FLASH_SR_SIZERR_Pos 10 +#define FLASH_SR_SIZERR_Msk (1UL << FLASH_SR_SIZERR_Pos) + +#define FLASH_SR_ALL_ERR (FLASH_SR_WRPERR_Msk | FLASH_SR_PGAERR_Msk | \ + FLASH_SR_SIZERR_Msk) + +/* Unlock keys */ +#define PEKEY1 0x89ABCDEF +#define PEKEY2 0x02030405 +#define PRGKEY1 0x8C9DAEBF +#define PRGKEY2 0x13141516 + +/* Page size: 256 bytes */ +#define PAGE_SIZE 256 +#define PAGE_SHIFT 8 + +#ifdef WHAL_CFG_FLASH_API_MAPPING_STM32L1 +#define whal_Stm32l1Flash_Init whal_Flash_Init +#define whal_Stm32l1Flash_Deinit whal_Flash_Deinit +#define whal_Stm32l1Flash_Lock whal_Flash_Lock +#define whal_Stm32l1Flash_Unlock whal_Flash_Unlock +#define whal_Stm32l1Flash_Read whal_Flash_Read +#define whal_Stm32l1Flash_Write whal_Flash_Write +#define whal_Stm32l1Flash_Erase whal_Flash_Erase +#endif + +/* + * Unlock FLASH_PECR by writing the PEKEY sequence to FLASH_PEKEYR. + * This clears PELOCK if the keys are correct. + */ +static void UnlockPecr(size_t base) +{ + size_t pelock; + whal_Reg_Get(base, FLASH_PECR_REG, FLASH_PECR_PELOCK_Msk, + FLASH_PECR_PELOCK_Pos, &pelock); + if (!pelock) + return; + + whal_Reg_Write(base, FLASH_PEKEYR_REG, PEKEY1); + whal_Reg_Write(base, FLASH_PEKEYR_REG, PEKEY2); +} + +/* + * Unlock program memory by writing the PRGKEY sequence to FLASH_PRGKEYR. + * PECR must be unlocked first. + */ +static void UnlockProgram(size_t base) +{ + size_t prglock; + whal_Reg_Get(base, FLASH_PECR_REG, FLASH_PECR_PRGLOCK_Msk, + FLASH_PECR_PRGLOCK_Pos, &prglock); + if (!prglock) + return; + + whal_Reg_Write(base, FLASH_PRGKEYR_REG, PRGKEY1); + whal_Reg_Write(base, FLASH_PRGKEYR_REG, PRGKEY2); +} + +whal_Error whal_Stm32l1Flash_Init(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Flash_Deinit(whal_Flash *flashDev) +{ + (void)flashDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len) +{ + (void)addr; + (void)len; + + if (!flashDev) + return WHAL_EINVAL; + + /* Set PELOCK to lock everything */ + whal_Reg_Update(flashDev->regmap.base, FLASH_PECR_REG, + FLASH_PECR_PELOCK_Msk, + whal_SetBits(FLASH_PECR_PELOCK_Msk, + FLASH_PECR_PELOCK_Pos, 1)); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len) +{ + (void)addr; + (void)len; + + if (!flashDev) + return WHAL_EINVAL; + + size_t base = flashDev->regmap.base; + + /* Unlock PECR then program memory */ + UnlockPecr(base); + UnlockProgram(base); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Flash_Read(whal_Flash *flashDev, size_t addr, void *data, + size_t dataSz) +{ + whal_Stm32l1Flash_Cfg *cfg; + uint8_t *dataBuf = (uint8_t *)data; + + if (!flashDev || !flashDev->cfg || !data) + return WHAL_EINVAL; + + if (dataSz == 0) + return WHAL_SUCCESS; + + cfg = flashDev->cfg; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + /* Flash is memory-mapped, direct read */ + uint8_t *flashAddr = (uint8_t *)addr; + for (size_t i = 0; i < dataSz; ++i) + dataBuf[i] = flashAddr[i]; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Flash_Write(whal_Flash *flashDev, size_t addr, + const void *data, size_t dataSz) +{ + whal_Stm32l1Flash_Cfg *cfg; + const uint8_t *buf = (const uint8_t *)data; + size_t base; + whal_Error err = WHAL_SUCCESS; + + if (!flashDev || !flashDev->cfg || !data) + return WHAL_EINVAL; + + if (dataSz == 0) + return WHAL_SUCCESS; + + /* Word-aligned writes only */ + if ((addr & 0x3) || (dataSz & 0x3)) + return WHAL_EINVAL; + + cfg = flashDev->cfg; + base = flashDev->regmap.base; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + /* Clear error flags */ + whal_Reg_Write(base, FLASH_SR_REG, FLASH_SR_ALL_ERR); + + /* + * Fast Word Write: PECR and program memory must already be unlocked. + * Simply write a 32-bit word to the flash address; the hardware + * performs the programming automatically. + */ + for (size_t i = 0; i < dataSz; i += 4) { + volatile uint32_t *flashAddr = (volatile uint32_t *)(addr + i); + uint32_t word = (uint32_t)buf[i] + | ((uint32_t)buf[i + 1] << 8) + | ((uint32_t)buf[i + 2] << 16) + | ((uint32_t)buf[i + 3] << 24); + + *flashAddr = word; + + err = whal_Reg_ReadPoll(base, FLASH_SR_REG, FLASH_SR_BSY_Msk, 0, + cfg->timeout); + if (err) + return err; + + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) + return WHAL_EHARDWARE; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz) +{ + whal_Stm32l1Flash_Cfg *cfg; + size_t base; + whal_Error err = WHAL_SUCCESS; + + if (!flashDev || !flashDev->cfg) + return WHAL_EINVAL; + + if (dataSz == 0) + return WHAL_SUCCESS; + + cfg = flashDev->cfg; + base = flashDev->regmap.base; + + if (addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) + return WHAL_EINVAL; + + err = whal_Reg_ReadPoll(base, FLASH_SR_REG, FLASH_SR_BSY_Msk, 0, + cfg->timeout); + if (err) + return err; + + whal_Reg_Write(base, FLASH_SR_REG, FLASH_SR_ALL_ERR); + + size_t startPage = (addr - cfg->startAddr) >> PAGE_SHIFT; + size_t endPage = ((addr - cfg->startAddr) + dataSz - 1) >> PAGE_SHIFT; + + whal_Reg_Update(base, FLASH_PECR_REG, FLASH_PECR_ERASE_Msk, + whal_SetBits(FLASH_PECR_ERASE_Msk, + FLASH_PECR_ERASE_Pos, 1)); + whal_Reg_Update(base, FLASH_PECR_REG, FLASH_PECR_PROG_Msk, + whal_SetBits(FLASH_PECR_PROG_Msk, + FLASH_PECR_PROG_Pos, 1)); + + for (size_t page = startPage; page <= endPage; ++page) { + volatile uint32_t *pageAddr = + (volatile uint32_t *)(cfg->startAddr + (page << PAGE_SHIFT)); + *pageAddr = 0x00000000; + + err = whal_Reg_ReadPoll(base, FLASH_SR_REG, FLASH_SR_BSY_Msk, 0, + cfg->timeout); + if (err) + goto cleanup; + + if (whal_Reg_Read(base, FLASH_SR_REG) & FLASH_SR_ALL_ERR) { + err = WHAL_EHARDWARE; + goto cleanup; + } + } + +cleanup: + whal_Reg_Update(base, FLASH_PECR_REG, + FLASH_PECR_ERASE_Msk | FLASH_PECR_PROG_Msk, 0); + + return err; +} + +whal_Error whal_Stm32l1Flash_Ext_SetLatency(whal_Stm32l1Flash_Latency latency) +{ + size_t val; + + whal_Reg_Update(FLASH_BASE_ADDR, FLASH_ACR_REG, FLASH_ACR_ACC64_Msk, + whal_SetBits(FLASH_ACR_ACC64_Msk, + FLASH_ACR_ACC64_Pos, 1)); + do { + whal_Reg_Get(FLASH_BASE_ADDR, FLASH_ACR_REG, + FLASH_ACR_ACC64_Msk, FLASH_ACR_ACC64_Pos, &val); + } while (!val); + + whal_Reg_Update(FLASH_BASE_ADDR, FLASH_ACR_REG, FLASH_ACR_PRFTEN_Msk, + whal_SetBits(FLASH_ACR_PRFTEN_Msk, + FLASH_ACR_PRFTEN_Pos, 1)); + + whal_Reg_Update(FLASH_BASE_ADDR, FLASH_ACR_REG, FLASH_ACR_LATENCY_Msk, + whal_SetBits(FLASH_ACR_LATENCY_Msk, + FLASH_ACR_LATENCY_Pos, latency)); + do { + whal_Reg_Get(FLASH_BASE_ADDR, FLASH_ACR_REG, + FLASH_ACR_LATENCY_Msk, FLASH_ACR_LATENCY_Pos, &val); + } while (val != (size_t)latency); + + return WHAL_SUCCESS; +} + +#ifndef WHAL_CFG_FLASH_API_MAPPING_STM32L1 +const whal_FlashDriver whal_Stm32l1Flash_Driver = { + .Init = whal_Stm32l1Flash_Init, + .Deinit = whal_Stm32l1Flash_Deinit, + .Lock = whal_Stm32l1Flash_Lock, + .Unlock = whal_Stm32l1Flash_Unlock, + .Read = whal_Stm32l1Flash_Read, + .Write = whal_Stm32l1Flash_Write, + .Erase = whal_Stm32l1Flash_Erase, +}; +#endif /* !WHAL_CFG_FLASH_API_MAPPING_STM32L1 */ diff --git a/src/gpio/stm32l1_gpio.c b/src/gpio/stm32l1_gpio.c new file mode 100644 index 0000000..7ddf812 --- /dev/null +++ b/src/gpio/stm32l1_gpio.c @@ -0,0 +1 @@ +#include "stm32wb_gpio.c" diff --git a/src/gpio/stm32wb_gpio.c b/src/gpio/stm32wb_gpio.c index 4515224..80b97fe 100644 --- a/src/gpio/stm32wb_gpio.c +++ b/src/gpio/stm32wb_gpio.c @@ -37,7 +37,8 @@ defined(WHAL_CFG_GPIO_API_MAPPING_STM32H5) || \ defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) || \ defined(WHAL_CFG_GPIO_API_MAPPING_STM32F0) || \ - defined(WHAL_CFG_GPIO_API_MAPPING_STM32F3) + defined(WHAL_CFG_GPIO_API_MAPPING_STM32F3) || \ + defined(WHAL_CFG_GPIO_API_MAPPING_STM32L1) #define whal_Stm32wbGpio_Init whal_Gpio_Init #define whal_Stm32wbGpio_Deinit whal_Gpio_Deinit #define whal_Stm32wbGpio_Get whal_Gpio_Get @@ -183,7 +184,8 @@ whal_Error whal_Stm32wbGpio_Set(whal_Gpio *gpioDev, size_t pin, size_t value) !defined(WHAL_CFG_GPIO_API_MAPPING_STM32H5) && \ !defined(WHAL_CFG_GPIO_API_MAPPING_STM32C0) && \ !defined(WHAL_CFG_GPIO_API_MAPPING_STM32F0) && \ - !defined(WHAL_CFG_GPIO_API_MAPPING_STM32F3) + !defined(WHAL_CFG_GPIO_API_MAPPING_STM32F3) && \ + !defined(WHAL_CFG_GPIO_API_MAPPING_STM32L1) const whal_GpioDriver whal_Stm32wbGpio_Driver = { .Init = whal_Stm32wbGpio_Init, .Deinit = whal_Stm32wbGpio_Deinit, diff --git a/src/i2c/stm32l1_i2c.c b/src/i2c/stm32l1_i2c.c new file mode 100644 index 0000000..7c6cbe1 --- /dev/null +++ b/src/i2c/stm32l1_i2c.c @@ -0,0 +1,418 @@ +#include +#include +#include +#include +#include +#include + +/** + * STM32L1 I2C (V1) Register Definitions + * + * The V1 I2C peripheral uses CR1/CR2/DR/SR1/SR2/CCR/TRISE registers. + * This driver operates in controller mode with polling, implementing the + * master transmitter and receiver sequences from RM0038 Section 26.3.3. + */ + +/* Register offsets */ +#define I2C_CR1 0x00 +#define I2C_CR2 0x04 +#define I2C_DR 0x10 +#define I2C_SR1 0x14 +#define I2C_SR2 0x18 +#define I2C_CCR 0x1C +#define I2C_TRISE 0x20 + +/* CR1 bits */ +#define CR1_PE_Pos 0 +#define CR1_PE_Msk (1UL << CR1_PE_Pos) +#define CR1_START_Pos 8 +#define CR1_START_Msk (1UL << CR1_START_Pos) +#define CR1_STOP_Pos 9 +#define CR1_STOP_Msk (1UL << CR1_STOP_Pos) +#define CR1_ACK_Pos 10 +#define CR1_ACK_Msk (1UL << CR1_ACK_Pos) +#define CR1_POS_Pos 11 +#define CR1_POS_Msk (1UL << CR1_POS_Pos) +#define CR1_SWRST_Pos 15 +#define CR1_SWRST_Msk (1UL << CR1_SWRST_Pos) + +/* CR2 bits */ +#define CR2_FREQ_Pos 0 +#define CR2_FREQ_Msk (WHAL_BITMASK(6) << CR2_FREQ_Pos) + +/* SR1 bits */ +#define SR1_SB_Pos 0 +#define SR1_SB_Msk (1UL << SR1_SB_Pos) +#define SR1_ADDR_Pos 1 +#define SR1_ADDR_Msk (1UL << SR1_ADDR_Pos) +#define SR1_BTF_Pos 2 +#define SR1_BTF_Msk (1UL << SR1_BTF_Pos) +#define SR1_ADD10_Pos 3 +#define SR1_ADD10_Msk (1UL << SR1_ADD10_Pos) +#define SR1_RXNE_Pos 6 +#define SR1_RXNE_Msk (1UL << SR1_RXNE_Pos) +#define SR1_TXE_Pos 7 +#define SR1_TXE_Msk (1UL << SR1_TXE_Pos) +#define SR1_BERR_Pos 8 +#define SR1_BERR_Msk (1UL << SR1_BERR_Pos) +#define SR1_ARLO_Pos 9 +#define SR1_ARLO_Msk (1UL << SR1_ARLO_Pos) +#define SR1_AF_Pos 10 +#define SR1_AF_Msk (1UL << SR1_AF_Pos) + +#define SR1_ERR_Msk (SR1_BERR_Msk | SR1_ARLO_Msk | SR1_AF_Msk) + +/* CCR bits */ +#define CCR_CCR_Msk (WHAL_BITMASK(12)) +#define CCR_FS_Pos 15 +#define CCR_FS_Msk (1UL << CCR_FS_Pos) + +/* TRISE bits */ +#define TRISE_Msk (WHAL_BITMASK(6)) + +#if defined(WHAL_CFG_I2C_API_MAPPING_STM32L1) +#define whal_Stm32l1I2c_Init whal_I2c_Init +#define whal_Stm32l1I2c_Deinit whal_I2c_Deinit +#define whal_Stm32l1I2c_StartCom whal_I2c_StartCom +#define whal_Stm32l1I2c_EndCom whal_I2c_EndCom +#define whal_Stm32l1I2c_Transfer whal_I2c_Transfer +#endif + +static whal_Error Stm32l1I2c_WaitSR1(size_t base, uint32_t flag, + whal_Timeout *timeout) +{ + WHAL_TIMEOUT_START(timeout); + + while (1) { + uint32_t sr1 = whal_Reg_Read(base, I2C_SR1); + + if (sr1 & flag) + return WHAL_SUCCESS; + + if (sr1 & SR1_ERR_Msk) { + whal_Reg_Update(base, I2C_SR1, SR1_ERR_Msk, 0); + whal_Reg_Update(base, I2C_CR1, CR1_STOP_Msk, CR1_STOP_Msk); + return WHAL_EHARDWARE; + } + + if (WHAL_TIMEOUT_EXPIRED(timeout)) + return WHAL_ETIMEOUT; + } +} + +static void Stm32l1I2c_ClearAddr(size_t base) +{ + (void)whal_Reg_Read(base, I2C_SR1); + (void)whal_Reg_Read(base, I2C_SR2); +} + +static whal_Error Stm32l1I2c_SendStart(size_t base, uint16_t addr, + uint8_t addrSz, uint8_t isRead, + whal_Timeout *timeout) +{ + whal_Error err; + uint8_t header; + + whal_Reg_Update(base, I2C_CR1, CR1_START_Msk, CR1_START_Msk); + + err = Stm32l1I2c_WaitSR1(base, SR1_SB_Msk, timeout); + if (err) + return err; + + if (addrSz == 7) { + whal_Reg_Write(base, I2C_DR, + (uint8_t)((addr << 1) | (isRead ? 1 : 0))); + + return Stm32l1I2c_WaitSR1(base, SR1_ADDR_Msk, timeout); + } + + /* + * 10-bit addressing per RM0038 §26.3.3: + * header byte is 0b11110. The master always begins with W, + * sends the low address byte after ADD10, then (for reads) issues a + * repeated start with the same header byte plus R=1. + */ + header = (uint8_t)(0xF0 | (((addr >> 8) & 0x03) << 1)); + + whal_Reg_Write(base, I2C_DR, header); + + err = Stm32l1I2c_WaitSR1(base, SR1_ADD10_Msk, timeout); + if (err) + return err; + + whal_Reg_Write(base, I2C_DR, (uint8_t)(addr & 0xFF)); + + err = Stm32l1I2c_WaitSR1(base, SR1_ADDR_Msk, timeout); + if (err) + return err; + + if (!isRead) + return WHAL_SUCCESS; + + Stm32l1I2c_ClearAddr(base); + + whal_Reg_Update(base, I2C_CR1, CR1_START_Msk, CR1_START_Msk); + + err = Stm32l1I2c_WaitSR1(base, SR1_SB_Msk, timeout); + if (err) + return err; + + whal_Reg_Write(base, I2C_DR, (uint8_t)(header | 0x01)); + + return Stm32l1I2c_WaitSR1(base, SR1_ADDR_Msk, timeout); +} + +static whal_Error Stm32l1I2c_MasterWrite(size_t base, uint8_t *buf, size_t len, + uint8_t stop, whal_Timeout *timeout) +{ + whal_Error err; + + for (size_t i = 0; i < len; i++) { + err = Stm32l1I2c_WaitSR1(base, SR1_TXE_Msk, timeout); + if (err) + return err; + + whal_Reg_Write(base, I2C_DR, buf[i]); + } + + err = Stm32l1I2c_WaitSR1(base, SR1_BTF_Msk, timeout); + if (err) + return err; + + if (stop) + whal_Reg_Update(base, I2C_CR1, CR1_STOP_Msk, CR1_STOP_Msk); + + return WHAL_SUCCESS; +} + +/** + * Master receive with ADDR not yet cleared. + * + * Implements the 1-byte, 2-byte, and N>2-byte receive procedures from + * RM0038 Section 26.3.3, including the ACK/POS manipulation that must + * happen before the ADDR flag is cleared. + */ +static whal_Error Stm32l1I2c_MasterRead(size_t base, uint8_t *buf, size_t len, + uint8_t stop, whal_Timeout *timeout) +{ + whal_Error err; + + if (len == 1) { + whal_Reg_Update(base, I2C_CR1, CR1_ACK_Msk, 0); + Stm32l1I2c_ClearAddr(base); + + if (stop) + whal_Reg_Update(base, I2C_CR1, CR1_STOP_Msk, CR1_STOP_Msk); + + err = Stm32l1I2c_WaitSR1(base, SR1_RXNE_Msk, timeout); + if (err) + return err; + + buf[0] = (uint8_t)whal_Reg_Read(base, I2C_DR); + } + else if (len == 2) { + whal_Reg_Update(base, I2C_CR1, CR1_ACK_Msk | CR1_POS_Msk, CR1_POS_Msk); + Stm32l1I2c_ClearAddr(base); + + err = Stm32l1I2c_WaitSR1(base, SR1_BTF_Msk, timeout); + if (err) + return err; + + if (stop) + whal_Reg_Update(base, I2C_CR1, CR1_STOP_Msk, CR1_STOP_Msk); + + buf[0] = (uint8_t)whal_Reg_Read(base, I2C_DR); + buf[1] = (uint8_t)whal_Reg_Read(base, I2C_DR); + } + else { + whal_Reg_Update(base, I2C_CR1, CR1_ACK_Msk, CR1_ACK_Msk); + Stm32l1I2c_ClearAddr(base); + + for (size_t i = 0; i < len - 3; i++) { + err = Stm32l1I2c_WaitSR1(base, SR1_RXNE_Msk, timeout); + if (err) + return err; + + buf[i] = (uint8_t)whal_Reg_Read(base, I2C_DR); + } + + err = Stm32l1I2c_WaitSR1(base, SR1_BTF_Msk, timeout); + if (err) + return err; + + whal_Reg_Update(base, I2C_CR1, CR1_ACK_Msk, 0); + buf[len - 3] = (uint8_t)whal_Reg_Read(base, I2C_DR); + + err = Stm32l1I2c_WaitSR1(base, SR1_BTF_Msk, timeout); + if (err) + return err; + + if (stop) + whal_Reg_Update(base, I2C_CR1, CR1_STOP_Msk, CR1_STOP_Msk); + + buf[len - 2] = (uint8_t)whal_Reg_Read(base, I2C_DR); + buf[len - 1] = (uint8_t)whal_Reg_Read(base, I2C_DR); + } + + whal_Reg_Update(base, I2C_CR1, CR1_POS_Msk, 0); + + return WHAL_SUCCESS; +} + +static uint32_t Stm32l1I2c_CalcCcr(uint32_t pclk, uint32_t freq) +{ + uint32_t ccr; + + if (freq <= 100000) { + ccr = pclk / (2 * freq); + if (ccr < 4) + ccr = 4; + return ccr & CCR_CCR_Msk; + } + + ccr = pclk / (3 * freq); + if (ccr < 1) + ccr = 1; + return CCR_FS_Msk | (ccr & CCR_CCR_Msk); +} + +static uint32_t Stm32l1I2c_CalcTrise(uint32_t pclk, uint32_t freq) +{ + uint32_t pclkMhz = pclk / 1000000; + + if (freq <= 100000) + return (pclkMhz + 1) & TRISE_Msk; + + return ((pclkMhz * 300 / 1000) + 1) & TRISE_Msk; +} + +whal_Error whal_Stm32l1I2c_Init(whal_I2c *i2cDev) +{ + size_t base; + + if (!i2cDev || !i2cDev->cfg) + return WHAL_EINVAL; + + base = i2cDev->regmap.base; + + whal_Reg_Update(base, I2C_CR1, CR1_PE_Msk, 0); + whal_Reg_Update(base, I2C_CR1, CR1_SWRST_Msk, CR1_SWRST_Msk); + whal_Reg_Update(base, I2C_CR1, CR1_SWRST_Msk, 0); + whal_Reg_Update(base, I2C_CR1, CR1_PE_Msk, CR1_PE_Msk); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1I2c_Deinit(whal_I2c *i2cDev) +{ + if (!i2cDev || !i2cDev->cfg) + return WHAL_EINVAL; + + whal_Reg_Update(i2cDev->regmap.base, I2C_CR1, CR1_PE_Msk, 0); + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1I2c_StartCom(whal_I2c *i2cDev, whal_I2c_ComCfg *comCfg) +{ + whal_Stm32l1I2c_Cfg *cfg; + size_t base; + uint32_t freqMhz; + + if (!i2cDev || !i2cDev->cfg || !comCfg) + return WHAL_EINVAL; + + if ((comCfg->addrSz != 7 && comCfg->addrSz != 10) || comCfg->freq == 0) + return WHAL_EINVAL; + + cfg = (whal_Stm32l1I2c_Cfg *)i2cDev->cfg; + base = i2cDev->regmap.base; + + whal_Reg_Update(base, I2C_CR1, CR1_PE_Msk, 0); + + freqMhz = cfg->pclk / 1000000; + whal_Reg_Update(base, I2C_CR2, CR2_FREQ_Msk, + whal_SetBits(CR2_FREQ_Msk, CR2_FREQ_Pos, freqMhz)); + + whal_Reg_Write(base, I2C_CCR, Stm32l1I2c_CalcCcr(cfg->pclk, comCfg->freq)); + whal_Reg_Write(base, I2C_TRISE, + Stm32l1I2c_CalcTrise(cfg->pclk, comCfg->freq)); + + whal_Reg_Update(base, I2C_CR1, CR1_PE_Msk, CR1_PE_Msk); + + cfg->_addr = comCfg->addr; + cfg->_addrSz = comCfg->addrSz; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1I2c_EndCom(whal_I2c *i2cDev) +{ + whal_Stm32l1I2c_Cfg *cfg; + + if (!i2cDev || !i2cDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32l1I2c_Cfg *)i2cDev->cfg; + cfg->_addr = 0; + cfg->_addrSz = 0; + + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1I2c_Transfer(whal_I2c *i2cDev, whal_I2c_Msg *msgs, + size_t numMsgs) +{ + whal_Stm32l1I2c_Cfg *cfg; + size_t base; + whal_Error err; + + if (!i2cDev || !i2cDev->cfg || !msgs || numMsgs == 0) + return WHAL_EINVAL; + + cfg = (whal_Stm32l1I2c_Cfg *)i2cDev->cfg; + base = i2cDev->regmap.base; + + for (size_t i = 0; i < numMsgs; i++) { + uint8_t isRead = (msgs[i].flags & WHAL_I2C_MSG_READ) ? 1 : 0; + uint8_t doStart = (msgs[i].flags & WHAL_I2C_MSG_START) ? 1 : 0; + uint8_t doStop = (msgs[i].flags & WHAL_I2C_MSG_STOP) ? 1 : 0; + uint8_t *buf = (uint8_t *)msgs[i].data; + size_t len = msgs[i].dataSz; + + if (len == 0) + return WHAL_EINVAL; + + if (doStart) { + err = Stm32l1I2c_SendStart(base, cfg->_addr, cfg->_addrSz, + isRead, cfg->timeout); + if (err) + return err; + } + + if (isRead) { + err = Stm32l1I2c_MasterRead(base, buf, len, doStop, cfg->timeout); + } + else { + if (doStart) + Stm32l1I2c_ClearAddr(base); + + err = Stm32l1I2c_MasterWrite(base, buf, len, doStop, cfg->timeout); + } + + if (err) + return err; + } + + return WHAL_SUCCESS; +} + +#if !defined(WHAL_CFG_I2C_API_MAPPING_STM32L1) +const whal_I2cDriver whal_Stm32l1I2c_Driver = { + .Init = whal_Stm32l1I2c_Init, + .Deinit = whal_Stm32l1I2c_Deinit, + .StartCom = whal_Stm32l1I2c_StartCom, + .EndCom = whal_Stm32l1I2c_EndCom, + .Transfer = whal_Stm32l1I2c_Transfer, +}; +#endif /* !WHAL_CFG_I2C_API_MAPPING_STM32L1 */ diff --git a/src/spi/stm32f4_spi.c b/src/spi/stm32f4_spi.c index 4a1ba37..1170f78 100644 --- a/src/spi/stm32f4_spi.c +++ b/src/spi/stm32f4_spi.c @@ -56,7 +56,8 @@ /* Data Register - 8/16-bit access */ #define SPI_DR_REG 0x0C -#ifdef WHAL_CFG_SPI_API_MAPPING_STM32F4 +#if defined(WHAL_CFG_SPI_API_MAPPING_STM32F4) || \ + defined(WHAL_CFG_SPI_API_MAPPING_STM32L1) #define whal_Stm32f4Spi_Init whal_Spi_Init #define whal_Stm32f4Spi_Deinit whal_Spi_Deinit #define whal_Stm32f4Spi_StartCom whal_Spi_StartCom @@ -227,7 +228,8 @@ whal_Error whal_Stm32f4Spi_SendRecv(whal_Spi *spiDev, cfg->timeout); } -#ifndef WHAL_CFG_SPI_API_MAPPING_STM32F4 +#if !defined(WHAL_CFG_SPI_API_MAPPING_STM32F4) && \ + !defined(WHAL_CFG_SPI_API_MAPPING_STM32L1) const whal_SpiDriver whal_Stm32f4Spi_Driver = { .Init = whal_Stm32f4Spi_Init, .Deinit = whal_Stm32f4Spi_Deinit, @@ -235,4 +237,4 @@ const whal_SpiDriver whal_Stm32f4Spi_Driver = { .EndCom = whal_Stm32f4Spi_EndCom, .SendRecv = whal_Stm32f4Spi_SendRecv, }; -#endif /* !WHAL_CFG_SPI_API_MAPPING_STM32F4 */ +#endif /* !WHAL_CFG_SPI_API_MAPPING */ diff --git a/src/spi/stm32l1_spi.c b/src/spi/stm32l1_spi.c new file mode 100644 index 0000000..449c4f7 --- /dev/null +++ b/src/spi/stm32l1_spi.c @@ -0,0 +1 @@ +#include "stm32f4_spi.c" diff --git a/src/supply/stm32l1_pwr.c b/src/supply/stm32l1_pwr.c new file mode 100644 index 0000000..2cfdec2 --- /dev/null +++ b/src/supply/stm32l1_pwr.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#define PWR_CR_REG 0x00 +#define PWR_CR_VOS_Pos 11 +#define PWR_CR_VOS_Msk (WHAL_BITMASK(2) << PWR_CR_VOS_Pos) +#define PWR_CSR_REG 0x04 +#define PWR_CSR_VOSF_Pos 4 +#define PWR_CSR_VOSF_Msk (1UL << PWR_CSR_VOSF_Pos) + +#ifdef WHAL_CFG_SUPPLY_API_MAPPING_STM32L1 +#define whal_Stm32l1Pwr_Init whal_Supply_Init +#define whal_Stm32l1Pwr_Deinit whal_Supply_Deinit +#define whal_Stm32l1Pwr_Enable whal_Supply_Enable +#define whal_Stm32l1Pwr_Disable whal_Supply_Disable +#endif /* WHAL_CFG_SUPPLY_API_MAPPING_STM32L1 */ + +whal_Error whal_Stm32l1Pwr_Init(whal_Supply *supplyDev) +{ + whal_Stm32l1Pwr_Cfg *cfg; + size_t base; + whal_Error err; + + if (!supplyDev || !supplyDev->cfg) + return WHAL_EINVAL; + + cfg = (whal_Stm32l1Pwr_Cfg *)supplyDev->cfg; + base = supplyDev->regmap.base; + + err = whal_Reg_ReadPoll(base, PWR_CSR_REG, PWR_CSR_VOSF_Msk, 0, + cfg->timeout); + if (err) + return err; + + whal_Reg_Update(base, PWR_CR_REG, PWR_CR_VOS_Msk, + whal_SetBits(PWR_CR_VOS_Msk, PWR_CR_VOS_Pos, + cfg->vosRange)); + + return whal_Reg_ReadPoll(base, PWR_CSR_REG, PWR_CSR_VOSF_Msk, 0, + cfg->timeout); +} + +whal_Error whal_Stm32l1Pwr_Deinit(whal_Supply *supplyDev) +{ + (void)supplyDev; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Pwr_Enable(whal_Supply *supplyDev, void *supply) +{ + (void)supplyDev; + (void)supply; + return WHAL_SUCCESS; +} + +whal_Error whal_Stm32l1Pwr_Disable(whal_Supply *supplyDev, void *supply) +{ + (void)supplyDev; + (void)supply; + return WHAL_SUCCESS; +} + +#ifndef WHAL_CFG_SUPPLY_API_MAPPING_STM32L1 +const whal_SupplyDriver whal_Stm32l1Pwr_Driver = { + .Init = whal_Stm32l1Pwr_Init, + .Deinit = whal_Stm32l1Pwr_Deinit, + .Enable = whal_Stm32l1Pwr_Enable, + .Disable = whal_Stm32l1Pwr_Disable, +}; +#endif /* !WHAL_CFG_SUPPLY_API_MAPPING_STM32L1 */ diff --git a/src/uart/stm32f4_uart.c b/src/uart/stm32f4_uart.c index de95200..1800418 100644 --- a/src/uart/stm32f4_uart.c +++ b/src/uart/stm32f4_uart.c @@ -45,7 +45,8 @@ #define UART_CR1_UE_Pos 13 /* USART enable */ #define UART_CR1_UE_Msk (1UL << UART_CR1_UE_Pos) -#ifdef WHAL_CFG_UART_API_MAPPING_STM32F4 +#if defined(WHAL_CFG_UART_API_MAPPING_STM32F4) || \ + defined(WHAL_CFG_UART_API_MAPPING_STM32L1) #define whal_Stm32f4Uart_Init whal_Uart_Init #define whal_Stm32f4Uart_Deinit whal_Uart_Deinit #define whal_Stm32f4Uart_Send whal_Uart_Send @@ -182,7 +183,8 @@ whal_Error whal_Stm32f4Uart_RecvAsync(whal_Uart *uartDev, void *data, size_t dat return WHAL_ENOTSUP; } -#ifndef WHAL_CFG_UART_API_MAPPING_STM32F4 +#if !defined(WHAL_CFG_UART_API_MAPPING_STM32F4) && \ + !defined(WHAL_CFG_UART_API_MAPPING_STM32L1) const whal_UartDriver whal_Stm32f4Uart_Driver = { .Init = whal_Stm32f4Uart_Init, .Deinit = whal_Stm32f4Uart_Deinit, @@ -191,4 +193,4 @@ const whal_UartDriver whal_Stm32f4Uart_Driver = { .RecvAsync = whal_Stm32f4Uart_RecvAsync, .Recv = whal_Stm32f4Uart_Recv, }; -#endif /* !WHAL_CFG_UART_API_MAPPING_STM32F4 */ +#endif /* !WHAL_CFG_UART_API_MAPPING */ diff --git a/src/uart/stm32l1_uart.c b/src/uart/stm32l1_uart.c new file mode 100644 index 0000000..545287d --- /dev/null +++ b/src/uart/stm32l1_uart.c @@ -0,0 +1 @@ +#include "stm32f4_uart.c" diff --git a/src/watchdog/stm32f0_wwdg.c b/src/watchdog/stm32f0_wwdg.c index 541cac6..520229c 100644 --- a/src/watchdog/stm32f0_wwdg.c +++ b/src/watchdog/stm32f0_wwdg.c @@ -19,7 +19,8 @@ #define CFR_EWI_Msk (1UL << CFR_EWI_Pos) #if defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG) || \ - defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_WWDG) + defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_WWDG) || \ + defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_WWDG) #define whal_Stm32f0Wwdg_Init whal_Watchdog_Init #define whal_Stm32f0Wwdg_Deinit whal_Watchdog_Deinit #define whal_Stm32f0Wwdg_Refresh whal_Watchdog_Refresh @@ -73,7 +74,8 @@ whal_Error whal_Stm32f0Wwdg_Refresh(whal_Watchdog *wdgDev) } #if !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_WWDG) && \ - !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_WWDG) + !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_WWDG) && \ + !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_WWDG) const whal_WatchdogDriver whal_Stm32f0Wwdg_Driver = { .Init = whal_Stm32f0Wwdg_Init, .Deinit = whal_Stm32f0Wwdg_Deinit, diff --git a/src/watchdog/stm32l1_iwdg.c b/src/watchdog/stm32l1_iwdg.c new file mode 100644 index 0000000..130c617 --- /dev/null +++ b/src/watchdog/stm32l1_iwdg.c @@ -0,0 +1 @@ +#include "stm32wb_iwdg.c" diff --git a/src/watchdog/stm32l1_wwdg.c b/src/watchdog/stm32l1_wwdg.c new file mode 100644 index 0000000..2651cfc --- /dev/null +++ b/src/watchdog/stm32l1_wwdg.c @@ -0,0 +1 @@ +#include "stm32f0_wwdg.c" diff --git a/src/watchdog/stm32wb_iwdg.c b/src/watchdog/stm32wb_iwdg.c index 7c988b2..2b5e6b7 100644 --- a/src/watchdog/stm32wb_iwdg.c +++ b/src/watchdog/stm32wb_iwdg.c @@ -36,7 +36,8 @@ #if defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32WB_IWDG) || \ defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_IWDG) || \ - defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_IWDG) + defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_IWDG) || \ + defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_IWDG) #define whal_Stm32wbIwdg_Init whal_Watchdog_Init #define whal_Stm32wbIwdg_Deinit whal_Watchdog_Deinit #define whal_Stm32wbIwdg_Refresh whal_Watchdog_Refresh @@ -106,7 +107,8 @@ whal_Error whal_Stm32wbIwdg_Refresh(whal_Watchdog *wdgDev) #if !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32WB_IWDG) && \ !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F0_IWDG) && \ - !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_IWDG) + !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32F3_IWDG) && \ + !defined(WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_IWDG) const whal_WatchdogDriver whal_Stm32wbIwdg_Driver = { .Init = whal_Stm32wbIwdg_Init, .Deinit = whal_Stm32wbIwdg_Deinit, diff --git a/tests/flash/test_flash.c b/tests/flash/test_flash.c index 5e94303..f4044c1 100644 --- a/tests/flash/test_flash.c +++ b/tests/flash/test_flash.c @@ -7,10 +7,6 @@ static whal_Flash *g_testFlashDev; static size_t g_testFlashAddr; static size_t g_testFlashSectorSz; -#ifdef BOARD_FLASH_SIZE -static size_t g_testFlashStartAddr; -static size_t g_testFlashSize; -#endif static void Test_Flash_Api(void) { @@ -27,27 +23,7 @@ static void Test_Flash_Api(void) WHAL_ASSERT_EQ(whal_Flash_Write(g_testFlashDev, 0, NULL, 8), WHAL_EINVAL); } -static void Test_Flash_EraseBlank(void) -{ - uint8_t readback[8] = {0}; - uint8_t erased[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - - WHAL_ASSERT_EQ(whal_Flash_Unlock(g_testFlashDev, g_testFlashAddr, - g_testFlashSectorSz), WHAL_SUCCESS); - - WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, g_testFlashAddr, - g_testFlashSectorSz), WHAL_SUCCESS); - - WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, g_testFlashAddr, - readback, sizeof(readback)), WHAL_SUCCESS); - - WHAL_ASSERT_MEM_EQ(readback, erased, sizeof(erased)); - - WHAL_ASSERT_EQ(whal_Flash_Lock(g_testFlashDev, g_testFlashAddr, - g_testFlashSectorSz), WHAL_SUCCESS); -} - -static void Test_Flash_WriteRead(void) +static void Test_Flash_WriteReadErase(void) { uint8_t pattern[32] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, @@ -56,14 +32,18 @@ static void Test_Flash_WriteRead(void) 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE, }; uint8_t readback[32]; + whal_Error err; WHAL_ASSERT_EQ(whal_Flash_Unlock(g_testFlashDev, g_testFlashAddr, g_testFlashSectorSz), WHAL_SUCCESS); + WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, g_testFlashAddr, + readback, sizeof(readback)), WHAL_SUCCESS); + WHAL_ASSERT_MEM_NEQ(readback, pattern, sizeof(pattern)); + WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, g_testFlashAddr, g_testFlashSectorSz), WHAL_SUCCESS); - whal_Error err; do { err = whal_Flash_Write(g_testFlashDev, g_testFlashAddr, pattern, sizeof(pattern)); @@ -72,35 +52,18 @@ static void Test_Flash_WriteRead(void) WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, g_testFlashAddr, readback, sizeof(readback)), WHAL_SUCCESS); - WHAL_ASSERT_MEM_EQ(pattern, readback, sizeof(pattern)); - WHAL_ASSERT_EQ(whal_Flash_Lock(g_testFlashDev, g_testFlashAddr, - g_testFlashSectorSz), WHAL_SUCCESS); -} - -#ifdef BOARD_FLASH_SIZE -static void Test_Flash_EraseLastSector(void) -{ - size_t lastSectorAddr = g_testFlashStartAddr + g_testFlashSize - g_testFlashSectorSz; - uint8_t readback[8] = {0}; - uint8_t erased[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - - WHAL_ASSERT_EQ(whal_Flash_Unlock(g_testFlashDev, lastSectorAddr, - g_testFlashSectorSz), WHAL_SUCCESS); - - WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, lastSectorAddr, + WHAL_ASSERT_EQ(whal_Flash_Erase(g_testFlashDev, g_testFlashAddr, g_testFlashSectorSz), WHAL_SUCCESS); - WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, lastSectorAddr, + WHAL_ASSERT_EQ(whal_Flash_Read(g_testFlashDev, g_testFlashAddr, readback, sizeof(readback)), WHAL_SUCCESS); + WHAL_ASSERT_MEM_NEQ(readback, pattern, sizeof(pattern)); - WHAL_ASSERT_MEM_EQ(readback, erased, sizeof(erased)); - - WHAL_ASSERT_EQ(whal_Flash_Lock(g_testFlashDev, lastSectorAddr, + WHAL_ASSERT_EQ(whal_Flash_Lock(g_testFlashDev, g_testFlashAddr, g_testFlashSectorSz), WHAL_SUCCESS); } -#endif static void run_flash_tests(const char *name) { @@ -108,11 +71,7 @@ static void run_flash_tests(const char *name) if (name) whal_Test_Printf(" device: %s\n", name); WHAL_TEST(Test_Flash_Api); - WHAL_TEST(Test_Flash_EraseBlank); - WHAL_TEST(Test_Flash_WriteRead); -#ifdef BOARD_FLASH_SIZE - WHAL_TEST(Test_Flash_EraseLastSector); -#endif + WHAL_TEST(Test_Flash_WriteReadErase); WHAL_TEST_SUITE_END(); } @@ -121,10 +80,6 @@ void whal_Test_Flash(void) /* Test on-chip flash */ g_testFlashDev = &g_whalFlash; g_testFlashAddr = BOARD_FLASH_TEST_ADDR; -#ifdef BOARD_FLASH_SIZE - g_testFlashStartAddr = BOARD_FLASH_START_ADDR; - g_testFlashSize = BOARD_FLASH_SIZE; -#endif g_testFlashSectorSz = BOARD_FLASH_SECTOR_SZ; run_flash_tests("on-chip"); diff --git a/tests/gpio/test_stm32l1_gpio.c b/tests/gpio/test_stm32l1_gpio.c new file mode 100644 index 0000000..c287cb9 --- /dev/null +++ b/tests/gpio/test_stm32l1_gpio.c @@ -0,0 +1 @@ +#include "test_stm32wb_gpio.c" diff --git a/tests/gpio/test_stm32wb_gpio.c b/tests/gpio/test_stm32wb_gpio.c index 4b93b61..4007acb 100644 --- a/tests/gpio/test_stm32wb_gpio.c +++ b/tests/gpio/test_stm32wb_gpio.c @@ -5,11 +5,27 @@ #include "test.h" /* - * GPIO register offsets. - * LED port and pin come from board.h (BOARD_LED_PORT_OFFSET, BOARD_LED_PIN_NUM). + * GPIO register offsets. Port and pin are derived from the LED entry in + * g_whalGpio.cfg->pinCfg[BOARD_LED_PIN]. Port stride is 0x400 on all + * supported STM32 families. */ #define GPIOx_MODE_REG 0x00 #define GPIOx_ODR_REG 0x14 +#define GPIOx_STRIDE 0x400 + +static inline size_t Board_LedPortBase(void) +{ + whal_Stm32wbGpio_Cfg *cfg = (whal_Stm32wbGpio_Cfg *)g_whalGpio.cfg; + whal_Stm32wbGpio_PinCfg led = cfg->pinCfg[BOARD_LED_PIN]; + return g_whalGpio.regmap.base + WHAL_STM32WB_GPIO_GET_PORT(led) * GPIOx_STRIDE; +} + +static inline size_t Board_LedPinNum(void) +{ + whal_Stm32wbGpio_Cfg *cfg = (whal_Stm32wbGpio_Cfg *)g_whalGpio.cfg; + whal_Stm32wbGpio_PinCfg led = cfg->pinCfg[BOARD_LED_PIN]; + return WHAL_STM32WB_GPIO_GET_PIN(led); +} static void Test_Gpio_PinCfgRoundTrip(void) { @@ -45,12 +61,12 @@ static void Test_Gpio_NoDuplicatePins(void) static void Test_Gpio_ModeRegister(void) { - size_t portBase = g_whalGpio.regmap.base + BOARD_LED_PORT_OFFSET; - size_t bitPos = BOARD_LED_PIN_NUM << 1; + size_t pinNum = Board_LedPinNum(); + size_t bitPos = pinNum << 1; size_t mask = (WHAL_BITMASK(2) << bitPos); size_t val = 0; - whal_Reg_Get(portBase, GPIOx_MODE_REG, mask, bitPos, &val); + whal_Reg_Get(Board_LedPortBase(), GPIOx_MODE_REG, mask, bitPos, &val); WHAL_ASSERT_EQ(val, WHAL_STM32WB_GPIO_MODE_OUT); } @@ -58,10 +74,10 @@ static void Test_Gpio_SetHighReg(void) { WHAL_ASSERT_EQ(whal_Gpio_Set(&g_whalGpio, BOARD_LED_PIN, 1), WHAL_SUCCESS); - size_t portBase = g_whalGpio.regmap.base + BOARD_LED_PORT_OFFSET; + size_t pinNum = Board_LedPinNum(); size_t val = 0; - whal_Reg_Get(portBase, GPIOx_ODR_REG, (1UL << BOARD_LED_PIN_NUM), - BOARD_LED_PIN_NUM, &val); + whal_Reg_Get(Board_LedPortBase(), GPIOx_ODR_REG, (1UL << pinNum), + pinNum, &val); WHAL_ASSERT_EQ(val, 1); } @@ -69,10 +85,10 @@ static void Test_Gpio_SetLowReg(void) { WHAL_ASSERT_EQ(whal_Gpio_Set(&g_whalGpio, BOARD_LED_PIN, 0), WHAL_SUCCESS); - size_t portBase = g_whalGpio.regmap.base + BOARD_LED_PORT_OFFSET; + size_t pinNum = Board_LedPinNum(); size_t val = 0; - whal_Reg_Get(portBase, GPIOx_ODR_REG, (1UL << BOARD_LED_PIN_NUM), - BOARD_LED_PIN_NUM, &val); + whal_Reg_Get(Board_LedPortBase(), GPIOx_ODR_REG, (1UL << pinNum), + pinNum, &val); WHAL_ASSERT_EQ(val, 0); } diff --git a/tests/test.h b/tests/test.h index 7e0ea1c..fe9baa3 100644 --- a/tests/test.h +++ b/tests/test.h @@ -154,6 +154,22 @@ extern int g_whalTestCurSkipped; } \ } while (0) +#define WHAL_ASSERT_MEM_NEQ(a, b, len) \ + do { \ + const unsigned char *_a = (const unsigned char *)(a); \ + const unsigned char *_b = (const unsigned char *)(b); \ + int _differ = 0; \ + for (size_t _i = 0; _i < (len); _i++) { \ + if (_a[_i] != _b[_i]) { _differ = 1; break; } \ + } \ + if (!_differ) { \ + whal_Test_Printf(" ASSERT_MEM_NEQ failed at %s:%d\n", \ + __FILE__, __LINE__); \ + g_whalTestCurFailed = 1; \ + return; \ + } \ + } while (0) + #define WHAL_TEST_SUMMARY() \ do { \ whal_Test_Printf("\n"); \ diff --git a/wolfHAL/clock/stm32l1_rcc.h b/wolfHAL/clock/stm32l1_rcc.h new file mode 100644 index 0000000..98ce954 --- /dev/null +++ b/wolfHAL/clock/stm32l1_rcc.h @@ -0,0 +1,118 @@ +#ifndef WHAL_STM32L1_RCC_H +#define WHAL_STM32L1_RCC_H + +#include +#include +#include + +/* + * @file stm32l1_rcc.h + * @brief STM32L1 RCC (Reset and Clock Control) driver configuration. + * + * The STM32L1 RCC peripheral controls: + * - System clock source selection (MSI, HSI, HSE, PLL) + * - PLL with PLLMUL multiplier and PLLDIV divider + * - Peripheral clock gating (AHB, APB1, APB2 buses) + * + * Clock sources: + * MSI = 65.536 kHz to 4.194 MHz multispeed internal oscillator (default) + * HSI = 16 MHz internal RC oscillator + * HSE = 1-24 MHz external oscillator + * PLL = HSI or HSE * PLLMUL / PLLDIV (output max 32 MHz) + * + * RCC register map (RM0038 Table 36): + * RCC_CR = 0x00 (HSION, HSIRDY, MSION, MSIRDY, HSEON, HSERDY, PLLON, PLLRDY) + * RCC_ICSCR = 0x04 (MSIRANGE) + * RCC_CFGR = 0x08 (SW, SWS, HPRE, PPRE1, PPRE2, PLLSRC, PLLMUL, PLLDIV) + * RCC_CIR = 0x0C + * RCC_AHBRSTR = 0x10 + * RCC_APB2RSTR = 0x14 + * RCC_APB1RSTR = 0x18 + * RCC_AHBENR = 0x1C + * RCC_APB2ENR = 0x20 + * RCC_APB1ENR = 0x24 + */ + +/* + * @brief System clock source selection. + */ +typedef enum { + WHAL_STM32L1_RCC_SYSCLK_SRC_MSI, /* Multispeed internal (default) */ + WHAL_STM32L1_RCC_SYSCLK_SRC_HSI, /* 16 MHz internal RC */ + WHAL_STM32L1_RCC_SYSCLK_SRC_HSE, /* External crystal/oscillator */ + WHAL_STM32L1_RCC_SYSCLK_SRC_PLL, /* PLL output */ +} whal_Stm32l1Rcc_SysClockSrc; + +/* + * @brief PLL input clock source selection. + */ +typedef enum { + WHAL_STM32L1_RCC_PLLSRC_HSI, /* HSI (16 MHz) */ + WHAL_STM32L1_RCC_PLLSRC_HSE, /* HSE */ +} whal_Stm32l1Rcc_PllClockSrc; + +/* + * @brief PLL multiplication factor (PLLMUL field in RCC_CFGR). + * + * PLLVCO = PLL_input * pllmul + * PLLVCO must not exceed 96 MHz (range 1), 48 MHz (range 2), 24 MHz (range 3). + */ +typedef enum { + WHAL_STM32L1_RCC_PLLMUL_3 = 0, + WHAL_STM32L1_RCC_PLLMUL_4 = 1, + WHAL_STM32L1_RCC_PLLMUL_6 = 2, + WHAL_STM32L1_RCC_PLLMUL_8 = 3, + WHAL_STM32L1_RCC_PLLMUL_12 = 4, + WHAL_STM32L1_RCC_PLLMUL_16 = 5, + WHAL_STM32L1_RCC_PLLMUL_24 = 6, + WHAL_STM32L1_RCC_PLLMUL_32 = 7, + WHAL_STM32L1_RCC_PLLMUL_48 = 8, +} whal_Stm32l1Rcc_PllMul; + +/* + * @brief PLL output division factor (PLLDIV field in RCC_CFGR). + * + * SYSCLK = PLLVCO / plldiv + */ +typedef enum { + WHAL_STM32L1_RCC_PLLDIV_2 = 1, + WHAL_STM32L1_RCC_PLLDIV_3 = 2, + WHAL_STM32L1_RCC_PLLDIV_4 = 3, +} whal_Stm32l1Rcc_PllDiv; + +/* + * @brief PLL configuration parameters. + */ +typedef struct { + whal_Stm32l1Rcc_PllClockSrc clkSrc; + whal_Stm32l1Rcc_PllMul pllmul; + whal_Stm32l1Rcc_PllDiv plldiv; +} whal_Stm32l1Rcc_PllCfg; + +/* + * @brief Peripheral clock enable descriptor. + */ +typedef struct { + size_t regOffset; + size_t enableMask; + size_t enablePos; +} whal_Stm32l1Rcc_Clk; + +/* + * @brief RCC driver configuration. + */ +typedef struct whal_Stm32l1Rcc_Cfg { + whal_Stm32l1Rcc_SysClockSrc sysClkSrc; + whal_Stm32l1Rcc_PllCfg *pllCfg; +} whal_Stm32l1Rcc_Cfg; + +#ifndef WHAL_CFG_CLOCK_API_MAPPING_STM32L1 +extern const whal_ClockDriver whal_Stm32l1Rcc_Driver; + +whal_Error whal_Stm32l1Rcc_Init(whal_Clock *clkDev); +whal_Error whal_Stm32l1Rcc_Deinit(whal_Clock *clkDev); +whal_Error whal_Stm32l1Rcc_Enable(whal_Clock *clkDev, const void *clk); +whal_Error whal_Stm32l1Rcc_Disable(whal_Clock *clkDev, const void *clk); +#endif /* !WHAL_CFG_CLOCK_API_MAPPING_STM32L1 */ + +#endif /* WHAL_STM32L1_RCC_H */ diff --git a/wolfHAL/flash/stm32l1_flash.h b/wolfHAL/flash/stm32l1_flash.h new file mode 100644 index 0000000..81e3c0d --- /dev/null +++ b/wolfHAL/flash/stm32l1_flash.h @@ -0,0 +1,77 @@ +#ifndef WHAL_STM32L1_FLASH_H +#define WHAL_STM32L1_FLASH_H + +#include +#include +#include +#include + +/* + * @file stm32l1_flash.h + * @brief STM32L1 flash driver configuration. + * + * The STM32L1 flash uses a PECR-based unlock model: + * 1. Unlock FLASH_PECR via FLASH_PEKEYR (PEKEY1=0x89ABCDEF, PEKEY2=0x02030405) + * 2. Unlock program memory via FLASH_PRGKEYR (PRGKEY1=0x8C9DAEBF, PRGKEY2=0x13141516) + * + * Register layout: + * FLASH_ACR = 0x00 (LATENCY, ACC64, PRFTEN, RUN_PD, SLEEP_PD) + * FLASH_PECR = 0x04 (PELOCK, PRGLOCK, OPTLOCK, PROG, ERASE, FPRG, DATA, FTDW) + * FLASH_PDKEYR = 0x08 + * FLASH_PEKEYR = 0x0C + * FLASH_PRGKEYR = 0x10 + * FLASH_OPTKEYR = 0x14 + * FLASH_SR = 0x18 (BSY, EOP, ENDHV, READY, WRPERR, PGAERR, SIZERR, OPTVERR) + * FLASH_OBR = 0x1C + * FLASH_WRPR1 = 0x20 + * + * Programming: + * - Write alignment: 4 bytes (word) + * - Erase granularity: 256 bytes (page) + * - Fast word write: unlock PECR + PRGKEYR, write 32-bit word to flash address + * - Page erase: set ERASE+PROG in PECR, write 0x00000000 to first word of page + */ + +typedef struct whal_Stm32l1Flash_Cfg { + size_t startAddr; + size_t size; + whal_Timeout *timeout; +} whal_Stm32l1Flash_Cfg; + +/* + * @brief Flash access latency values for STM32L1. + * + * 0 WS: HCLK <= 16 MHz (voltage range 1 / 2), HCLK <= 8 MHz (range 3) + * 1 WS: 16 < HCLK <= 32 MHz (range 1), 8 < HCLK <= 16 MHz (range 2/3) + */ +typedef enum { + WHAL_STM32L1_FLASH_LATENCY_0 = 0, + WHAL_STM32L1_FLASH_LATENCY_1 = 1, +} whal_Stm32l1Flash_Latency; + +#ifndef WHAL_CFG_FLASH_API_MAPPING_STM32L1 +extern const whal_FlashDriver whal_Stm32l1Flash_Driver; + +whal_Error whal_Stm32l1Flash_Init(whal_Flash *flashDev); +whal_Error whal_Stm32l1Flash_Deinit(whal_Flash *flashDev); +whal_Error whal_Stm32l1Flash_Lock(whal_Flash *flashDev, size_t addr, size_t len); +whal_Error whal_Stm32l1Flash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); +whal_Error whal_Stm32l1Flash_Read(whal_Flash *flashDev, size_t addr, void *data, + size_t dataSz); +whal_Error whal_Stm32l1Flash_Write(whal_Flash *flashDev, size_t addr, + const void *data, size_t dataSz); +whal_Error whal_Stm32l1Flash_Erase(whal_Flash *flashDev, size_t addr, + size_t dataSz); +#endif /* !WHAL_CFG_FLASH_API_MAPPING_STM32L1 */ + +/* + * @brief Set flash access latency (FLASH_ACR). + * + * Enables 64-bit access (ACC64) and prefetch (PRFTEN) as required by RM0038 + * §3.9.1 before programming the LATENCY bit, and polls until LATENCY matches + * the requested value. Must be called by the board before increasing SYSCLK + * beyond 16 MHz. + */ +whal_Error whal_Stm32l1Flash_Ext_SetLatency(whal_Stm32l1Flash_Latency latency); + +#endif /* WHAL_STM32L1_FLASH_H */ diff --git a/wolfHAL/gpio/stm32l1_gpio.h b/wolfHAL/gpio/stm32l1_gpio.h new file mode 100644 index 0000000..b5416b4 --- /dev/null +++ b/wolfHAL/gpio/stm32l1_gpio.h @@ -0,0 +1,54 @@ +#ifndef WHAL_STM32L1_GPIO_H +#define WHAL_STM32L1_GPIO_H + +/* + * @file stm32l1_gpio.h + * @brief STM32L1 GPIO driver (alias for STM32WB GPIO). + * + * The STM32L1 GPIO peripheral is register-compatible with the STM32WB GPIO. + * This header re-exports the STM32WB GPIO driver types and symbols under + * STM32L1-specific names. The underlying implementation is shared. + */ + +#include + +typedef whal_Stm32wbGpio_Cfg whal_Stm32l1Gpio_Cfg; +typedef whal_Stm32wbGpio_PinCfg whal_Stm32l1Gpio_PinCfg; + +#ifndef WHAL_CFG_GPIO_API_MAPPING_STM32L1 +#define whal_Stm32l1Gpio_Driver whal_Stm32wbGpio_Driver +#define whal_Stm32l1Gpio_Init whal_Stm32wbGpio_Init +#define whal_Stm32l1Gpio_Deinit whal_Stm32wbGpio_Deinit +#define whal_Stm32l1Gpio_Get whal_Stm32wbGpio_Get +#define whal_Stm32l1Gpio_Set whal_Stm32wbGpio_Set +#endif /* !WHAL_CFG_GPIO_API_MAPPING_STM32L1 */ + +#define WHAL_STM32L1_GPIO_MODE_IN WHAL_STM32WB_GPIO_MODE_IN +#define WHAL_STM32L1_GPIO_MODE_OUT WHAL_STM32WB_GPIO_MODE_OUT +#define WHAL_STM32L1_GPIO_MODE_ALTFN WHAL_STM32WB_GPIO_MODE_ALTFN +#define WHAL_STM32L1_GPIO_MODE_ANALOG WHAL_STM32WB_GPIO_MODE_ANALOG + +#define WHAL_STM32L1_GPIO_OUTTYPE_PUSHPULL WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL +#define WHAL_STM32L1_GPIO_OUTTYPE_OPENDRAIN WHAL_STM32WB_GPIO_OUTTYPE_OPENDRAIN + +#define WHAL_STM32L1_GPIO_SPEED_LOW WHAL_STM32WB_GPIO_SPEED_LOW +#define WHAL_STM32L1_GPIO_SPEED_MEDIUM WHAL_STM32WB_GPIO_SPEED_MEDIUM +#define WHAL_STM32L1_GPIO_SPEED_FAST WHAL_STM32WB_GPIO_SPEED_FAST +#define WHAL_STM32L1_GPIO_SPEED_HIGH WHAL_STM32WB_GPIO_SPEED_HIGH + +#define WHAL_STM32L1_GPIO_PULL_NONE WHAL_STM32WB_GPIO_PULL_NONE +#define WHAL_STM32L1_GPIO_PULL_UP WHAL_STM32WB_GPIO_PULL_UP +#define WHAL_STM32L1_GPIO_PULL_DOWN WHAL_STM32WB_GPIO_PULL_DOWN + +#define WHAL_STM32L1_GPIO_PORT_A WHAL_STM32WB_GPIO_PORT_A +#define WHAL_STM32L1_GPIO_PORT_B WHAL_STM32WB_GPIO_PORT_B +#define WHAL_STM32L1_GPIO_PORT_C WHAL_STM32WB_GPIO_PORT_C +#define WHAL_STM32L1_GPIO_PORT_D WHAL_STM32WB_GPIO_PORT_D +#define WHAL_STM32L1_GPIO_PORT_E WHAL_STM32WB_GPIO_PORT_E +#define WHAL_STM32L1_GPIO_PORT_F WHAL_STM32WB_GPIO_PORT_F +#define WHAL_STM32L1_GPIO_PORT_G WHAL_STM32WB_GPIO_PORT_G +#define WHAL_STM32L1_GPIO_PORT_H WHAL_STM32WB_GPIO_PORT_H + +#define WHAL_STM32L1_GPIO_PIN WHAL_STM32WB_GPIO_PIN + +#endif /* WHAL_STM32L1_GPIO_H */ diff --git a/wolfHAL/i2c/stm32l1_i2c.h b/wolfHAL/i2c/stm32l1_i2c.h new file mode 100644 index 0000000..0a03822 --- /dev/null +++ b/wolfHAL/i2c/stm32l1_i2c.h @@ -0,0 +1,105 @@ +#ifndef WHAL_STM32L1_I2C_H +#define WHAL_STM32L1_I2C_H + +#include +#include +#include +#include + +/** + * @file stm32l1_i2c.h + * @brief STM32L1 I2C driver configuration. + * + * The STM32L1 uses the V1 I2C peripheral with CR1/CR2/DR/SR1/SR2/CCR/TRISE + * registers. This driver supports controller mode with polling: + * - Standard-mode (up to 100 kHz) and Fast-mode (up to 400 kHz) + * - 7-bit and 10-bit addressing + */ + +/** + * @brief I2C device configuration. + */ +typedef struct whal_Stm32l1I2c_Cfg { + uint32_t pclk; /**< APB1 clock frequency in Hz */ + whal_Timeout *timeout; /**< Timeout instance */ + uint16_t _addr; /**< Target address (set by StartCom) */ + uint8_t _addrSz; /**< Address size in bits (set by StartCom) */ +} whal_Stm32l1I2c_Cfg; + +#ifndef WHAL_CFG_I2C_API_MAPPING_STM32L1 +/** + * @brief Driver instance for STM32L1 I2C peripheral. + */ +extern const whal_I2cDriver whal_Stm32l1I2c_Driver; + +/** + * @brief Initialize the STM32L1 I2C peripheral. + * + * Resets the peripheral and enables it. + * + * @param i2cDev I2C device instance to initialize. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32l1I2c_Init(whal_I2c *i2cDev); + +/** + * @brief Deinitialize the STM32L1 I2C peripheral. + * + * Disables the peripheral. + * + * @param i2cDev I2C device instance to deinitialize. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32l1I2c_Deinit(whal_I2c *i2cDev); + +/** + * @brief Begin a communication session on the STM32L1 I2C peripheral. + * + * Computes CCR and TRISE from the configured pclk and the requested + * frequency, then stores the target address for use by Transfer. + * + * @param i2cDev I2C device instance. + * @param comCfg Per-session communication parameters. + * + * @retval WHAL_SUCCESS Communication session started. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32l1I2c_StartCom(whal_I2c *i2cDev, whal_I2c_ComCfg *comCfg); + +/** + * @brief End the current communication session on the STM32L1 I2C peripheral. + * + * Clears the stored target address. + * + * @param i2cDev I2C device instance. + * + * @retval WHAL_SUCCESS Communication session ended. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Stm32l1I2c_EndCom(whal_I2c *i2cDev); + +/** + * @brief Execute a sequence of I2C messages on the bus. + * + * Supports 7-bit and 10-bit addressing with the V1 I2C master transmitter + * and receiver sequences. Handles 1-byte, 2-byte, and N-byte receive with + * the correct ACK/POS/STOP sequencing per RM0038. + * + * @param i2cDev I2C device instance. + * @param msgs Array of message descriptors. + * @param numMsgs Number of messages in the array. + * + * @retval WHAL_SUCCESS All messages transferred successfully. + * @retval WHAL_EINVAL Invalid arguments. + * @retval WHAL_ETIMEOUT Hardware did not respond in time. + * @retval WHAL_EHARDWARE NACK or bus error detected. + */ +whal_Error whal_Stm32l1I2c_Transfer(whal_I2c *i2cDev, whal_I2c_Msg *msgs, + size_t numMsgs); +#endif /* !WHAL_CFG_I2C_API_MAPPING_STM32L1 */ + +#endif /* WHAL_STM32L1_I2C_H */ diff --git a/wolfHAL/platform/arm/cortex_m3.h b/wolfHAL/platform/arm/cortex_m3.h new file mode 100644 index 0000000..c3ee8b5 --- /dev/null +++ b/wolfHAL/platform/arm/cortex_m3.h @@ -0,0 +1,17 @@ +#ifndef WHAL_CORTEX_M3_H +#define WHAL_CORTEX_M3_H + +#include +#include + +#define WHAL_CORTEX_M3_SYSTICK_REGMAP \ + .base = 0xE000E010, \ + .size = 0x400 +#define WHAL_CORTEX_M3_SYSTICK_DRIVER &whal_SysTick_Driver + +#define WHAL_CORTEX_M3_NVIC_REGMAP \ + .base = 0xE000E100, \ + .size = 0x400 +#define WHAL_CORTEX_M3_NVIC_DRIVER &whal_Nvic_Driver + +#endif /* WHAL_CORTEX_M3_H */ diff --git a/wolfHAL/platform/st/stm32l152re.h b/wolfHAL/platform/st/stm32l152re.h new file mode 100644 index 0000000..b21ad14 --- /dev/null +++ b/wolfHAL/platform/st/stm32l152re.h @@ -0,0 +1,272 @@ +#ifndef WHAL_STM32L152RE_H +#define WHAL_STM32L152RE_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * @file stm32l152re.h + * @brief Convenience initializers for STM32L152RE device instances. + * + * Base addresses from RM0038 Table 5 (STM32L1xxxx memory map). + * RCC: 0x40023800 + * GPIO: 0x40020000 (port A), 0x400 spacing per port (A-H) + * USART1: 0x40013800 (APB2), USART2: 0x40004400 (APB1), USART3: 0x40004800 + * UART4: 0x40004C00, UART5: 0x40005000 + * SPI1: 0x40013000 (APB2), SPI2: 0x40003800, SPI3: 0x40003C00 + * I2C1: 0x40005400, I2C2: 0x40005800 + * Flash: 0x40023C00 + * IWDG: 0x40003000, WWDG: 0x40002C00 + * PWR: 0x40007000 + */ + +/* --- Device macros --- */ + +#define WHAL_STM32L152_RCC_REGMAP \ + .base = 0x40023800, \ + .size = 0x400 +#define WHAL_STM32L152_RCC_DRIVER &whal_Stm32l1Rcc_Driver + +#define WHAL_STM32L152_GPIO_REGMAP \ + .base = 0x40020000, \ + .size = 0x2000 +#define WHAL_STM32L152_GPIO_DRIVER &whal_Stm32l1Gpio_Driver + +#define WHAL_STM32L152_USART1_REGMAP \ + .base = 0x40013800, \ + .size = 0x400 +#define WHAL_STM32L152_USART1_DRIVER &whal_Stm32l1Uart_Driver + +#define WHAL_STM32L152_USART2_REGMAP \ + .base = 0x40004400, \ + .size = 0x400 +#define WHAL_STM32L152_USART2_DRIVER &whal_Stm32l1Uart_Driver + +#define WHAL_STM32L152_USART3_REGMAP \ + .base = 0x40004800, \ + .size = 0x400 +#define WHAL_STM32L152_USART3_DRIVER &whal_Stm32l1Uart_Driver + +#define WHAL_STM32L152_SPI1_REGMAP \ + .base = 0x40013000, \ + .size = 0x400 +#define WHAL_STM32L152_SPI1_DRIVER &whal_Stm32l1Spi_Driver + +#define WHAL_STM32L152_SPI2_REGMAP \ + .base = 0x40003800, \ + .size = 0x400 +#define WHAL_STM32L152_SPI2_DRIVER &whal_Stm32l1Spi_Driver + +#define WHAL_STM32L152_SPI3_REGMAP \ + .base = 0x40003C00, \ + .size = 0x400 +#define WHAL_STM32L152_SPI3_DRIVER &whal_Stm32l1Spi_Driver + +#define WHAL_STM32L152_I2C1_REGMAP \ + .base = 0x40005400, \ + .size = 0x400 +#define WHAL_STM32L152_I2C1_DRIVER &whal_Stm32l1I2c_Driver + +#define WHAL_STM32L152_I2C2_REGMAP \ + .base = 0x40005800, \ + .size = 0x400 +#define WHAL_STM32L152_I2C2_DRIVER &whal_Stm32l1I2c_Driver + +#define WHAL_STM32L152_FLASH_REGMAP \ + .base = 0x40023C00, \ + .size = 0x400 +#define WHAL_STM32L152_FLASH_DRIVER &whal_Stm32l1Flash_Driver + +#define WHAL_STM32L152_IWDG_REGMAP \ + .base = 0x40003000, \ + .size = 0x400 +#define WHAL_STM32L152_IWDG_DRIVER &whal_Stm32l1Iwdg_Driver + +#define WHAL_STM32L152_WWDG_REGMAP \ + .base = 0x40002C00, \ + .size = 0x400 +#define WHAL_STM32L152_WWDG_DRIVER &whal_Stm32l1Wwdg_Driver + +#define WHAL_STM32L152_PWR_REGMAP \ + .base = 0x40007000, \ + .size = 0x400 +#define WHAL_STM32L152_PWR_DRIVER &whal_Stm32l1Pwr_Driver + +/* --- Clock gate macros --- */ + +/* RCC_AHBENR (offset 0x1C) */ + +#define WHAL_STM32L152_GPIOA_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32L152_GPIOB_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +#define WHAL_STM32L152_GPIOC_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 2), \ + .enablePos = 2 + +#define WHAL_STM32L152_GPIOD_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 3), \ + .enablePos = 3 + +#define WHAL_STM32L152_GPIOE_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32L152_GPIOH_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 5), \ + .enablePos = 5 + +#define WHAL_STM32L152_FLITF_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 15), \ + .enablePos = 15 + +#define WHAL_STM32L152_DMA1_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 24), \ + .enablePos = 24 + +#define WHAL_STM32L152_DMA2_CLOCK \ + .regOffset = 0x1C, \ + .enableMask = (1UL << 25), \ + .enablePos = 25 + +/* RCC_APB2ENR (offset 0x20) */ + +#define WHAL_STM32L152_SYSCFG_CLOCK \ + .regOffset = 0x20, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32L152_TIM9_CLOCK \ + .regOffset = 0x20, \ + .enableMask = (1UL << 2), \ + .enablePos = 2 + +#define WHAL_STM32L152_TIM10_CLOCK \ + .regOffset = 0x20, \ + .enableMask = (1UL << 3), \ + .enablePos = 3 + +#define WHAL_STM32L152_TIM11_CLOCK \ + .regOffset = 0x20, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32L152_ADC1_CLOCK \ + .regOffset = 0x20, \ + .enableMask = (1UL << 9), \ + .enablePos = 9 + +#define WHAL_STM32L152_SPI1_CLOCK \ + .regOffset = 0x20, \ + .enableMask = (1UL << 12), \ + .enablePos = 12 + +#define WHAL_STM32L152_USART1_CLOCK \ + .regOffset = 0x20, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +/* RCC_APB1ENR (offset 0x24) */ + +#define WHAL_STM32L152_TIM2_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 0), \ + .enablePos = 0 + +#define WHAL_STM32L152_TIM3_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 1), \ + .enablePos = 1 + +#define WHAL_STM32L152_TIM4_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 2), \ + .enablePos = 2 + +#define WHAL_STM32L152_TIM5_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 3), \ + .enablePos = 3 + +#define WHAL_STM32L152_TIM6_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 4), \ + .enablePos = 4 + +#define WHAL_STM32L152_TIM7_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 5), \ + .enablePos = 5 + +#define WHAL_STM32L152_WWDG_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 11), \ + .enablePos = 11 + +#define WHAL_STM32L152_SPI2_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 14), \ + .enablePos = 14 + +#define WHAL_STM32L152_SPI3_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 15), \ + .enablePos = 15 + +#define WHAL_STM32L152_USART2_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 17), \ + .enablePos = 17 + +#define WHAL_STM32L152_USART3_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 18), \ + .enablePos = 18 + +#define WHAL_STM32L152_I2C1_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 21), \ + .enablePos = 21 + +#define WHAL_STM32L152_I2C2_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 22), \ + .enablePos = 22 + +#define WHAL_STM32L152_USB_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 23), \ + .enablePos = 23 + +#define WHAL_STM32L152_PWR_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 28), \ + .enablePos = 28 + +#define WHAL_STM32L152_DAC_CLOCK \ + .regOffset = 0x24, \ + .enableMask = (1UL << 29), \ + .enablePos = 29 + +#endif /* WHAL_STM32L152RE_H */ diff --git a/wolfHAL/spi/stm32l1_spi.h b/wolfHAL/spi/stm32l1_spi.h new file mode 100644 index 0000000..76a2c79 --- /dev/null +++ b/wolfHAL/spi/stm32l1_spi.h @@ -0,0 +1,25 @@ +#ifndef WHAL_STM32L1_SPI_H +#define WHAL_STM32L1_SPI_H + +/* + * @file stm32l1_spi.h + * @brief STM32L1 SPI driver (alias for STM32F4 SPI). + * + * The STM32L1 SPI peripheral uses the same V1 SPI register layout as the + * STM32F4 (CR1 with DFF bit at 0x00, CR2 at 0x04, SR at 0x08, DR at 0x0C). + */ + +#include + +typedef whal_Stm32f4Spi_Cfg whal_Stm32l1Spi_Cfg; + +#ifndef WHAL_CFG_SPI_API_MAPPING_STM32L1 +#define whal_Stm32l1Spi_Driver whal_Stm32f4Spi_Driver +#define whal_Stm32l1Spi_Init whal_Stm32f4Spi_Init +#define whal_Stm32l1Spi_Deinit whal_Stm32f4Spi_Deinit +#define whal_Stm32l1Spi_StartCom whal_Stm32f4Spi_StartCom +#define whal_Stm32l1Spi_EndCom whal_Stm32f4Spi_EndCom +#define whal_Stm32l1Spi_SendRecv whal_Stm32f4Spi_SendRecv +#endif /* !WHAL_CFG_SPI_API_MAPPING_STM32L1 */ + +#endif /* WHAL_STM32L1_SPI_H */ diff --git a/wolfHAL/supply/stm32l1_pwr.h b/wolfHAL/supply/stm32l1_pwr.h new file mode 100644 index 0000000..c8ca1c7 --- /dev/null +++ b/wolfHAL/supply/stm32l1_pwr.h @@ -0,0 +1,79 @@ +#ifndef WHAL_STM32L1_PWR_H +#define WHAL_STM32L1_PWR_H + +#include +#include +#include + +/* + * @file stm32l1_pwr.h + * @brief STM32L1 PWR (power control) driver configuration. + * + * Controls the internal voltage regulator output range (PWR_CR.VOS), which + * bounds the maximum permitted SYSCLK and PLL VCO frequencies. Must be + * configured before bringing the PLL above the reset-default limits. + * + * Range 1 (1.8 V): SYSCLK <= 32 MHz, PLL VCO <= 96 MHz. + * Range 2 (1.5 V): SYSCLK <= 16 MHz, PLL VCO <= 48 MHz. Reset default. + * Range 3 (1.2 V): SYSCLK <= 4 MHz, PLL disabled. + */ + +/* + * @brief Internal voltage regulator output voltage ranges (PWR_CR.VOS). + */ +typedef enum { + WHAL_STM32L1_PWR_VOS_RANGE_1 = 1, + WHAL_STM32L1_PWR_VOS_RANGE_2 = 2, + WHAL_STM32L1_PWR_VOS_RANGE_3 = 3, +} whal_Stm32l1Pwr_VosRange; + +/* + * @brief STM32L1 PWR driver configuration. + */ +typedef struct whal_Stm32l1Pwr_Cfg { + whal_Stm32l1Pwr_VosRange vosRange; + whal_Timeout *timeout; /**< Timeout instance for VOSF polling */ +} whal_Stm32l1Pwr_Cfg; + +#ifndef WHAL_CFG_SUPPLY_API_MAPPING_STM32L1 +/* + * @brief Driver instance for STM32L1 PWR peripheral. + */ +extern const whal_SupplyDriver whal_Stm32l1Pwr_Driver; + +/* + * @brief Initialize the STM32L1 PWR peripheral. + * + * Programs PWR_CR.VOS from the cfg and polls PWR_CSR.VOSF until voltage + * scaling completes. The PWR APB1 clock must already be enabled (via + * whal_Clock_Enable with WHAL_STM32L152_PWR_CLOCK) before calling. + * + * @param supplyDev Supply instance to initialize. + * + * @retval WHAL_SUCCESS Voltage scaling settled at the requested range. + * @retval WHAL_EINVAL Null pointer or missing cfg. + * @retval WHAL_ETIMEOUT VOSF did not clear within the configured timeout. + */ +whal_Error whal_Stm32l1Pwr_Init(whal_Supply *supplyDev); + +/* + * @brief Deinitialize the STM32L1 PWR peripheral. + * + * @param supplyDev Supply instance to deinitialize. + * + * @retval WHAL_SUCCESS Always. + */ +whal_Error whal_Stm32l1Pwr_Deinit(whal_Supply *supplyDev); + +/* + * @brief Unused for STM32L1 PWR; provided for vtable completeness. + */ +whal_Error whal_Stm32l1Pwr_Enable(whal_Supply *supplyDev, void *supply); + +/* + * @brief Unused for STM32L1 PWR; provided for vtable completeness. + */ +whal_Error whal_Stm32l1Pwr_Disable(whal_Supply *supplyDev, void *supply); +#endif /* !WHAL_CFG_SUPPLY_API_MAPPING_STM32L1 */ + +#endif /* WHAL_STM32L1_PWR_H */ diff --git a/wolfHAL/uart/stm32l1_uart.h b/wolfHAL/uart/stm32l1_uart.h new file mode 100644 index 0000000..3371be6 --- /dev/null +++ b/wolfHAL/uart/stm32l1_uart.h @@ -0,0 +1,28 @@ +#ifndef WHAL_STM32L1_UART_H +#define WHAL_STM32L1_UART_H + +/* + * @file stm32l1_uart.h + * @brief STM32L1 UART driver (alias for STM32F4 UART). + * + * The STM32L1 USART uses the same USARTv1 register layout as the STM32F4 + * (SR/DR at 0x00/0x04, BRR at 0x08, CR1 at 0x0C). + */ + +#include + +typedef whal_Stm32f4Uart_Cfg whal_Stm32l1Uart_Cfg; + +#define WHAL_STM32L1_UART_BRR WHAL_STM32F4_UART_BRR + +#ifndef WHAL_CFG_UART_API_MAPPING_STM32L1 +#define whal_Stm32l1Uart_Driver whal_Stm32f4Uart_Driver +#define whal_Stm32l1Uart_Init whal_Stm32f4Uart_Init +#define whal_Stm32l1Uart_Deinit whal_Stm32f4Uart_Deinit +#define whal_Stm32l1Uart_Send whal_Stm32f4Uart_Send +#define whal_Stm32l1Uart_Recv whal_Stm32f4Uart_Recv +#define whal_Stm32l1Uart_SendAsync whal_Stm32f4Uart_SendAsync +#define whal_Stm32l1Uart_RecvAsync whal_Stm32f4Uart_RecvAsync +#endif /* !WHAL_CFG_UART_API_MAPPING_STM32L1 */ + +#endif /* WHAL_STM32L1_UART_H */ diff --git a/wolfHAL/watchdog/stm32l1_iwdg.h b/wolfHAL/watchdog/stm32l1_iwdg.h new file mode 100644 index 0000000..3289e6a --- /dev/null +++ b/wolfHAL/watchdog/stm32l1_iwdg.h @@ -0,0 +1,30 @@ +#ifndef WHAL_STM32L1_IWDG_H +#define WHAL_STM32L1_IWDG_H + +/* + * @file stm32l1_iwdg.h + * @brief STM32L1 IWDG driver (alias for STM32WB IWDG). + * + * The STM32L1 IWDG peripheral is register-compatible with the STM32WB IWDG. + */ + +#include + +typedef whal_Stm32wbIwdg_Cfg whal_Stm32l1Iwdg_Cfg; + +#ifndef WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_IWDG +#define whal_Stm32l1Iwdg_Driver whal_Stm32wbIwdg_Driver +#define whal_Stm32l1Iwdg_Init whal_Stm32wbIwdg_Init +#define whal_Stm32l1Iwdg_Deinit whal_Stm32wbIwdg_Deinit +#define whal_Stm32l1Iwdg_Refresh whal_Stm32wbIwdg_Refresh +#endif /* !WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_IWDG */ + +#define WHAL_STM32L1_IWDG_PR_4 WHAL_STM32WB_IWDG_PR_4 +#define WHAL_STM32L1_IWDG_PR_8 WHAL_STM32WB_IWDG_PR_8 +#define WHAL_STM32L1_IWDG_PR_16 WHAL_STM32WB_IWDG_PR_16 +#define WHAL_STM32L1_IWDG_PR_32 WHAL_STM32WB_IWDG_PR_32 +#define WHAL_STM32L1_IWDG_PR_64 WHAL_STM32WB_IWDG_PR_64 +#define WHAL_STM32L1_IWDG_PR_128 WHAL_STM32WB_IWDG_PR_128 +#define WHAL_STM32L1_IWDG_PR_256 WHAL_STM32WB_IWDG_PR_256 + +#endif /* WHAL_STM32L1_IWDG_H */ diff --git a/wolfHAL/watchdog/stm32l1_wwdg.h b/wolfHAL/watchdog/stm32l1_wwdg.h new file mode 100644 index 0000000..cd42968 --- /dev/null +++ b/wolfHAL/watchdog/stm32l1_wwdg.h @@ -0,0 +1,23 @@ +#ifndef WHAL_STM32L1_WWDG_H +#define WHAL_STM32L1_WWDG_H + +/* + * @file stm32l1_wwdg.h + * @brief STM32L1 WWDG driver (alias for STM32F0 WWDG). + * + * The STM32L1 WWDG peripheral uses the same register layout as the STM32F0 + * (2-bit WDGTB prescaler at CFR bits 8:7). + */ + +#include + +typedef whal_Stm32f0Wwdg_Cfg whal_Stm32l1Wwdg_Cfg; + +#ifndef WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_WWDG +#define whal_Stm32l1Wwdg_Driver whal_Stm32f0Wwdg_Driver +#define whal_Stm32l1Wwdg_Init whal_Stm32f0Wwdg_Init +#define whal_Stm32l1Wwdg_Deinit whal_Stm32f0Wwdg_Deinit +#define whal_Stm32l1Wwdg_Refresh whal_Stm32f0Wwdg_Refresh +#endif /* !WHAL_CFG_WATCHDOG_API_MAPPING_STM32L1_WWDG */ + +#endif /* WHAL_STM32L1_WWDG_H */