From 0044081b92db78084ceab2e4d69d33e8528b9417 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Mon, 18 May 2026 16:31:57 -0400 Subject: [PATCH] [stm32*, pic32, drivers] Add single instnace device struct to each driver --- docs/getting_started.md | 653 ++++++++++++++++------------- src/block/sdhc_spi_block.c | 4 + src/dma/stm32wb_dma.c | 4 + src/dma/stm32wba_gpdma.c | 5 + src/flash/spi_nor_flash.c | 3 + src/i2c/stm32l1_i2c.c | 4 + src/i2c/stm32wb_i2c.c | 7 + src/sensor/imu/bmi270_sensor.c | 4 + src/spi/stm32f4_spi.c | 5 + src/spi/stm32h5_spi.c | 6 + src/spi/stm32wb_spi.c | 7 + src/uart/pic32cz_uart.c | 4 + src/uart/stm32f0_uart.c | 5 + src/uart/stm32f4_uart.c | 5 + src/uart/stm32wb_uart.c | 29 +- src/uart/stm32wb_uart_dma.c | 4 + src/uart/stm32wba_uart_dma.c | 4 + tests/ipc/test_ipc.c | 5 - tests/main.c | 8 - tests/sensor/test_sensor.c | 37 -- wolfHAL/block/sdhc_spi_block.h | 8 + wolfHAL/dma/stm32wb_dma.h | 8 + wolfHAL/dma/stm32wba_gpdma.h | 9 + wolfHAL/flash/spi_nor_flash.h | 8 + wolfHAL/i2c/stm32l1_i2c.h | 8 + wolfHAL/i2c/stm32wb_i2c.h | 11 + wolfHAL/sensor/imu/bmi270_sensor.h | 8 + wolfHAL/spi/stm32f4_spi.h | 9 + wolfHAL/spi/stm32h5_spi.h | 10 + wolfHAL/spi/stm32wb_spi.h | 11 + wolfHAL/uart/pic32cz_uart.h | 8 + wolfHAL/uart/stm32f0_uart.h | 9 + wolfHAL/uart/stm32f4_uart.h | 9 + wolfHAL/uart/stm32wb_uart.h | 16 +- wolfHAL/uart/stm32wb_uart_dma.h | 8 + wolfHAL/uart/stm32wba_uart_dma.h | 8 + 36 files changed, 610 insertions(+), 341 deletions(-) delete mode 100644 tests/sensor/test_sensor.c diff --git a/docs/getting_started.md b/docs/getting_started.md index 137f7df..2f7b7cb 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -11,243 +11,406 @@ my_project/ wolfHAL/ wolfHAL repository (submodule, copy, etc.) boards/ / - board.h Peripheral externs and board constants - board.c Device instances, configuration, and Board_Init + board.h Per-peripheral DEV macros and config initializers + board.c Pointer-based device globals and Board_Init ivt.c Interrupt vector table and Reset_Handler linker.ld Linker script for your MCU - board.mk Toolchain and source list + board.mk Toolchain, source list, and feature flags src/ main.c Application entry point ... Additional application sources Makefile ``` -The key idea is that your project provides the board-level glue (device -instances, pin assignments, clock config, startup code) and wolfHAL provides -the driver implementations and API. +Your project provides the board-level glue (device instances, pin assignments, +clock config, startup code) and wolfHAL provides the driver implementations +and API. ## Adding wolfHAL to Your Project wolfHAL is a source-level library with no external dependencies beyond a C compiler and standard headers (`stdint.h`, `stddef.h`). To use it: -1. Add the wolfHAL repository root to your include path (e.g., `-I/path/to/wolfHAL`) -2. Compile the generic dispatch sources for the modules you need: +1. Add the wolfHAL repository root to your include path (e.g., `-I/path/to/wolfHAL`). +2. Compile the generic dispatch sources for the device types you need + (`src/gpio/gpio.c`, `src/uart/uart.c`, `src/flash/flash.c`, …), **except** + for types where you've enabled direct API mapping — see below. +3. Compile the platform-specific driver sources for your target + (`src/gpio/_gpio.c`, `src/uart/_uart.c`, …). -``` -src/gpio/gpio.c -src/uart/uart.c -src/flash/flash.c -... -``` - -3. Compile the platform-specific driver sources for your target: - -``` -src/gpio/_gpio.c -src/uart/_uart.c -src/flash/_flash.c -... -``` - -You only need to include the modules and platform drivers your project actually -uses. - -Clock drivers are header-only — every `whal___*` helper in -`wolfHAL/clock/_*.h` is a `static inline` function, so there is no -matching `.c` file to compile. +You only need the modules and drivers your project actually uses. ## The Device Model -wolfHAL has three driver categories — platform, peripheral, and board-level -(see `docs/writing_a_driver.md`). Their device structs have slightly -different shapes. +Most HALs hand you a single fixed device struct per peripheral and a single +way to call into it. wolfHAL doesn't, because the deployments it targets are +too different from each other for one shape to fit. A test build that wants +the smallest possible binary on a chip with one of everything has different +needs than a board that hosts on-chip flash *and* an external SPI NOR flash +behind the same `whal_Flash_*` API. So instead of a single shape, a wolfHAL +device sits at a point in a small configuration space: how its state is +*owned* (single-instance device vs caller-passed pointer), how its API is +*dispatched* (direct symbol vs vtable indirection), and where its storage +*lives* (driver `.c` vs `board.c`). Each axis is independent. A board +picks a point per peripheral, and a `BOARD__DEV` macro hides the +choice from application code. + +The rest of this section unpacks each axis, then shows how the four +useful combinations look on a real board. + +### Driver Categories + +- **Platform drivers** talk to SoC registers directly (`stm32wb_uart`, + `stm32wb_gpio`, `stm32wb_aes`). +- **Peripheral drivers** talk to external chips over a bus + (`spi_nor_w25q64`, `sdhc_spi_block`, `bmi270_sensor`, `lan8742a_eth_phy`). +- **Board-level drivers** only expose chip-specific helpers — no vtable, + no generic `whal__*` API, no device struct (clock, power). These + drivers are only called within the board.c for platform init/deinit. + +Platform and peripheral drivers share the same vtable interface — application +code calls `whal_Flash_Read()` whether the flash is on-chip or SPI NOR. +Board-level drivers are the exception: applications reach them through +`Board_()` wrappers in `board.c`, not a generic API. + +The three knobs below apply to platform and peripheral drivers. Board-level +drivers don't have them. For details on board-level drivers, see +`docs/writing_a_driver.md`. + +### Knob 1: Single-instance vs Pointer-based + +**Pointer-based (the default).** The driver reads its `.base` and `.cfg` +from the device handle the caller passes in: -### Platform drivers +```c +whal_Error whal_Stm32wb_Uart_Send(whal_Uart *dev, ...) +{ + size_t base = dev->base; + whal_Stm32wb_Uart_Cfg *cfg = (whal_Stm32wb_Uart_Cfg *)dev->cfg; + /* ... */ +} +``` + +The board declares the device as a `g_whal` global in `board.c`. The +caller passes its address through the API. -Platform drivers operate directly on SoC registers. The device struct has -three fields: +**Single-instance.** The driver reads `.base` and `.cfg` from a named +single-instance device it owns. The handle parameter still exists (the +function sits behind a generic vtable signature) but the body ignores it: ```c -struct whal_Gpio { - const size_t base; /* peripheral base address */ - const whal_GpioDriver *driver; /* vtable of function pointers */ - const void *cfg; /* platform-specific configuration */ -}; -``` +extern const whal_Uart whal_Stm32wb_Uart_Dev; /* in the driver header */ -- **base** — the peripheral's memory-mapped register base address -- **driver** — points to the driver implementation (the vtable) -- **cfg** — points to a driver-specific configuration struct that the - driver reads during Init +whal_Error whal_Stm32wb_Uart_Send(whal_Uart *dev, ...) +{ + size_t base = whal_Stm32wb_Uart_Dev.base; + (void)dev; + /* ... */ +} +``` -Platform headers provide `_BASE` and `_DRIVER` macros for each peripheral, -so you only need to fill in the `cfg`: +The single-instance device struct is *defined* in the driver `.c`, +initialized from a `WHAL_CFG___DEV` macro the board supplies +in `board.h`. The driver `#include`s `board.h` to pull in the +initializer. Callers pass `WHAL_INTERNAL_DEV` (defined as `((void *)0)`) +at the call site to make the intent explicit. + +Single-instance drivers come in two flavors: + +- **Unconditional single-instance.** Used when every chip in this driver's + family has exactly one instance — there's no plausible board where the + pointer path would be exercised. The driver has no `#if` fences: it + always reads from its single-instance device. Examples: GPIO (one + register block per chip), on-chip flash, RNG, on-MCU AES, IWDG, WWDG, + NVIC, SysTick. +- **Conditional single-instance.** Used when the chip generally has + multiple instances but a given board only wires one. Gated by + `WHAL_CFG___SINGLE_INSTANCE`. The driver body is bifurcated + with `#if defined(...SINGLE_INSTANCE...) / #else`: the single-instance + branch reads the single-instance device, the `#else` branch is the + original pointer-based path. Boards opt in per peripheral. Examples: + UART, SPI, I2C, DMA. + +Conditional single-instance is genuinely opt-in: a board with a single +UART can keep the pointer-based path if it prefers (the WB55 board does +this). + +### Knob 2: Direct API Mapping vs Vtable Dispatch + +**Vtable dispatch (the default).** The generic dispatch source +`src//.c` provides the top-level `whal__*` symbols and +forwards each call through a function pointer in the device's `.driver` +field. The board sets `.driver = WHAL___DRIVER` in the device +initializer. + +**Direct API mapping** (`WHAL_CFG__DIRECT_API_MAPPING`). The +chip-specific functions are renamed to the top-level API names at the +definition site, so `src//_.c` itself provides the +`whal__*` symbols. No vtable, no indirection. The board omits the +`.driver` field from the device initializer. ```c -#include +/* board.c — vtable dispatch */ +whal_Flash g_whalFlash = { + .base = WHAL_STM32WB55_FLASH_BASE, + .driver = WHAL_STM32WB55_FLASH_DRIVER, + .cfg = &flashCfg, +}; -/* In board.c (vtable-dispatched driver): */ -whal_Gpio g_whalGpio = { - .base = WHAL_STM32WB55_GPIO_BASE, - .driver = WHAL_STM32WB55_GPIO_DRIVER, - .cfg = &gpioConfig, +/* board.c — direct API mapping */ +whal_Uart g_whalUart = { + .base = WHAL_STM32WB55_UART1_BASE, + /* .driver: direct API mapping */ + .cfg = &uartCfg, }; ``` -When direct API mapping is active for a device type, the `.driver` field is -omitted since calls go directly to the driver implementation. When the driver -is wired as single-instance, the device is defined in the driver's `.c` file -from an initializer macro the board supplies — see the next section. +Two constraints come with direct API mapping: -#### Single-instance platform drivers +1. **Only one driver of that type per build.** Both the dispatch source + and the mapped driver source provide the same top-level symbols, so + the dispatch source must be excluded from `board.mk`. And a board + that needs to host multiple drivers of the same type (e.g. on-chip + flash *and* SPI NOR flash) can't use mapping for that type — it has + to keep vtable dispatch so both drivers can link. +2. **Only one mapping flag per type per build.** Two + `WHAL_CFG___DIRECT_API_MAPPING` flags in the same build + produce duplicate `whal__*` definitions and won't link. -Some platform drivers are wired as **single-instance**: rather than reading -`.base` and `.cfg` from a handle the caller passes in, the driver reads -directly from a named `whal___Dev` singleton. The device handle -parameter becomes a formal-only argument — the board passes -`WHAL_INTERNAL_DEV` (defined as `((void *)0)`) to make that intent explicit. +Mapping flags go in `board.mk` as `-D` flags, not in headers. See +`boards/stm32wb55xx_nucleo/board.mk` for a real list. -There are two flavors: +### Knob 3: Where the Device Storage Lives -- **Unconditional** — the driver always reads from its singleton. Used - for driver types where every supported chip exposes a single instance, - so the pointer-based path would never get exercised. -- **Conditional** — gated on `WHAL_CFG___SINGLE_INSTANCE`. - Used for driver types where chips commonly have more than one instance - (UART, SPI, I2C, DMA, etc.). The default build keeps the pointer-based - path; boards opt in per driver via the macro when they only use one - instance. +This knob is tightly coupled to knob 1, but worth naming explicitly: -The driver header `extern`-declares the singleton; the driver `.c` defines -it from a `WHAL_CFG___DEV` initializer macro the board provides in -`board.h`: +- **Pointer-based driver →** device is a `g_whal` global in `board.c`. + The board owns the storage; the driver `.c` never sees it. +- **Single-instance driver →** the *single-instance device struct* + (storage) lives in the driver `.c`, defined from a + `WHAL_CFG___DEV` initializer macro in `board.h`. The board + owns the macro's *contents*, the driver owns the device's *storage*. -```c -/* wolfHAL/rng/stm32wb_rng.h */ -extern const whal_Rng whal_Stm32wb_Rng_Dev; +For the single-instance case, the driver `.c` `#include`s `board.h` at +the top so the preprocessor can see the initializer when it defines the +single-instance device: +```c /* src/rng/stm32wb_rng.c */ #include "board.h" const whal_Rng whal_Stm32wb_Rng_Dev = WHAL_CFG_STM32WB_RNG_DEV; - -/* boards//board.h */ -#define WHAL_CFG_STM32WB_RNG_DEV { \ - .base = WHAL_STM32WB55_RNG_BASE, \ - .cfg = (void *)&(const whal_Stm32wb_Rng_Cfg){ .timeout = &g_whalTimeout }, \ -} ``` -Aliased drivers (where one chip's driver re-exports another's) reuse the -upstream singleton's extern declaration through a `#define` in the alias -header — see `wolfHAL/watchdog/stm32n6_iwdg.h` for an example. +If a single-instance driver needs mutable scratch state (e.g. an AES-GCM +state struct), that storage is also `static` in the driver `.c`; the +`WHAL_CFG_*_DEV` macro's `.state` field plumbs its address through. See +`g_stm32wbAesGcmDevState` in `src/crypto/stm32wb_aes.c`. -### Peripheral drivers +### `BOARD__DEV` Ties It Together -Peripheral drivers talk to external chips over a bus (SPI, I2C, MDIO). The -device struct shape mirrors platform drivers — same vtable + cfg pattern — -but instead of a register block the device carries the bus handle and any -chip-specific addressing inside its cfg: +The three knobs are per-peripheral choices, so application code that +hard-codes `&g_whalUart` or `WHAL_INTERNAL_DEV` becomes non-portable as +soon as the board changes one. Each `board.h` defines a `BOARD__DEV` +macro per peripheral that resolves to whichever shape the board uses: ```c -whal_Flash g_whalSpiFlash = { - .driver = WHAL_SPI_NOR_W25Q64_FLASH_DRIVER, - .cfg = &(whal_SpiNor_W25q64_Cfg) { - .spi = BOARD_SPI_DEV, /* underlying bus driver, per board.h */ - .csPin = SPI_FLASH_CS_PIN, - /* ...chip-specific fields... */ - }, -}; +/* boards/stm32wb55xx_nucleo/board.h */ +#define BOARD_GPIO_DEV WHAL_INTERNAL_DEV +#define BOARD_UART_DEV (&g_whalUart) +#define BOARD_SPI_DEV (&g_whalSpi) +#define BOARD_I2C_DEV (&g_whalI2c) +#define BOARD_FLASH_DEV ((whal_Flash *)&whal_Stm32wb_Flash_Dev) +#define BOARD_WATCHDOG_DEV WHAL_INTERNAL_DEV +#define BOARD_RNG_DEV WHAL_INTERNAL_DEV +#define BOARD_AES_GCM_DEV WHAL_INTERNAL_DEV +/* ... */ ``` -The application calls the same generic API (`whal_Flash_Read(&g_whalSpiFlash, ...)`) -whether the flash is on-chip (platform driver) or external SPI NOR (peripheral -driver) — the device pointer determines which implementation runs. +Apps call `whal_Rng_Generate(BOARD_RNG_DEV, ...)` regardless of which +shape the board picked. Three shapes show up in practice: + +- **`WHAL_INTERNAL_DEV`** — single-instance driver. The driver body + ignores the pointer, so the sentinel just documents the intent. +- **`(&g_whal)`** — pointer-based driver. The board defines the global + in `board.c`. +- **`((whal_ *)&whal___Dev)`** — single-instance driver + *with* vtable dispatch (knobs 1 and 2 are independent). The + single-instance device lives in the driver `.c`, but the API call + still vtable-dispatches because another driver of the same type + coexists. The cast strips the `const` since the generic API takes a + non-const pointer. + +### Worked Combinations + +The four combinations of knobs 1 and 2 all appear on +`boards/stm32wb55xx_nucleo` (with knob 3 falling out of knob 1): + +| Peripheral | Knob 1 | Knob 2 | `BOARD_*_DEV` resolves to | +|---|---|---|---| +| GPIO, RNG, IWDG, NVIC, SysTick, AES* | unconditional single-instance | direct mapping | `WHAL_INTERNAL_DEV` | +| On-chip Flash | unconditional single-instance | **vtable** (SPI NOR coexists) | `(whal_Flash *)&whal_Stm32wb_Flash_Dev` | +| UART, SPI, I2C | **pointer** (board didn't opt into conditional single-instance) | direct mapping | `&g_whal` | +| SPI NOR W25Q64 | pointer | vtable (peripheral driver) | `&g_whalSpiNorW25q64` | + +\* Including the per-algorithm AES devices (ECB, CBC, CTR, GCM, GMAC, CCM). + +The UART row is the most instructive: STM32WB has conditional +single-instance available for UART, and the WB55 board only wires one +UART, but the board chose to keep it pointer-based anyway. That's a +legitimate choice — conditional single-instance is opt-in, not automatic. +The Flash row is the second-most: on-chip Flash is unconditional +single-instance, yet its `BOARD_FLASH_DEV` still uses vtable dispatch +because the peripheral board's SPI NOR driver shares the `whal_Flash_*` +API and both have to be linkable simultaneously. -### Board-level drivers +## Configuring Devices -Board-level drivers (clock, power) only expose chip-specific helpers — no -vtable, no generic `whal__*` API, no device struct. The driver header -owns the chip's `_BASE` macro at the top and the helpers take no device -pointer: +Each driver defines its own configuration struct. The knob-1 choice +determines where you put the device initializer. -```c -/* wolfHAL/clock/stm32wb_rcc.h (excerpt) */ -#define WHAL_STM32WB_RCC_BASE 0x58000000 +### Single-instance: `WHAL_CFG___DEV` in `board.h` + +The driver `.c` defines the single-instance device struct from a +`WHAL_CFG___DEV` initializer macro that the board supplies in +`board.h`. The board never defines the storage itself — it only writes +the macro. The driver header `extern`-declares the device so the board +(and any code that needs to take its address) can see it. + +A typical single-instance initializer for a driver with both `.base` and +`.cfg`: -static inline whal_Error whal_Stm32wb_Rcc_EnableMsi( - whal_Stm32wb_Rcc_MsiRange range); +```c +/* boards/stm32wb55xx_nucleo/board.h */ +#define WHAL_CFG_STM32WB_RNG_DEV { \ + .base = WHAL_STM32WB55_RNG_BASE, \ + /* .driver: direct API mapping */ \ + .cfg = (void *)&(const whal_Stm32wb_Rng_Cfg){ \ + .timeout = &g_whalTimeout, \ + }, \ +} ``` -Boards bring up the clock tree imperatively in `Board_Init` by calling these -helpers in the required order — `whal_Stm32wb_Rcc_EnableOsc()`, -`EnablePll()`, `SetSysClock()`, etc. Applications that need to trigger -board-level behavior at runtime (e.g., enter low-power mode) call a -board-provided wrapper such as `Board_Sleep()` rather than a generic -`whal_X` function. +A few important shape details: -## Configuring Devices +- The `.cfg` payload is a **compound literal cast to `const` and pointed + at**. Because the macro expands inside the device's static + initializer, the compound literal also gets static storage duration — + it's not on a stack frame. +- The `.driver` field is omitted when direct API mapping is active for + this type. Leave the `/* .driver: direct API mapping */` comment so + readers know the omission is intentional, not an oversight. +- If the driver pairs with another driver of the same type (knob 2 says + vtable), `.driver` *is* present — see the Flash example below. -Each platform driver defines its own configuration struct with the parameters -it needs. For example, a GPIO driver takes a pin configuration table; the -platform usually provides a `WHAL__GPIO_PIN(...)` macro to populate -each entry compactly: +When the on-chip Flash coexists with an external SPI NOR Flash on the +same board, the single-instance driver still has its device struct in +the driver `.c`, but the initializer keeps `.driver` so `whal_Flash_*` +calls can vtable-dispatch: + +```c +/* boards/stm32wb55xx_nucleo/board.h */ +#define WHAL_CFG_STM32WB_FLASH_DEV { \ + .driver = WHAL_STM32WB55_FLASH_DRIVER, \ + .base = WHAL_STM32WB55_FLASH_BASE, \ + .cfg = (void *)&(const whal_Stm32wb_Flash_Cfg){ \ + .timeout = &g_whalTimeout, \ + .startAddr = 0x08000000, \ + .size = 0x80000, \ + }, \ +} +``` -For GPIO (a single-instance driver — see above), the singleton is defined -in the driver `.c` from a `WHAL_CFG___DEV` initializer in `board.h`: +The GPIO case is the same shape but its `.cfg` is much larger — a pin +table. The board's `enum { LED_PIN, UART_TX_PIN, ... PIN_COUNT }` gives +each pin an index, and the initializer fills the table by index using a +`WHAL__GPIO_PIN(...)` helper macro: ```c -/* board.h */ +/* boards/stm32wb55xx_nucleo/board.h */ #define WHAL_CFG_STM32WB_GPIO_DEV { \ .base = WHAL_STM32WB55_GPIO_BASE, \ - /* .driver: direct API mapping */ \ - .cfg = (void *)&(const whal_Stm32wb_Gpio_Cfg){ \ + .cfg = (void *)&(const whal_Stm32wb_Gpio_Cfg){ \ .pinCfg = (const whal_Stm32wb_Gpio_PinCfg[PIN_COUNT]){ \ [LED_PIN] = WHAL_STM32WB_GPIO_PIN( \ WHAL_STM32WB_GPIO_PORT_B, 5, WHAL_STM32WB_GPIO_MODE_OUT, \ WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32WB_GPIO_SPEED_LOW, \ WHAL_STM32WB_GPIO_PULL_UP, 0), \ + [UART_TX_PIN] = WHAL_STM32WB_GPIO_PIN( \ + WHAL_STM32WB_GPIO_PORT_B, 6, WHAL_STM32WB_GPIO_MODE_ALTFN, \ + WHAL_STM32WB_GPIO_OUTTYPE_PUSHPULL, WHAL_STM32WB_GPIO_SPEED_FAST, \ + WHAL_STM32WB_GPIO_PULL_UP, 7), \ + /* ... one entry per pin in the enum ... */ \ }, \ .pinCount = PIN_COUNT, \ }, \ } ``` -A UART driver typically takes a pre-computed baud rate register value and a -timeout. For boards that opt the UART into single-instance, the device -goes alongside GPIO in `board.h`; otherwise it stays in `board.c` as a -regular `g_whal` global: +### Pointer-based: `g_whal` global in `board.c` + +For drivers that aren't single-instance (either because the chip +genuinely has many instances and the driver is conditional-single-instance +without the flag set, or because the board chose not to opt in), the +device lives in `board.c` as a regular global: ```c +/* boards/stm32wb55xx_nucleo/board.c — pointer-based UART, direct mapping */ whal_Uart g_whalUart = { .base = WHAL_STM32WB55_UART1_BASE, /* .driver: direct API mapping */ - - .cfg = &(whal_Stm32wb_Uart_Cfg) { - .brr = WHAL_STM32WB_UART_BRR(64000000, 115200), + .cfg = &(whal_Stm32wb_Uart_Cfg) { + .brr = WHAL_STM32WB_UART_BRR(64000000, 115200), .timeout = &g_whalTimeout, }, }; ``` -The `.driver: direct API mapping` comment indicates this peripheral is using -the optimization path described above — calls to `whal_Uart_*` link directly -to the chip-specific implementation, no vtable dispatch. +And `board.h` declares it `extern` and points `BOARD_UART_DEV` at it: + +```c +extern whal_Uart g_whalUart; +#define BOARD_UART_DEV (&g_whalUart) +``` + +For peripheral drivers (which talk over a bus), the `.cfg` carries the +bus device pointer plus chip-specific addressing. SPI NOR W25Q64 is a +good reference: -See the platform-specific headers in `wolfHAL//` for the full set -of configuration options for each driver, and the example boards in `boards/` -for full instantiations. +```c +/* boards/peripheral/flash/spi_nor_w25q64.c */ +whal_Flash g_whalSpiNorW25q64 = { + .driver = &whal_SpiNor_Driver, + .cfg = &(whal_SpiNor_Cfg) { + .spiDev = BOARD_SPI_DEV, /* uses the board's SPI device */ + .spiComCfg = &g_w25q64ComCfg, /* freq, mode, wordSz, dataLines */ + .gpioDev = BOARD_GPIO_DEV, /* GPIO controller for chip select */ + .csPin = SPI_CS_PIN, + .timeout = &g_whalTimeout, + .pageSz = W25Q64_PAGE_SZ, + .capacity = W25Q64_CAPACITY, + }, +}; +``` + +The same generic API runs against either flash device — the vtable in +each `.driver` field dispatches to the right implementation. Application +code calls `whal_Flash_Read(BOARD_FLASH_DEV, ...)` for on-chip flash and +`whal_Flash_Read(BOARD_SPI_FLASH_DEV, ...)` for the W25Q64 with no other +difference. + +See the platform-specific headers in `wolfHAL//` for each +driver's full config struct, and the example boards in `boards/` for +complete instantiations. ## Initialization The board is responsible for initializing peripherals in dependency order. Drivers do not enable their own clocks or power supplies — the board must -handle these prerequisites explicitly before calling a driver's Init. +handle these prerequisites explicitly before calling each driver's `Init`. -A typical initialization sequence: +A typical sequence: -1. Do any pre-clock-controller initialization (e.g., flash wait states, - power supplies) +1. Pre-clock setup (flash wait states, power supplies) 2. Bring up the clock tree (oscillators, optional PLL, sysclk source) 3. Enable peripheral clocks 4. Initialize peripheral drivers @@ -258,67 +421,47 @@ the board calls in order. There is no generic `whal_Clock_Init` walker — clock-tree shape varies too much across vendors to abstract. ```c -static const whal_Myplatform_Clock_PeriphClk g_periphClks[] = { - {MY_PLATFORM_GPIOB_CLOCK}, - {MY_PLATFORM_UART1_CLOCK}, +static const whal_Myplatform_Rcc_PeriphClk g_periphClks[] = { + {WHAL_MYPLATFORM_GPIOB_GATE}, + {WHAL_MYPLATFORM_UART1_GATE}, }; -#define PERIPH_CLK_COUNT \ - (sizeof(g_periphClks) / sizeof(g_periphClks[0])) +#define PERIPH_CLK_COUNT (sizeof(g_periphClks) / sizeof(g_periphClks[0])) whal_Error Board_Init(void) { whal_Error err; - /* Bring up clocks (chip-specific helpers, called in order — no device - * pointer; each helper reads the chip's fixed clock-controller base - * address from its own header). */ - err = whal_Myplatform_Clock_EnableOsc( - &(whal_Myplatform_Clock_OscCfg){WHAL_MYPLATFORM_CLOCK_OSC0_CFG}); - if (err) - return err; - err = whal_Myplatform_Clock_SetSysClock( - WHAL_MYPLATFORM_CLOCK_SYSCLK_SRC_OSC0); - if (err) - return err; - - /* Enable peripheral clocks */ + /* Bring up clocks — chip-specific helpers, called in order. No device + * pointer; each helper reads the chip's fixed base from its own header. */ + err = whal_Myplatform_Rcc_EnableOsc( + &(whal_Myplatform_Rcc_OscCfg){WHAL_MYPLATFORM_OSC0_CFG}); + if (err) return err; + err = whal_Myplatform_Rcc_SetSysClock(WHAL_MYPLATFORM_SYSCLK_SRC_OSC0); + if (err) return err; + + /* Enable peripheral clocks. */ for (size_t i = 0; i < PERIPH_CLK_COUNT; i++) { - err = whal_Myplatform_Clock_EnablePeriphClk(&g_periphClks[i]); - if (err) - return err; + err = whal_Myplatform_Rcc_EnablePeriphClk(&g_periphClks[i]); + if (err) return err; } - /* Initialize peripherals through the board's BOARD__DEV macros */ - err = whal_Gpio_Init(BOARD_GPIO_DEV); - if (err) - return err; - - err = whal_Uart_Init(BOARD_UART_DEV); - if (err) - return err; - - err = whal_Timer_Init(BOARD_TIMER_DEV); - if (err) - return err; - - err = whal_Timer_Start(BOARD_TIMER_DEV); - if (err) - return err; + /* Initialize peripherals through BOARD__DEV. */ + err = whal_Gpio_Init(BOARD_GPIO_DEV); if (err) return err; + err = whal_Uart_Init(BOARD_UART_DEV); if (err) return err; + err = whal_Timer_Init(BOARD_TIMER_DEV); if (err) return err; + err = whal_Timer_Start(BOARD_TIMER_DEV); if (err) return err; return WHAL_SUCCESS; } ``` -See the board examples in `boards/` for complete initialization sequences -including platform-specific steps. +See the board examples in `boards/` for complete sequences. ## Using the API After initialization, use the wolfHAL API to interact with peripherals. -Reach each device through the `BOARD__DEV` macro that `board.h` -provides — the board picks whether that resolves to `WHAL_INTERNAL_DEV` (for -single-instance drivers) or `&g_whal` (for vtable-dispatched drivers), -so the application source stays portable. +Always reach each device through `BOARD__DEV` so application source +stays portable across boards. ```c #include @@ -340,62 +483,28 @@ void main(void) } ``` -All API functions return `whal_Error`. Check for `WHAL_SUCCESS` to confirm the -operation completed. The error codes are: +All API functions return `whal_Error`. The codes are: | Code | Meaning | |------|---------| | `WHAL_SUCCESS` | Operation completed successfully | | `WHAL_EINVAL` | Invalid argument (null device pointer, null data pointer) | +| `WHAL_ENOTSUP` | Argument value not supported by this driver/hardware | | `WHAL_ENOTREADY` | Resource is busy or not yet available | | `WHAL_EHARDWARE` | Hardware error (e.g., RNG entropy failure) | | `WHAL_ETIMEOUT` | Operation timed out waiting for hardware | -| `WHAL_ENOTSUP` | Operation or parameter not supported by this driver/hardware | - -## Optimizing for Size - -wolfHAL gives you several ways to reduce code size depending on how much -control you want. - -### Direct API Mapping -Each driver source (platform or peripheral) provides an `#ifdef` block that -renames its driver functions to the top-level API names. When the -corresponding `WHAL_CFG__API_MAPPING_` flag is defined, the -driver file itself provides the definition of the top-level API — no -wrapper, no vtable indirection, no runtime null-check. +## Reducing Code Size Further -For example, `-DWHAL_CFG_UART_API_MAPPING_STM32WB` causes -`src/uart/stm32wb_uart.c` to emit external symbols named `whal_Uart_Init`, -`whal_Uart_Deinit`, `whal_Uart_Send`, and `whal_Uart_Recv`, each bound to -the polled STM32WB UART driver body. Application code calling -`whal_Uart_Send(&dev, buf, sz)` links directly to the driver. +Knob 2 (direct API mapping) and knob 1 (single-instance) already remove +the dispatch and indirection overheads. A few additional knobs help when +you need to squeeze further. -The same pattern works for peripheral drivers: enabling -`WHAL_CFG_SDHC_SPI_BLOCK_DIRECT_API_MAPPING`, for instance, makes the -external SD-card-over-SPI driver provide the top-level `whal_Block_*` API -symbols directly. +### Custom vtables -Direct API mapping is only safe when a single driver of that type is -present in the build. Boards that combine multiple drivers of the same type -(e.g., on-chip flash + external SPI NOR flash) cannot enable mapping for -that type — they keep the vtable dispatch so both drivers can be linked -simultaneously. - -**The dispatch source `src//.c` must not be compiled when the -corresponding mapping flag is active.** Both the dispatch source and the -mapped driver source provide the same top-level symbols, which would cause -a multiple-definition link error. Exclude the dispatch source from the -board's source list. - -Only one mapping flag may be active per device type per build. - -### Custom Vtables - -The platform drivers provide a pre-built vtable with all operations populated. -For vtable-dispatched devices, if you only use a subset of a driver's -functionality, you can define your own vtable that only includes the functions -you need: +For vtable-dispatched devices, the platform driver exports a full vtable +with every operation populated. If you only use a subset, define your +own vtable with just the entries you need: ```c static const whal_SpiDriver mySpiDriver = { @@ -413,20 +522,16 @@ whal_Spi g_whalSpi = { }; ``` -With link-time optimization (`-flto`) or garbage collection (`-ffunction-sections` -+ `-Wl,--gc-sections`), any driver functions not referenced through the vtable -will be stripped from the final binary. +With `-ffunction-sections -fdata-sections -Wl,--gc-sections`, the unused +driver functions are stripped from the final binary. -Single-instance drivers (see above) are not vtable-dispatched in their -single-instance form — the driver body reads its `.base` and `.cfg` straight -out of the named singleton its `.c` defines from `WHAL_CFG___DEV` -in `board.h`. The "custom vtable" knob does not apply; any unreferenced -entry point is dropped by `--gc-sections`. +This knob is meaningless for direct-API-mapping devices — those have no +vtable, and `--gc-sections` already drops any unreferenced entry points. -### Calling Driver Functions Directly +### Calling driver functions directly -For maximum control on a vtable-dispatched driver, you can skip the vtable -and call the underlying platform driver functions directly: +For maximum control on a vtable-dispatched, pointer-based driver, you +can skip the vtable and call the chip-specific function directly: ```c #include @@ -435,48 +540,30 @@ whal_Stm32wb_Uart_Init(&g_whalUart); whal_Stm32wb_Uart_Send(&g_whalUart, "hi\r\n", 4); ``` -This eliminates the vtable indirection and lets the compiler inline or -optimize the calls more aggressively. - -Single-instance drivers fall into two cases depending on whether direct API -mapping is also active for them: +This eliminates the vtable indirection and lets the compiler inline more +aggressively. For single-instance drivers the equivalent is to call the +chip-specific function with `WHAL_INTERNAL_DEV`: -- **Single-instance + direct API mapping** (the common case for RNG, - watchdog, NVIC, etc.). The chip-specific functions are renamed to the - generic API names, and the driver body reads from the singleton (which - the driver `.c` defines from the `WHAL_CFG___DEV` initializer - in `board.h`). Call sites pass `WHAL_INTERNAL_DEV`: - - ```c - whal_Stm32wb_Gpio_Set(WHAL_INTERNAL_DEV, BOARD_LED_PIN, 1); - ``` - -- **Single-instance without direct API mapping** (used when several - drivers of the same type must coexist on one board — for example - on-chip flash plus an external SPI-NOR flash). The chip's `_Dev` - singleton (defined in the driver `.c` from the `WHAL_CFG___DEV` - initializer) carries `.driver`, `.base`, and `.cfg`, so generic API - calls vtable-dispatch through it. Call sites pass the singleton's - address (cast away the const because the generic API takes a non-const - pointer): +```c +whal_Stm32wb_Gpio_Set(WHAL_INTERNAL_DEV, BOARD_LED_PIN, 1); +``` - ```c - whal_Stm32wb_Flash_Read((whal_Flash *)&whal_Stm32wb_Flash_Dev, - addr, buf, sz); - ``` +The `BOARD__DEV` macros normally hide this distinction — only reach +for direct chip-specific calls when portability across boards is not a +goal (e.g. board-internal code). -The `BOARD__DEV` macros described above abstract this distinction -away from application code — boards point each macro at whichever shape -they wired. +### Disabling timeouts -Register-level drivers do not call other drivers internally, so this works -without any caveats. Peripheral drivers (e.g., SPI flash) still call their -bus driver through the vtable. +Define `WHAL_CFG_NO_TIMEOUT` globally to remove all timeout logic from +the binary. `WHAL_TIMEOUT_START` becomes a no-op and `WHAL_TIMEOUT_EXPIRED` +always evaluates to `0`, so polling loops run until the hardware +condition is met. Useful when you trust the hardware and care more about +code size than about bounding a stuck-bus hang. ## Next Steps -- See `boards/` for complete board configuration examples -- See [Writing a Driver](writing_a_driver.md) for how to add support for a new - platform -- See [Adding a Board](adding_a_board.md) for how to create a board - configuration for your hardware +- See `boards/` for complete board configuration examples. +- See [Writing a Driver](writing_a_driver.md) for how to add support for + a new platform. +- See [Adding a Board](adding_a_board.md) for how to wire up a new + hardware target. diff --git a/src/block/sdhc_spi_block.c b/src/block/sdhc_spi_block.c index 3c0512c..79857c5 100644 --- a/src/block/sdhc_spi_block.c +++ b/src/block/sdhc_spi_block.c @@ -68,6 +68,10 @@ #define whal_SdhcSpi_Erase whal_Block_Erase #endif /* WHAL_CFG_SDHC_SPI_BLOCK_DIRECT_API_MAPPING */ +#ifdef WHAL_CFG_SDHC_SPI_SINGLE_INSTANCE +const whal_Block whal_SdhcSpi_Dev = WHAL_CFG_SDHC_SPI_DEV; +#endif + static whal_Error SdhcSpi_CsAssert(whal_SdhcSpi_Cfg *cfg) { uint8_t dummy = DUMMY; diff --git a/src/dma/stm32wb_dma.c b/src/dma/stm32wb_dma.c index bc20d56..bd5bb31 100644 --- a/src/dma/stm32wb_dma.c +++ b/src/dma/stm32wb_dma.c @@ -120,6 +120,10 @@ #define whal_Stm32wb_Dma_Stop whal_Dma_Stop #endif /* WHAL_CFG_STM32WB_DMA_DIRECT_API_MAPPING */ +#ifdef WHAL_CFG_STM32WB_DMA_SINGLE_INSTANCE +const whal_Dma whal_Stm32wb_Dma_Dev = WHAL_CFG_STM32WB_DMA_DEV; +#endif + whal_Error whal_Stm32wb_Dma_Init(whal_Dma *dmaDev) { #ifdef WHAL_CFG_STM32WB_DMA_SINGLE_INSTANCE diff --git a/src/dma/stm32wba_gpdma.c b/src/dma/stm32wba_gpdma.c index 30eb96b..00508bd 100644 --- a/src/dma/stm32wba_gpdma.c +++ b/src/dma/stm32wba_gpdma.c @@ -138,6 +138,11 @@ #define whal_Stm32wba_Gpdma_Stop whal_Dma_Stop #endif +#if defined(WHAL_CFG_STM32WBA_GPDMA_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_GPDMA_SINGLE_INSTANCE) +const whal_Dma whal_Stm32wba_Gpdma_Dev = WHAL_CFG_STM32WBA_GPDMA_DEV; +#endif + whal_Error whal_Stm32wba_Gpdma_Init(whal_Dma *dmaDev) { #if defined(WHAL_CFG_STM32WBA_GPDMA_SINGLE_INSTANCE) || \ diff --git a/src/flash/spi_nor_flash.c b/src/flash/spi_nor_flash.c index f0c4345..525a21a 100644 --- a/src/flash/spi_nor_flash.c +++ b/src/flash/spi_nor_flash.c @@ -72,6 +72,9 @@ #define DUMMY 0xFF +#ifdef WHAL_CFG_SPI_NOR_SINGLE_INSTANCE +const whal_Flash whal_SpiNor_Dev = WHAL_CFG_SPI_NOR_DEV; +#endif static whal_Error SpiNor_CsAssert(whal_SpiNor_Cfg *cfg) { diff --git a/src/i2c/stm32l1_i2c.c b/src/i2c/stm32l1_i2c.c index 35be051..5a51416 100644 --- a/src/i2c/stm32l1_i2c.c +++ b/src/i2c/stm32l1_i2c.c @@ -102,6 +102,10 @@ #define whal_Stm32l1_I2c_Transfer whal_I2c_Transfer #endif +#ifdef WHAL_CFG_STM32L1_I2C_SINGLE_INSTANCE +const whal_I2c whal_Stm32l1_I2c_Dev = WHAL_CFG_STM32L1_I2C_DEV; +#endif + static whal_Error Stm32l1_I2c_WaitSR1(size_t base, uint32_t flag, whal_Timeout *timeout) { diff --git a/src/i2c/stm32wb_i2c.c b/src/i2c/stm32wb_i2c.c index 8b4f995..519b107 100644 --- a/src/i2c/stm32wb_i2c.c +++ b/src/i2c/stm32wb_i2c.c @@ -159,6 +159,13 @@ #define whal_Stm32wb_I2c_Transfer whal_I2c_Transfer #endif /* WHAL_CFG_I2C_API_MAPPING */ +#if defined(WHAL_CFG_STM32WB_I2C_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F0_I2C_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F3_I2C_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_I2C_SINGLE_INSTANCE) +const whal_I2c whal_Stm32wb_I2c_Dev = WHAL_CFG_STM32WB_I2C_DEV; +#endif + static uint32_t Stm32wb_I2c_CalcTimingr(uint32_t pclk, uint32_t freq) { uint32_t tLowNs, tHighNs; diff --git a/src/sensor/imu/bmi270_sensor.c b/src/sensor/imu/bmi270_sensor.c index 9c4177c..b82ebc6 100644 --- a/src/sensor/imu/bmi270_sensor.c +++ b/src/sensor/imu/bmi270_sensor.c @@ -63,6 +63,10 @@ #define whal_Bmi270_Read whal_Sensor_Read #endif /* WHAL_CFG_BMI270_SENSOR_DIRECT_API_MAPPING */ +#ifdef WHAL_CFG_BMI270_SINGLE_INSTANCE +const whal_Sensor whal_Bmi270_Dev = WHAL_CFG_BMI270_DEV; +#endif + whal_Error whal_Bmi270_Init(whal_Sensor *dev) { whal_Bmi270_Cfg *cfg; diff --git a/src/spi/stm32f4_spi.c b/src/spi/stm32f4_spi.c index e297111..f926f55 100644 --- a/src/spi/stm32f4_spi.c +++ b/src/spi/stm32f4_spi.c @@ -90,6 +90,11 @@ #define whal_Stm32f4_Spi_SendRecv whal_Spi_SendRecv #endif /* WHAL_CFG_STM32F4_SPI_DIRECT_API_MAPPING */ +#if defined(WHAL_CFG_STM32F4_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32L1_SPI_SINGLE_INSTANCE) +const whal_Spi whal_Stm32f4_Spi_Dev = WHAL_CFG_STM32F4_SPI_DEV; +#endif + /* * Calculate the baud rate prescaler index for a target baud rate. * diff --git a/src/spi/stm32h5_spi.c b/src/spi/stm32h5_spi.c index 85f7be6..d553a9c 100644 --- a/src/spi/stm32h5_spi.c +++ b/src/spi/stm32h5_spi.c @@ -124,6 +124,12 @@ #define whal_Stm32h5_Spi_SendRecv whal_Spi_SendRecv #endif /* WHAL_CFG_STM32H5_SPI_DIRECT_API_MAPPING */ +#if defined(WHAL_CFG_STM32H5_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_SPI_SINGLE_INSTANCE) +const whal_Spi whal_Stm32h5_Spi_Dev = WHAL_CFG_STM32H5_SPI_DEV; +#endif + /* * Calculate the baud rate prescaler index for a target baud rate. * SPI baud rate = fPCLK / (2 ^ (MBR + 1)) diff --git a/src/spi/stm32wb_spi.c b/src/spi/stm32wb_spi.c index 7259603..3cc609b 100644 --- a/src/spi/stm32wb_spi.c +++ b/src/spi/stm32wb_spi.c @@ -98,6 +98,13 @@ #define whal_Stm32wb_Spi_SendRecv whal_Spi_SendRecv #endif /* WHAL_CFG_SPI_API_MAPPING */ +#if defined(WHAL_CFG_STM32WB_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32C0_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F0_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F3_SPI_SINGLE_INSTANCE) +const whal_Spi whal_Stm32wb_Spi_Dev = WHAL_CFG_STM32WB_SPI_DEV; +#endif + /* * Calculate the baud rate prescaler index for a target baud rate. * diff --git a/src/uart/pic32cz_uart.c b/src/uart/pic32cz_uart.c index f535ab7..a1e7435 100644 --- a/src/uart/pic32cz_uart.c +++ b/src/uart/pic32cz_uart.c @@ -192,6 +192,10 @@ #define whal_Pic32cz_Uart_RecvAsync whal_Uart_RecvAsync #endif /* WHAL_CFG_PIC32CZ_UART_DIRECT_API_MAPPING */ +#ifdef WHAL_CFG_PIC32CZ_UART_SINGLE_INSTANCE +const whal_Uart whal_Pic32cz_Uart_Dev = WHAL_CFG_PIC32CZ_UART_DEV; +#endif + whal_Error whal_Pic32cz_Uart_Init(whal_Uart *uartDev) { whal_Error err; diff --git a/src/uart/stm32f0_uart.c b/src/uart/stm32f0_uart.c index f2811bc..16adef8 100644 --- a/src/uart/stm32f0_uart.c +++ b/src/uart/stm32f0_uart.c @@ -69,6 +69,11 @@ #define whal_Stm32f0_Uart_RecvAsync whal_Uart_RecvAsync #endif +#if defined(WHAL_CFG_STM32F0_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F3_UART_SINGLE_INSTANCE) +const whal_Uart whal_Stm32f0_Uart_Dev = WHAL_CFG_STM32F0_UART_DEV; +#endif + whal_Error whal_Stm32f0_Uart_Init(whal_Uart *uartDev) { #if defined(WHAL_CFG_STM32F0_UART_SINGLE_INSTANCE) || \ diff --git a/src/uart/stm32f4_uart.c b/src/uart/stm32f4_uart.c index 8a64d1c..c1de6cd 100644 --- a/src/uart/stm32f4_uart.c +++ b/src/uart/stm32f4_uart.c @@ -80,6 +80,11 @@ #define whal_Stm32f4_Uart_RecvAsync whal_Uart_RecvAsync #endif /* WHAL_CFG_STM32F4_UART_DIRECT_API_MAPPING */ +#if defined(WHAL_CFG_STM32F4_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32L1_UART_SINGLE_INSTANCE) +const whal_Uart whal_Stm32f4_Uart_Dev = WHAL_CFG_STM32F4_UART_DEV; +#endif + whal_Error whal_Stm32f4_Uart_Init(whal_Uart *uartDev) { uint32_t brr; diff --git a/src/uart/stm32wb_uart.c b/src/uart/stm32wb_uart.c index 26736b7..6f3bcba 100644 --- a/src/uart/stm32wb_uart.c +++ b/src/uart/stm32wb_uart.c @@ -23,7 +23,8 @@ #if defined(WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32H5_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32C0_UART_SINGLE_INSTANCE) || \ - defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) + defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_UART_SINGLE_INSTANCE) #include "board.h" /* provides whal_Stm32wb_Uart_Dev singleton (possibly via platform alias macro) */ #endif #include @@ -71,7 +72,8 @@ #if defined(WHAL_CFG_STM32WB_UART_DIRECT_API_MAPPING) || \ defined(WHAL_CFG_STM32H5_UART_DIRECT_API_MAPPING) || \ defined(WHAL_CFG_STM32C0_UART_DIRECT_API_MAPPING) || \ - defined(WHAL_CFG_STM32N6_UART_DIRECT_API_MAPPING) + defined(WHAL_CFG_STM32N6_UART_DIRECT_API_MAPPING) || \ + defined(WHAL_CFG_STM32WBA_UART_DIRECT_API_MAPPING) #define whal_Stm32wb_Uart_Init whal_Uart_Init #define whal_Stm32wb_Uart_Deinit whal_Uart_Deinit #define whal_Stm32wb_Uart_Send whal_Uart_Send @@ -85,13 +87,22 @@ #define whal_Stm32wb_Uart_Deinit whal_Uart_Deinit #endif /* WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING */ +#if defined(WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32H5_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32C0_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_UART_SINGLE_INSTANCE) +const whal_Uart whal_Stm32wb_Uart_Dev = WHAL_CFG_STM32WB_UART_DEV; +#endif + whal_Error whal_Stm32wb_Uart_Init(whal_Uart *uartDev) { uint32_t brr; #if defined(WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32H5_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32C0_UART_SINGLE_INSTANCE) || \ - defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) + defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_UART_SINGLE_INSTANCE) const whal_Stm32wb_Uart_Cfg *cfg = (const whal_Stm32wb_Uart_Cfg *)whal_Stm32wb_Uart_Dev.cfg; size_t base = whal_Stm32wb_Uart_Dev.base; @@ -129,7 +140,8 @@ whal_Error whal_Stm32wb_Uart_Deinit(whal_Uart *uartDev) #if defined(WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32H5_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32C0_UART_SINGLE_INSTANCE) || \ - defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) + defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_UART_SINGLE_INSTANCE) size_t base = whal_Stm32wb_Uart_Dev.base; (void)uartDev; #else @@ -161,7 +173,8 @@ whal_Error whal_Stm32wb_Uart_Send(whal_Uart *uartDev, const void *data, size_t d #if defined(WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32H5_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32C0_UART_SINGLE_INSTANCE) || \ - defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) + defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_UART_SINGLE_INSTANCE) const whal_Stm32wb_Uart_Cfg *cfg = (const whal_Stm32wb_Uart_Cfg *)whal_Stm32wb_Uart_Dev.cfg; size_t base = whal_Stm32wb_Uart_Dev.base; @@ -202,7 +215,8 @@ whal_Error whal_Stm32wb_Uart_Recv(whal_Uart *uartDev, void *data, size_t dataSz) #if defined(WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32H5_UART_SINGLE_INSTANCE) || \ defined(WHAL_CFG_STM32C0_UART_SINGLE_INSTANCE) || \ - defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) + defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_UART_SINGLE_INSTANCE) const whal_Stm32wb_Uart_Cfg *cfg = (const whal_Stm32wb_Uart_Cfg *)whal_Stm32wb_Uart_Dev.cfg; size_t base = whal_Stm32wb_Uart_Dev.base; @@ -260,7 +274,8 @@ whal_Error whal_Stm32wb_Uart_RecvAsync(whal_Uart *uartDev, void *data, size_t da !defined(WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING) && \ !defined(WHAL_CFG_STM32H5_UART_DIRECT_API_MAPPING) && \ !defined(WHAL_CFG_STM32C0_UART_DIRECT_API_MAPPING) && \ - !defined(WHAL_CFG_STM32N6_UART_DIRECT_API_MAPPING) + !defined(WHAL_CFG_STM32N6_UART_DIRECT_API_MAPPING) && \ + !defined(WHAL_CFG_STM32WBA_UART_DIRECT_API_MAPPING) const whal_UartDriver whal_Stm32wb_Uart_Driver = { .Init = whal_Stm32wb_Uart_Init, .Deinit = whal_Stm32wb_Uart_Deinit, diff --git a/src/uart/stm32wb_uart_dma.c b/src/uart/stm32wb_uart_dma.c index ddda0f6..0ba77c0 100644 --- a/src/uart/stm32wb_uart_dma.c +++ b/src/uart/stm32wb_uart_dma.c @@ -59,6 +59,10 @@ #define whal_Stm32wb_UartDma_RecvAsync whal_Uart_RecvAsync #endif /* WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING */ +#ifdef WHAL_CFG_STM32WB_UART_DMA_SINGLE_INSTANCE +const whal_Uart whal_Stm32wb_UartDma_Dev = WHAL_CFG_STM32WB_UART_DMA_DEV; +#endif + whal_Error whal_Stm32wb_UartDma_SendAsync(whal_Uart *uartDev, const void *data, size_t dataSz) { diff --git a/src/uart/stm32wba_uart_dma.c b/src/uart/stm32wba_uart_dma.c index b0459c0..4847d39 100644 --- a/src/uart/stm32wba_uart_dma.c +++ b/src/uart/stm32wba_uart_dma.c @@ -48,6 +48,10 @@ #define UART_RDR_REG 0x24 #define UART_TDR_REG 0x28 +#ifdef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE +const whal_Uart whal_Stm32wba_UartDma_Dev = WHAL_CFG_STM32WBA_UART_DMA_DEV; +#endif + whal_Error whal_Stm32wba_UartDma_SendAsync(whal_Uart *uartDev, const void *data, size_t dataSz) { diff --git a/tests/ipc/test_ipc.c b/tests/ipc/test_ipc.c index 532fb52..de72447 100644 --- a/tests/ipc/test_ipc.c +++ b/tests/ipc/test_ipc.c @@ -30,10 +30,6 @@ static void Test_Ipc_InitDeinit(void) WHAL_ASSERT_EQ(whal_Ipc_Init(BOARD_IPC_DEV), WHAL_SUCCESS); } -static void Test_Ipc_InitNull(void) -{ -} - static void Test_Ipc_SendNull(void) { WHAL_ASSERT_EQ(whal_Ipc_Send(BOARD_IPC_DEV, NULL, 0), WHAL_EINVAL); @@ -48,7 +44,6 @@ void whal_Test_Ipc(void) { WHAL_TEST_SUITE_START("ipc"); WHAL_TEST(Test_Ipc_InitDeinit); - WHAL_TEST(Test_Ipc_InitNull); WHAL_TEST(Test_Ipc_SendNull); WHAL_TEST(Test_Ipc_RecvNull); WHAL_TEST_SUITE_END(); diff --git a/tests/main.c b/tests/main.c index 6992756..c64fea8 100644 --- a/tests/main.c +++ b/tests/main.c @@ -166,10 +166,6 @@ void whal_Test_Dma_Platform(void); void whal_Test_Irq_Platform(void); #endif -#ifdef WHAL_TEST_ENABLE_SENSOR -void whal_Test_Sensor(void); -#endif - int g_whalTestPassed; int g_whalTestFailed; int g_whalTestSkipped; @@ -347,10 +343,6 @@ void main(void) whal_Test_Irq_Platform(); #endif -#ifdef WHAL_TEST_ENABLE_SENSOR - whal_Test_Sensor(); -#endif - WHAL_TEST_SUMMARY(); if (g_whalTestFailed == 0) { diff --git a/tests/sensor/test_sensor.c b/tests/sensor/test_sensor.c deleted file mode 100644 index edbce00..0000000 --- a/tests/sensor/test_sensor.c +++ /dev/null @@ -1,37 +0,0 @@ -/* test_sensor.c - * - * Copyright (C) 2026 wolfSSL Inc. - * - * This file is part of wolfHAL. - * - * wolfHAL is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfHAL is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA - */ - -#include -#include "board.h" -#include "test.h" - -static void Test_Sensor_Api(void) -{ - uint8_t data[32]; - -} - -void whal_Test_Sensor(void) -{ - WHAL_TEST_SUITE_START("sensor"); - WHAL_TEST(Test_Sensor_Api); - WHAL_TEST_SUITE_END(); -} diff --git a/wolfHAL/block/sdhc_spi_block.h b/wolfHAL/block/sdhc_spi_block.h index 9db80d4..b5a3cef 100644 --- a/wolfHAL/block/sdhc_spi_block.h +++ b/wolfHAL/block/sdhc_spi_block.h @@ -56,6 +56,14 @@ typedef struct whal_SdhcSpi_Cfg { whal_Timeout *timeout; /* Optional timeout for poll loops */ } whal_SdhcSpi_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_SDHC_SPI_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_SDHC_SPI_SINGLE_INSTANCE +extern const whal_Block whal_SdhcSpi_Dev; +#endif + #ifndef WHAL_CFG_SDHC_SPI_BLOCK_DIRECT_API_MAPPING /* * @brief Driver instance for SDHC/SDXC over SPI. diff --git a/wolfHAL/dma/stm32wb_dma.h b/wolfHAL/dma/stm32wb_dma.h index 5420997..ed77dea 100644 --- a/wolfHAL/dma/stm32wb_dma.h +++ b/wolfHAL/dma/stm32wb_dma.h @@ -97,6 +97,14 @@ typedef struct { uint8_t numChannels; /* Number of channels (7 for DMA1, 5 for DMA2) */ } whal_Stm32wb_Dma_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32WB_DMA_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_STM32WB_DMA_SINGLE_INSTANCE +extern const whal_Dma whal_Stm32wb_Dma_Dev; +#endif + #ifndef WHAL_CFG_STM32WB_DMA_DIRECT_API_MAPPING /* * @brief Driver instance for STM32WB DMA. diff --git a/wolfHAL/dma/stm32wba_gpdma.h b/wolfHAL/dma/stm32wba_gpdma.h index e937d2c..6c8e2bf 100644 --- a/wolfHAL/dma/stm32wba_gpdma.h +++ b/wolfHAL/dma/stm32wba_gpdma.h @@ -94,6 +94,15 @@ typedef struct { whal_Timeout *timeout; /* Timeout for channel reset/suspend polling */ } whal_Stm32wba_Gpdma_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32WBA_GPDMA_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32WBA_GPDMA_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_GPDMA_SINGLE_INSTANCE) +extern const whal_Dma whal_Stm32wba_Gpdma_Dev; +#endif + extern const whal_DmaDriver whal_Stm32wba_Gpdma_Driver; /* diff --git a/wolfHAL/flash/spi_nor_flash.h b/wolfHAL/flash/spi_nor_flash.h index 411d553..7035bc4 100644 --- a/wolfHAL/flash/spi_nor_flash.h +++ b/wolfHAL/flash/spi_nor_flash.h @@ -69,6 +69,14 @@ typedef struct whal_SpiNor_Cfg { size_t capacity; /* Total flash capacity in bytes */ } whal_SpiNor_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_SPI_NOR_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_SPI_NOR_SINGLE_INSTANCE +extern const whal_Flash whal_SpiNor_Dev; +#endif + /* * @brief Default driver vtable using 3-byte addressing with 4 KB erase. */ diff --git a/wolfHAL/i2c/stm32l1_i2c.h b/wolfHAL/i2c/stm32l1_i2c.h index 553d749..68828a7 100644 --- a/wolfHAL/i2c/stm32l1_i2c.h +++ b/wolfHAL/i2c/stm32l1_i2c.h @@ -47,6 +47,14 @@ typedef struct whal_Stm32l1_I2c_Cfg { uint8_t _addrSz; /**< Address size in bits (set by StartCom) */ } whal_Stm32l1_I2c_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32L1_I2C_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_STM32L1_I2C_SINGLE_INSTANCE +extern const whal_I2c whal_Stm32l1_I2c_Dev; +#endif + #ifndef WHAL_CFG_STM32L1_I2C_DIRECT_API_MAPPING /** * @brief Driver instance for STM32L1 I2C peripheral. diff --git a/wolfHAL/i2c/stm32wb_i2c.h b/wolfHAL/i2c/stm32wb_i2c.h index 1dfc7aa..f12f5e3 100644 --- a/wolfHAL/i2c/stm32wb_i2c.h +++ b/wolfHAL/i2c/stm32wb_i2c.h @@ -48,6 +48,17 @@ typedef struct whal_Stm32wb_I2c_Cfg { whal_Timeout *timeout; } whal_Stm32wb_I2c_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32WB_I2C_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32WB_I2C_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F0_I2C_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F3_I2C_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_I2C_SINGLE_INSTANCE) +extern const whal_I2c whal_Stm32wb_I2c_Dev; +#endif + #ifndef WHAL_CFG_STM32WB_I2C_DIRECT_API_MAPPING /* * @brief Driver instance for STM32WB I2C peripheral. diff --git a/wolfHAL/sensor/imu/bmi270_sensor.h b/wolfHAL/sensor/imu/bmi270_sensor.h index 9b6ce96..0bd06ab 100644 --- a/wolfHAL/sensor/imu/bmi270_sensor.h +++ b/wolfHAL/sensor/imu/bmi270_sensor.h @@ -67,6 +67,14 @@ typedef struct { void (*DelayMs)(size_t ms); /* Millisecond delay function */ } whal_Bmi270_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_BMI270_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_BMI270_SINGLE_INSTANCE +extern const whal_Sensor whal_Bmi270_Dev; +#endif + #ifndef WHAL_CFG_BMI270_SENSOR_DIRECT_API_MAPPING /* * @brief Driver instance for the BMI270. diff --git a/wolfHAL/spi/stm32f4_spi.h b/wolfHAL/spi/stm32f4_spi.h index dc229ab..9a43d06 100644 --- a/wolfHAL/spi/stm32f4_spi.h +++ b/wolfHAL/spi/stm32f4_spi.h @@ -52,6 +52,15 @@ typedef struct whal_Stm32f4_Spi_Cfg { whal_Timeout *timeout; } whal_Stm32f4_Spi_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32F4_SPI_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32F4_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32L1_SPI_SINGLE_INSTANCE) +extern const whal_Spi whal_Stm32f4_Spi_Dev; +#endif + #ifndef WHAL_CFG_STM32F4_SPI_DIRECT_API_MAPPING /* * @brief Driver instance for STM32F4 SPI peripheral. diff --git a/wolfHAL/spi/stm32h5_spi.h b/wolfHAL/spi/stm32h5_spi.h index 822acba..d1d4ed2 100644 --- a/wolfHAL/spi/stm32h5_spi.h +++ b/wolfHAL/spi/stm32h5_spi.h @@ -46,6 +46,16 @@ typedef struct whal_Stm32h5_Spi_Cfg { whal_Timeout *timeout; } whal_Stm32h5_Spi_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32H5_SPI_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32H5_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_SPI_SINGLE_INSTANCE) +extern const whal_Spi whal_Stm32h5_Spi_Dev; +#endif + #ifndef WHAL_CFG_STM32H5_SPI_DIRECT_API_MAPPING /* * @brief Driver instance for STM32H5 SPI peripheral. diff --git a/wolfHAL/spi/stm32wb_spi.h b/wolfHAL/spi/stm32wb_spi.h index b06e63f..34d1c9b 100644 --- a/wolfHAL/spi/stm32wb_spi.h +++ b/wolfHAL/spi/stm32wb_spi.h @@ -48,6 +48,17 @@ typedef struct whal_Stm32wb_Spi_Cfg { whal_Timeout *timeout; } whal_Stm32wb_Spi_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32WB_SPI_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32WB_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32C0_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F0_SPI_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F3_SPI_SINGLE_INSTANCE) +extern const whal_Spi whal_Stm32wb_Spi_Dev; +#endif + #if !defined(WHAL_CFG_STM32WB_SPI_DIRECT_API_MAPPING) && \ !defined(WHAL_CFG_STM32C0_SPI_DIRECT_API_MAPPING) /* diff --git a/wolfHAL/uart/pic32cz_uart.h b/wolfHAL/uart/pic32cz_uart.h index 80974e2..4a3d0ed 100644 --- a/wolfHAL/uart/pic32cz_uart.h +++ b/wolfHAL/uart/pic32cz_uart.h @@ -64,6 +64,14 @@ typedef struct whal_Pic32cz_Uart_Cfg { whal_Timeout *timeout; } whal_Pic32cz_Uart_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_PIC32CZ_UART_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_PIC32CZ_UART_SINGLE_INSTANCE +extern const whal_Uart whal_Pic32cz_Uart_Dev; +#endif + #ifndef WHAL_CFG_PIC32CZ_UART_DIRECT_API_MAPPING /* * @brief Driver instance for PIC32CZ UART. diff --git a/wolfHAL/uart/stm32f0_uart.h b/wolfHAL/uart/stm32f0_uart.h index 59c092d..74a4a0e 100644 --- a/wolfHAL/uart/stm32f0_uart.h +++ b/wolfHAL/uart/stm32f0_uart.h @@ -42,6 +42,15 @@ typedef struct whal_Stm32f0_Uart_Cfg { whal_Timeout *timeout; } whal_Stm32f0_Uart_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32F0_UART_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32F0_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32F3_UART_SINGLE_INSTANCE) +extern const whal_Uart whal_Stm32f0_Uart_Dev; +#endif + #ifndef WHAL_CFG_STM32F0_UART_DIRECT_API_MAPPING /* * @brief Driver instance for the STM32F0 polled UART. diff --git a/wolfHAL/uart/stm32f4_uart.h b/wolfHAL/uart/stm32f4_uart.h index d83fdbe..bfe6823 100644 --- a/wolfHAL/uart/stm32f4_uart.h +++ b/wolfHAL/uart/stm32f4_uart.h @@ -63,6 +63,15 @@ typedef struct whal_Stm32f4_Uart_Cfg { whal_Timeout *timeout; } whal_Stm32f4_Uart_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32F4_UART_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32F4_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32L1_UART_SINGLE_INSTANCE) +extern const whal_Uart whal_Stm32f4_Uart_Dev; +#endif + #ifndef WHAL_CFG_STM32F4_UART_DIRECT_API_MAPPING /* * @brief Driver instance for STM32F4 UART peripheral. diff --git a/wolfHAL/uart/stm32wb_uart.h b/wolfHAL/uart/stm32wb_uart.h index 4d3d7b6..5365c53 100644 --- a/wolfHAL/uart/stm32wb_uart.h +++ b/wolfHAL/uart/stm32wb_uart.h @@ -51,10 +51,24 @@ typedef struct whal_Stm32wb_Uart_Cfg { whal_Timeout *timeout; } whal_Stm32wb_Uart_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32WB_UART_DEV initializer in board.h. + */ +#if defined(WHAL_CFG_STM32WB_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32H5_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32C0_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32N6_UART_SINGLE_INSTANCE) || \ + defined(WHAL_CFG_STM32WBA_UART_SINGLE_INSTANCE) +extern const whal_Uart whal_Stm32wb_Uart_Dev; +#endif + #if !defined(WHAL_CFG_STM32WB_UART_DIRECT_API_MAPPING) && \ !defined(WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING) && \ !defined(WHAL_CFG_STM32H5_UART_DIRECT_API_MAPPING) && \ - !defined(WHAL_CFG_STM32C0_UART_DIRECT_API_MAPPING) + !defined(WHAL_CFG_STM32C0_UART_DIRECT_API_MAPPING) && \ + !defined(WHAL_CFG_STM32N6_UART_DIRECT_API_MAPPING) && \ + !defined(WHAL_CFG_STM32WBA_UART_DIRECT_API_MAPPING) /* * @brief Polled UART driver. Implements Init, Deinit, Send, Recv. */ diff --git a/wolfHAL/uart/stm32wb_uart_dma.h b/wolfHAL/uart/stm32wb_uart_dma.h index 6fae48b..7ffa482 100644 --- a/wolfHAL/uart/stm32wb_uart_dma.h +++ b/wolfHAL/uart/stm32wb_uart_dma.h @@ -50,6 +50,14 @@ typedef struct { volatile whal_Error rxResult; } whal_Stm32wb_UartDma_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32WB_UART_DMA_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_STM32WB_UART_DMA_SINGLE_INSTANCE +extern const whal_Uart whal_Stm32wb_UartDma_Dev; +#endif + #ifndef WHAL_CFG_STM32WB_UART_DMA_DIRECT_API_MAPPING /* * @brief DMA-backed UART driver. Implements Init, Deinit, Send, Recv, diff --git a/wolfHAL/uart/stm32wba_uart_dma.h b/wolfHAL/uart/stm32wba_uart_dma.h index 4958983..7e1107e 100644 --- a/wolfHAL/uart/stm32wba_uart_dma.h +++ b/wolfHAL/uart/stm32wba_uart_dma.h @@ -61,6 +61,14 @@ typedef struct { volatile whal_Error rxResult; /* Set by RX completion callback */ } whal_Stm32wba_UartDma_Cfg; +/* + * @brief Single-instance device struct. Defined in the driver TU + * from the WHAL_CFG_STM32WBA_UART_DMA_DEV initializer in board.h. + */ +#ifdef WHAL_CFG_STM32WBA_UART_DMA_SINGLE_INSTANCE +extern const whal_Uart whal_Stm32wba_UartDma_Dev; +#endif + /* * @brief Driver instance for the GPDMA-backed STM32WBA UART. */