Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions boards/peripheral/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ BOARD_SOURCE += $(_PERIPHERAL_DIR)/peripheral.c
ifneq ($(filter sdhc_spi_sdcard32gb,$(PERIPHERALS)),)
CFLAGS += -DPERIPHERAL_SDHC_SPI_SDCARD32GB
BOARD_SOURCE += $(_PERIPHERAL_DIR)/block/sdhc_spi_sdcard32gb.c
BOARD_SOURCE += $(WHAL_DIR)/src/block/sdhc_spi.c
BOARD_SOURCE += $(WHAL_DIR)/src/block/sdhc_spi_block.c
endif

ifneq ($(filter spi_nor_w25q64,$(PERIPHERALS)),)
CFLAGS += -DPERIPHERAL_SPI_NOR_W25Q64
BOARD_SOURCE += $(_PERIPHERAL_DIR)/flash/spi_nor_w25q64.c
BOARD_SOURCE += $(WHAL_DIR)/src/flash/spi_nor.c
BOARD_SOURCE += $(WHAL_DIR)/src/flash/spi_nor_flash.c
endif

ifneq ($(filter bmi270,$(PERIPHERALS)),)
CFLAGS += -DPERIPHERAL_BMI270
BOARD_SOURCE += $(_PERIPHERAL_DIR)/sensor/imu/bmi270.c
BOARD_SOURCE += $(WHAL_DIR)/src/sensor/imu/bmi270.c
BOARD_SOURCE += $(WHAL_DIR)/src/sensor/imu/bmi270_sensor.c
BOARD_SOURCE += $(WHAL_DIR)/src/sensor/imu/bmi270_config_data.c
endif
2 changes: 1 addition & 1 deletion boards/peripheral/block/sdhc_spi_sdcard32gb.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "sdhc_spi_sdcard32gb.h"
#include <wolfHAL/block/sdhc_spi.h>
#include <wolfHAL/block/sdhc_spi_block.h>
#include "board.h"

static whal_Spi_ComCfg g_sdcardComCfg = {
Expand Down
2 changes: 1 addition & 1 deletion boards/peripheral/block/sdhc_spi_sdcard32gb.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <wolfHAL/wolfHAL.h>
#include <wolfHAL/block/block.h>
#include <wolfHAL/block/sdhc_spi.h>
#include <wolfHAL/block/sdhc_spi_block.h>

extern whal_Block g_whalSdhcSpiSdcard32gb;

Expand Down
2 changes: 1 addition & 1 deletion boards/peripheral/flash/spi_nor_w25q64.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "spi_nor_w25q64.h"
#include <wolfHAL/flash/spi_nor.h>
#include <wolfHAL/flash/spi_nor_flash.h>
#include "board.h"

/*
Expand Down
2 changes: 1 addition & 1 deletion boards/peripheral/flash/spi_nor_w25q64.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <wolfHAL/wolfHAL.h>
#include <wolfHAL/flash/flash.h>
#include <wolfHAL/flash/spi_nor.h>
#include <wolfHAL/flash/spi_nor_flash.h>

extern whal_Flash g_whalSpiNorW25q64;

Expand Down
2 changes: 1 addition & 1 deletion boards/peripheral/sensor/imu/bmi270.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include "bmi270.h"
#include <wolfHAL/sensor/imu/bmi270.h>
#include <wolfHAL/sensor/imu/bmi270_sensor.h>
#include <wolfHAL/sensor/imu/bmi270_config_data.h>
#include "board.h"

Expand Down
2 changes: 1 addition & 1 deletion boards/peripheral/sensor/imu/bmi270.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <wolfHAL/wolfHAL.h>
#include <wolfHAL/sensor/sensor.h>
#include <wolfHAL/sensor/imu/bmi270.h>
#include <wolfHAL/sensor/imu/bmi270_sensor.h>

extern whal_Sensor g_whalBmi270;

Expand Down
2 changes: 1 addition & 1 deletion boards/pic32cz_curiosity_ultra/Makefile.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

PLATFORM = pic32cz
TESTS ?= clock gpio flash timer
TESTS ?= clock gpio flash timer supply uart

GCC = $(GCC_PATH)arm-none-eabi-gcc
LD = $(GCC_PATH)arm-none-eabi-ld
Expand Down
2 changes: 1 addition & 1 deletion boards/stm32c031_nucleo/Makefile.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

PLATFORM = stm32c0
TESTS ?= clock gpio timer flash
TESTS ?= clock gpio timer flash uart

GCC = $(GCC_PATH)arm-none-eabi-gcc
LD = $(GCC_PATH)arm-none-eabi-gcc
Expand Down
2 changes: 1 addition & 1 deletion boards/stm32f411_blackpill/Makefile.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

PLATFORM = stm32f4
TESTS ?= clock gpio timer flash
TESTS ?= clock gpio timer flash uart

GCC = $(GCC_PATH)arm-none-eabi-gcc
LD = $(GCC_PATH)arm-none-eabi-ld
Expand Down
2 changes: 1 addition & 1 deletion boards/stm32h563zi_nucleo/Makefile.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

PLATFORM = stm32h5
TESTS ?= clock gpio timer flash rng eth
TESTS ?= clock gpio timer flash rng eth uart

GCC = $(GCC_PATH)arm-none-eabi-gcc
LD = $(GCC_PATH)arm-none-eabi-ld
Expand Down
2 changes: 1 addition & 1 deletion boards/stm32h563zi_nucleo/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <stddef.h>
#include "board.h"
#include <wolfHAL/platform/st/stm32h563xx.h>
#include <wolfHAL/eth_phy/lan8742a.h>
#include <wolfHAL/eth_phy/lan8742a_eth_phy.h>
#include "peripheral.h"

/* SysTick timing */
Expand Down
2 changes: 1 addition & 1 deletion boards/stm32wb55xx_nucleo/Makefile.inc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
_BOARD_DIR := $(patsubst %/,%,$(dir $(lastword $(MAKEFILE_LIST))))

PLATFORM = stm32wb
TESTS ?= clock gpio flash timer rng crypto block
TESTS ?= clock gpio flash timer rng crypto block uart i2c dma irq

GCC = $(GCC_PATH)arm-none-eabi-gcc
LD = $(GCC_PATH)arm-none-eabi-ld
Expand Down
20 changes: 14 additions & 6 deletions docs/adding_a_peripheral.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ Declare the global device instance:

#include <wolfHAL/wolfHAL.h>
#include <wolfHAL/flash/flash.h>
#include <wolfHAL/flash/spi_nor.h>
#include <wolfHAL/flash/spi_nor_flash.h>

extern whal_Flash g_whalSpiNorW25q64;

Expand All @@ -65,7 +65,7 @@ globals (`g_whalSpi`, `g_whalGpio`, `SPI_CS_PIN`, `g_whalTimeout`) from

```c
#include "spi_nor_w25q64.h"
#include <wolfHAL/flash/spi_nor.h>
#include <wolfHAL/flash/spi_nor_flash.h>
#include "board.h"

#define W25Q64_PAGE_SZ 256
Expand Down Expand Up @@ -168,8 +168,16 @@ framework.

## Naming Convention

- Flag: `PERIPHERAL_<NAME>` (e.g., `PERIPHERAL_BMI270`)
- PERIPHERALS variable: lowercase name (e.g., `bmi270`, `spi_nor_w25q64`)
Instance files are named `<driver>_<instance>`:

- `sdhc_spi_sdcard32gb` — sdhc_spi driver, 32GB SD card
- `spi_nor_w25q64` — spi_nor driver, W25Q64 chip
- `bmi270` — bmi270 driver (single instance, no qualifier needed)

Summary:

- Directory: `boards/peripheral/<type>/` (e.g., `flash/`, `block/`, `sensor/imu/`)
- Files: `<name>.h` and `<name>.c`
- Global instance: `g_whal<Name>` (e.g., `g_whalBmi270`, `g_whalSpiNorW25q64`)
- Files: `<driver>.h` and `<driver>.c` for single-instance peripherals; otherwise `<driver>_<instance>.h` and `<driver>_<instance>.c`
- Flag: `PERIPHERAL_<NAME>` (e.g., `PERIPHERAL_SPI_NOR_W25Q64`)
- PERIPHERALS variable: lowercase name (e.g., `spi_nor_w25q64`, `bmi270`)
- Global instance: `g_whal<Name>` (e.g., `g_whalSpiNorW25q64`, `g_whalBmi270`)
2 changes: 1 addition & 1 deletion docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ This eliminates the vtable indirection and lets the compiler inline or optimize
the calls more aggressively.

Register-level drivers do not call other drivers internally, so this works
without any caveats. Bus-device drivers (e.g., SPI flash) still call their
without any caveats. Peripheral drivers (e.g., SPI flash) still call their
bus driver through the vtable.

## Next Steps
Expand Down
67 changes: 42 additions & 25 deletions docs/writing_a_driver.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,52 @@
# Writing a Driver

This guide covers how to implement a wolfHAL driver for a specific platform.
This guide covers how to implement wolfHAL drivers.

## Driver Categories

wolfHAL has two categories of drivers:

**Platform drivers** operate directly on SoC hardware registers at fixed memory
addresses. They are tied to a specific microcontroller family and use the
`whal_Reg_*` helpers to read and write peripheral registers. Examples:
`stm32wb_uart`, `stm32wb_gpio`, `stm32wb_dma`, `pic32cz_clock`.

**Peripheral drivers** communicate with external chips over a bus (SPI, I2C,
MDIO). They call platform drivers (e.g., `whal_Spi_SendRecv`) to reach the
hardware and are portable across any SoC that provides the required bus.
Examples: `spi_nor_flash` (SPI flash), `sdhc_spi_block` (SD card over SPI),
`bmi270_sensor` (IMU over I2C), `lan8742a_eth_phy` (Ethernet PHY over MDIO).

Both categories implement the same vtable interface — the application calls
`whal_Flash_Read()` whether the flash is on-chip (platform driver) or
external SPI NOR (peripheral driver). The distinction matters for driver
authors, not for application code.

## Common Pattern

Every device type in wolfHAL follows the same structure:

1. A **driver vtable** — a struct of function pointers that the platform driver
must populate.
1. A **driver vtable** — a struct of function pointers that the driver must
populate.
2. A **device struct** — contains a register map, a pointer to the driver
vtable, and a pointer to platform-specific configuration.
vtable, and a pointer to driver-specific configuration.
3. A **generic dispatch layer** — validates inputs and calls through the vtable.

To write a driver for a device type, you implement the functions defined in that
type's vtable and expose them as a const driver instance.

### File Layout

For a device type `foo` on platform `myplatform`:
For a platform driver implementing device type `foo` on platform `myplatform`:

- `wolfHAL/foo/myplatform_foo.h` — configuration types and driver extern
- `src/foo/myplatform_foo.c` — driver implementation and vtable definition

For a peripheral driver implementing device type `foo` for chip `mychip`:

- `wolfHAL/foo/mychip_foo.h` — configuration types and driver extern
- `src/foo/mychip_foo.c` — driver implementation and vtable definition

### Driver Vtable

Every vtable includes `Init` and `Deinit`. The remaining functions are specific
Expand Down Expand Up @@ -51,18 +76,17 @@ static whal_Error whal_MyplatformFoo_Init(whal_Foo *fooDev)

### No Cross-Driver Calls

Register-level drivers must not call other wolfHAL drivers. A UART driver
must not call the clock driver to enable its own clock, and a clock driver
must not call the flash driver to set wait states. The board is responsible
for all cross-peripheral dependencies — enabling clocks, configuring power
supplies, and setting flash latency — before calling a driver's Init.
Platform drivers should only touch their own registers. The board handles all
cross-peripheral setup — clock enables, power supply sequencing, flash wait
states — before calling Init.

This ensures drivers are pure register-level abstractions with no hidden
dependencies, making them usable with or without the vtable dispatch layer.
There are two exceptions:

Bus-device drivers (e.g., SPI flash) are the exception — they inherently
need to call their underlying bus driver (SPI, I2C) to communicate with the
device.
- **Peripheral drivers** call their underlying bus driver (SPI, I2C, MDIO) to
communicate with the external chip.
- **DMA-backed platform drivers** (e.g., `stm32wb_uart_dma`) call the DMA
driver to set up and start transfers. The DMA device is passed through the
driver's configuration struct.

### Register Access

Expand Down Expand Up @@ -332,12 +356,6 @@ driver should handle all of these.
Disable a peripheral clock gate. The inverse of Enable — clear the enable bit(s)
for the given clock descriptor.

### GetRate

Report the current system clock frequency in Hz. The driver should compute this
from the configured source, PLL coefficients, and divider settings. Store the
result in the output pointer.

---

## GPIO
Expand Down Expand Up @@ -707,7 +725,7 @@ Erase a flash region. Flash erase operates at sector/page granularity
- Validate that the region is unlocked before erasing

The `addr` does not need to be page-aligned — the driver should erase all pages
that overlap with the requested range. Bus-device flash drivers (e.g., SPI-NOR)
that overlap with the requested range. Peripheral flash drivers (e.g., SPI-NOR)
may enforce stricter alignment requirements where the underlying hardware
requires aligned erase addresses.

Expand All @@ -722,9 +740,8 @@ SD cards and eMMC. Unlike flash, block devices are addressed by block number
rather than byte address, and all operations work in units of fixed-size blocks
(e.g. 512 bytes).

Block drivers are bus-device drivers — they call their underlying bus driver
(SPI, SDIO) to communicate with the storage device. This is the expected
exception to the no-cross-driver-calls rule.
Block drivers are peripheral drivers — they call their underlying bus driver
(SPI, SDIO) to communicate with the storage device.

### Init

Expand Down
2 changes: 1 addition & 1 deletion src/block/sdhc_spi.c → src/block/sdhc_spi_block.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <stdint.h>
#include <wolfHAL/block/sdhc_spi.h>
#include <wolfHAL/block/sdhc_spi_block.h>
#include <wolfHAL/block/block.h>
#include <wolfHAL/spi/spi.h>
#include <wolfHAL/gpio/gpio.h>
Expand Down
11 changes: 0 additions & 11 deletions src/clock/clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,3 @@ inline whal_Error whal_Clock_Disable(whal_Clock *clkDev, const void *clk)
return clkDev->driver->Disable(clkDev, clk);
}

inline whal_Error whal_Clock_GetRate(whal_Clock *clkDev, size_t *rateOut)
{
if (!clkDev || !clkDev->driver || !clkDev->driver->GetRate ||
!rateOut)
{
return WHAL_EINVAL;
}

return clkDev->driver->GetRate(clkDev, rateOut);
}

12 changes: 0 additions & 12 deletions src/clock/pic32cz_clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,21 +238,9 @@ whal_Error whal_Pic32czClock_Disable(whal_Clock *clkDev, const void *clk)
return WHAL_SUCCESS;
}

whal_Error whal_Pic32czClock_GetRate(whal_Clock *clkDev, size_t *rateOut)
{
if (!clkDev || !rateOut) {
return WHAL_EINVAL;
}

/* TODO: Calculate actual clock rate from PLL and divider settings */
*rateOut = 0;
return WHAL_SUCCESS;
}

const whal_ClockDriver whal_Pic32czClockPll_Driver = {
.Init = whal_Pic32czClockPll_Init,
.Deinit = whal_Pic32czClockPll_Deinit,
.Enable = whal_Pic32czClock_Enable,
.Disable = whal_Pic32czClock_Disable,
.GetRate = whal_Pic32czClock_GetRate,
};
17 changes: 0 additions & 17 deletions src/clock/stm32c0_rcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,26 +114,9 @@ whal_Error whal_Stm32c0Rcc_Disable(whal_Clock *clkDev, const void *clk)
return WHAL_SUCCESS;
}

whal_Error whal_Stm32c0Rcc_GetRate(whal_Clock *clkDev, size_t *rateOut)
{
whal_Stm32c0Rcc_Cfg *cfg;

if (!clkDev || !clkDev->cfg || !rateOut) {
return WHAL_EINVAL;
}

cfg = (whal_Stm32c0Rcc_Cfg *)clkDev->cfg;

/* HSI48 base frequency divided by HSIDIV (1 << hsidiv) */
*rateOut = 48000000 / (1 << cfg->hsidiv);

return WHAL_SUCCESS;
}

const whal_ClockDriver whal_Stm32c0Rcc_Driver = {
.Init = whal_Stm32c0Rcc_Init,
.Deinit = whal_Stm32c0Rcc_Deinit,
.Enable = whal_Stm32c0Rcc_Enable,
.Disable = whal_Stm32c0Rcc_Disable,
.GetRate = whal_Stm32c0Rcc_GetRate,
};
Loading
Loading