|
| 1 | +# wolfHAL Integration |
| 2 | + |
| 3 | +wolfBoot supports [wolfHAL](https://github.com/wolfSSL/wolfHAL) as an alternative hardware abstraction layer backend. wolfHAL provides portable, vtable-dispatched drivers for common MCU peripherals (clock, flash, GPIO, UART, SPI, etc.) with a consistent API across platforms. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The wolfHAL integration consists of three parts: |
| 8 | + |
| 9 | +1. **HAL implementation** (`hal/wolfhal_<family>.c`) — implements the wolfBoot HAL API (`hal_init`, `hal_flash_write`, etc.) by calling wolfHAL driver functions. One file per MCU family (e.g. STM32WB). |
| 10 | + |
| 11 | +2. **Board configuration** (`hal/boards/<board>.c`) — defines the wolfHAL device instances (flash, clock, and optionally GPIO/UART for `DEBUG_UART`) with board-specific register addresses, clock parameters, and flash geometry. One file per board. |
| 12 | + |
| 13 | +3. **wolfHAL library** (`lib/wolfHAL/`) — the wolfHAL submodule containing the platform drivers. |
| 14 | + |
| 15 | +## Configuration |
| 16 | + |
| 17 | +A wolfHAL-based config requires two variables beyond the standard wolfBoot settings: |
| 18 | + |
| 19 | +``` |
| 20 | +TARGET=wolfhal_stm32wb |
| 21 | +BOARD=stm32wb_nucleo |
| 22 | +``` |
| 23 | + |
| 24 | +- `TARGET` selects the MCU family HAL implementation (`hal/wolfhal_stm32wb.c`) |
| 25 | +- `BOARD` selects the board configuration file (`hal/boards/stm32wb_nucleo.c`) |
| 26 | + |
| 27 | +## Adding a New Board |
| 28 | + |
| 29 | +To add a new board for an existing MCU family (e.g. a custom STM32WB board): |
| 30 | + |
| 31 | +1. Create `hal/boards/<board_name>.c` with the wolfHAL device configuration: |
| 32 | + |
| 33 | +```c |
| 34 | +#include <wolfHAL/clock/stm32wb_rcc.h> |
| 35 | +#include <wolfHAL/flash/stm32wb_flash.h> |
| 36 | +#ifdef DEBUG_UART |
| 37 | +#include <wolfHAL/gpio/stm32wb_gpio.h> |
| 38 | +#include <wolfHAL/uart/stm32wb_uart.h> |
| 39 | +#endif |
| 40 | +#include <wolfHAL/platform/st/stm32wb55xx.h> |
| 41 | + |
| 42 | +/* Forward declarations for circular references */ |
| 43 | +whal_Flash g_wbFlash; |
| 44 | +whal_Clock g_wbClock; |
| 45 | + |
| 46 | +/* PLL, clock, and flash configuration for your board */ |
| 47 | +static whal_Stm32wbRcc_PllClkCfg pllCfg = { ... }; |
| 48 | +static whal_Stm32wbRcc_Cfg rccCfg = { .flash = &g_wbFlash, ... }; |
| 49 | +static whal_Stm32wbFlash_Cfg flashCfg = { .clkCtrl = &g_wbClock, ... }; |
| 50 | + |
| 51 | +/* Minimal clock driver vtable: Enable/Disable are used by the flash, GPIO, and |
| 52 | + * UART drivers for peripheral clock gating. GetRate is only needed by the UART |
| 53 | + * driver for baud rate calculation. */ |
| 54 | +static const whal_ClockDriver clockDriver = { |
| 55 | + .Enable = whal_Stm32wbRcc_Enable, |
| 56 | + .Disable = whal_Stm32wbRcc_Disable, |
| 57 | +#ifdef DEBUG_UART |
| 58 | + .GetRate = whal_Stm32wbRccPll_GetRate, |
| 59 | +#endif |
| 60 | +}; |
| 61 | + |
| 62 | +/* Device definitions */ |
| 63 | +whal_Clock g_wbClock = { |
| 64 | + .regmap = { .base = 0x58000000, .size = 0x400 }, |
| 65 | + .driver = &clockDriver, |
| 66 | + .cfg = &rccCfg, |
| 67 | +}; |
| 68 | + |
| 69 | +whal_Flash g_wbFlash = { |
| 70 | + .regmap = { .base = 0x58004000, .size = 0x400 }, |
| 71 | + .cfg = &flashCfg, |
| 72 | +}; |
| 73 | + |
| 74 | +#ifdef DEBUG_UART |
| 75 | +/* GPIO — UART1 TX/RX pins */ |
| 76 | +static whal_Stm32wbGpio_PinCfg gpioPins[] = { ... }; |
| 77 | +static whal_Stm32wbGpio_Cfg gpioCfg = { .clkCtrl = &g_wbClock, ... }; |
| 78 | + |
| 79 | +whal_Gpio g_wbGpio = { |
| 80 | + .regmap = { .base = 0x48000000, .size = 0x400 }, |
| 81 | + .cfg = &gpioCfg, |
| 82 | +}; |
| 83 | + |
| 84 | +/* UART1 at 115200 baud */ |
| 85 | +static whal_Stm32wbUart_Cfg uartCfg = { .clkCtrl = &g_wbClock, .baud = 115200 }; |
| 86 | + |
| 87 | +whal_Uart g_wbUart = { |
| 88 | + .regmap = { .base = 0x40013800, .size = 0x400 }, |
| 89 | + .cfg = &uartCfg, |
| 90 | +}; |
| 91 | +#endif /* DEBUG_UART */ |
| 92 | +``` |
| 93 | + |
| 94 | +The board file exports `g_wbFlash` and `g_wbClock` as non-static globals (and `g_wbGpio`/`g_wbUart` when `DEBUG_UART` is enabled). The HAL implementation references these via `extern`. |
| 95 | + |
| 96 | +2. Create `config/examples/wolfhal_<target>_<board>.config`: |
| 97 | + |
| 98 | +``` |
| 99 | +TARGET=wolfhal_stm32wb |
| 100 | +BOARD=<board_name> |
| 101 | +SIGN=ECC256 |
| 102 | +HASH=SHA256 |
| 103 | +WOLFBOOT_SECTOR_SIZE=0x1000 |
| 104 | +WOLFBOOT_PARTITION_SIZE=0x20000 |
| 105 | +WOLFBOOT_PARTITION_BOOT_ADDRESS=0x08008000 |
| 106 | +WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x08028000 |
| 107 | +WOLFBOOT_PARTITION_SWAP_ADDRESS=0x08048000 |
| 108 | +NVM_FLASH_WRITEONCE=1 |
| 109 | +``` |
| 110 | + |
| 111 | +Adjust partition addresses and sizes for your board's flash layout. |
| 112 | + |
| 113 | +Optionally add `DEBUG_UART=1` to enable UART debug output via wolfHAL. |
| 114 | + |
| 115 | +### RAM_CODE |
| 116 | + |
| 117 | +When `RAM_CODE=1` is set, wolfBoot's core flash update functions are placed in RAM |
| 118 | +via the `RAMFUNCTION` attribute. For wolfHAL targets, the wolfHAL flash driver |
| 119 | +(`stm32wb_flash.o`) is also placed in RAM using `EXCLUDE_FILE` directives in the |
| 120 | +linker script. This ensures all flash operations execute from RAM, which is required |
| 121 | +on some MCUs that stall or fault when code executes from the same flash bank being |
| 122 | +programmed. |
| 123 | + |
| 124 | +``` |
| 125 | +RAM_CODE=1 |
| 126 | +``` |
| 127 | + |
| 128 | +The linker script (`hal/stm32wb.ld`) uses `@WOLFHAL_FLASH_EXCLUDE_TEXT@`, |
| 129 | +`@WOLFHAL_FLASH_EXCLUDE_RODATA@`, and `@WOLFHAL_FLASH_RAM_SECTIONS@` placeholders |
| 130 | +that are substituted at build time. When `RAM_CODE=1`, these expand to |
| 131 | +`EXCLUDE_FILE(*stm32wb_flash.o)` rules that move the flash driver's `.text` and |
| 132 | +`.rodata` sections from flash into the `.data` section (loaded to RAM at startup). |
| 133 | +When `RAM_CODE` is not set, all code remains in flash as normal. |
| 134 | + |
| 135 | +## Adding a New MCU Family |
| 136 | + |
| 137 | +To add support for a new MCU family (e.g. STM32H7): |
| 138 | + |
| 139 | +1. Create `hal/wolfhal_<family>.c` implementing the wolfBoot HAL functions. Use the appropriate wolfHAL driver headers and call driver functions directly for minimal overhead: |
| 140 | + |
| 141 | +```c |
| 142 | +#include <stdint.h> |
| 143 | +#include "hal.h" |
| 144 | +#include <wolfHAL/clock/<family>_rcc.h> |
| 145 | +#include <wolfHAL/flash/<family>_flash.h> |
| 146 | +#ifdef DEBUG_UART |
| 147 | +#include <wolfHAL/gpio/<family>_gpio.h> |
| 148 | +#include <wolfHAL/uart/<family>_uart.h> |
| 149 | +#endif |
| 150 | + |
| 151 | +extern whal_Flash g_wbFlash; |
| 152 | +extern whal_Clock g_wbClock; |
| 153 | +#ifdef DEBUG_UART |
| 154 | +extern whal_Gpio g_wbGpio; |
| 155 | +extern whal_Uart g_wbUart; |
| 156 | +#endif |
| 157 | + |
| 158 | +void hal_init(void) |
| 159 | +{ |
| 160 | + /* Family-specific clock and flash initialization */ |
| 161 | +#ifdef DEBUG_UART |
| 162 | + /* GPIO and UART initialization */ |
| 163 | +#endif |
| 164 | +} |
| 165 | + |
| 166 | +void hal_prepare_boot(void) |
| 167 | +{ |
| 168 | +#ifdef DEBUG_UART |
| 169 | + /* UART and GPIO deinitialization */ |
| 170 | +#endif |
| 171 | + /* Family-specific flash and clock deinitialization */ |
| 172 | +} |
| 173 | + |
| 174 | +/* hal_flash_unlock, hal_flash_lock, hal_flash_write, hal_flash_erase */ |
| 175 | + |
| 176 | +#ifdef DEBUG_UART |
| 177 | +void uart_write(const char *buf, unsigned int len) |
| 178 | +{ |
| 179 | + /* Send via wolfHAL UART driver */ |
| 180 | +} |
| 181 | +#endif |
| 182 | +``` |
| 183 | +
|
| 184 | +2. Add the target block in `arch.mk`: |
| 185 | +
|
| 186 | +```makefile |
| 187 | +ifeq ($(TARGET),wolfhal_<family>) |
| 188 | + ARCH_FLASH_OFFSET=0x08000000 |
| 189 | + LSCRIPT_IN=hal/<family>.ld |
| 190 | + WOLFHAL_ROOT?=$(WOLFBOOT_ROOT)/lib/wolfHAL |
| 191 | + CFLAGS+=-I$(WOLFHAL_ROOT) -DWHAL_CFG_DIRECT_CALLBACKS |
| 192 | + OBJS+=./hal/boards/$(BOARD).o |
| 193 | + OBJS+=$(WOLFHAL_ROOT)/src/<device>/<driver>.o |
| 194 | +endif |
| 195 | +``` |
| 196 | + |
| 197 | +3. Create at least one board configuration file in `hal/boards/`. |
| 198 | + |
| 199 | +## Test Application |
| 200 | + |
| 201 | +The test application (`test-app/app_wolfhal_stm32wb.c`) demonstrates using wolfHAL peripherals beyond what the bootloader needs. It initializes GPIO (LED on PB5) and UART (UART1 at 115200 baud) via wolfHAL, then exercises the wolfBoot update mechanism. |
| 202 | + |
| 203 | +The test app accesses the board's clock instance via `extern whal_Clock g_wbClock` for peripheral clock gating. |
| 204 | + |
| 205 | +The test-app compiles its own copy of the board file (`board_<board>.o`) with |
| 206 | +`-DDEBUG_UART` always defined, since the app needs `GetRate` in the clock vtable |
| 207 | +for UART baud rate calculation. This is independent of the bootloader's |
| 208 | +`DEBUG_UART` setting — the bootloader's board object only includes `GetRate` when |
| 209 | +`DEBUG_UART=1` is in the config. |
0 commit comments