Skip to content
Open
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
12 changes: 6 additions & 6 deletions .claude/skills/generate-driver-template/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ constness to the generic struct's `cfg` field.
```c
whal_Error whal_<Plat>_<Type>_<Member>(<params>)
{
size_t base = whal_<Plat>_<Type>_Dev.base;
uintptr_t base = whal_<Plat>_<Type>_Dev.base;
whal_<Plat>_<Type>_Cfg *cfg =
(whal_<Plat>_<Type>_Cfg *)whal_<Plat>_<Type>_Dev.cfg;
(void)<dev>;
Expand All @@ -267,12 +267,12 @@ the pointer, the default branch validates the pointer and reads base/cfg from it
whal_Error whal_<Plat>_<Type>_<Member>(<params>)
{
#ifdef WHAL_CFG_<PLAT>_<TYPE>_SINGLE_INSTANCE
size_t base = whal_<Plat>_<Type>_Dev.base;
uintptr_t base = whal_<Plat>_<Type>_Dev.base;
whal_<Plat>_<Type>_Cfg *cfg =
(whal_<Plat>_<Type>_Cfg *)whal_<Plat>_<Type>_Dev.cfg;
(void)<dev>;
#else
size_t base;
uintptr_t base;
whal_<Plat>_<Type>_Cfg *cfg;

if (!<dev> || !<dev>->cfg)
Expand All @@ -296,7 +296,7 @@ Notes for the bodies:
trailing `/* validate the remaining args */` line — there is nothing else to check.
- Keep `(void)base;` / `(void)cfg;` so the stub compiles with `-Werror` before the bodies are
filled in. Remove them as soon as `base`/`cfg` get used.
- Add a `whal_Timeout`-based wait (`WHAL_TIMEOUT_*` or `whal_Reg_ReadPoll`) wherever the real
- Add a `whal_Timeout`-based wait (`WHAL_TIMEOUT_*` or `whal_Reg32_ReadPoll`) wherever the real
implementation will poll hardware — never a bare `while`. Leave a TODO noting it.

---
Expand Down Expand Up @@ -379,9 +379,9 @@ takes **`void`** (so the header compiles before any structs/enums are defined),
static inline whal_Error whal_<Plat>_<Type>_Enable(void)
{
/* TODO: implement — write WHAL_<PLAT>_<TYPE>_BASE registers via
* whal_Reg_Update / whal_Reg_Get. Poll any ready bit before returning.
* whal_Reg32_Update / whal_Reg32_Get. Poll any ready bit before returning.
* Clock bring-up runs before the system timer, so a bare do/while on the
* ready bit is acceptable there; elsewhere prefer whal_Reg_ReadPoll with a
* ready bit is acceptable there; elsewhere prefer whal_Reg32_ReadPoll with a
* whal_Timeout. */
return WHAL_SUCCESS;
}
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/port-stm32-platform/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ Add the new board to `.github/workflows/boards.yml` by appending it to the `boar
- Missing symbol for an aliased driver → the alias header is missing a `#define` for that function/type, or the stub `.c` isn't present.
- `'whal_Stm32<orig>_<Type>_Dev' undeclared` in a single-instance leaf driver → the alias header for the new platform is missing the `#define whal_Stm32<new>_<Type>_Dev whal_Stm32<orig>_<Type>_Dev` line, OR the wolfHAL_board.h didn't provide `WHAL_CFG_STM32<ORIG>_<TYPE>_DEV` (the leaf `.c` defines the singleton from that name).
- Duplicate symbol → the Makefile is picking up both `<newplatform>_*.c` and the original `<origplatform>_*.c`; restrict the wildcard to the new prefix only.
- Implicit declaration warnings for `whal_Reg_*` / `whal_SetBits` in a stub include → you probably wrote `#include <wolfHAL/...>` with angle brackets in the stub instead of `#include "<origplatform>_<type>.c"` with quotes. The stub must use quoted include so the preprocessor finds the sibling `.c` in the same directory.
- Implicit declaration warnings for `whal_Reg32_*` / `whal_SetBits` in a stub include → you probably wrote `#include <wolfHAL/...>` with angle brackets in the stub instead of `#include "<origplatform>_<type>.c"` with quotes. The stub must use quoted include so the preprocessor finds the sibling `.c` in the same directory.
2. Flash the binary (user runs this) and run the test suite. Each suite prints `PASS`, `FAIL`, or `SKIP`.
3. If UART output is garbled or missing bytes and the chip uses DMA, enable `CR1.FIFOEN` in the UART init before chasing further — DMA→USART without FIFO has caused byte drops on WBA.

Expand Down
4 changes: 2 additions & 2 deletions boards/stm32wba55cg_nucleo/wolfHAL_board.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,10 @@ void Board_WaitMs(size_t ms)
static whal_Error Board_SetVosRange1(void)
{
/* Set VOS to Range 1 */
whal_Reg_Update(PWR_BASE, PWR_VOSR_REG, PWR_VOSR_VOS_Msk, PWR_VOSR_VOS_Msk);
whal_Reg32_Update(PWR_BASE, PWR_VOSR_REG, PWR_VOSR_VOS_Msk, PWR_VOSR_VOS_Msk);

/* Wait for VOSRDY */
while (!(whal_Reg_Read(PWR_BASE, PWR_VOSR_REG) & PWR_VOSR_VOSRDY_Msk))
while (!(whal_Reg32_Read(PWR_BASE, PWR_VOSR_REG) & PWR_VOSR_VOSRDY_Msk))
;

return WHAL_SUCCESS;
Expand Down
6 changes: 3 additions & 3 deletions docs/adding_a_test.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ name). Individual test functions are static and named `Test_<Device>_<Name>`.

Platform-specific tests verify that the driver correctly manipulates hardware
registers. They include platform-specific headers and read registers directly
using `whal_Reg_Get()` to confirm that Init configured the right fields, that
using `whal_Reg32_Get()` to confirm that Init configured the right fields, that
Set wrote to the correct output register, etc.

These tests are automatically detected and compiled when building for the
Expand All @@ -80,12 +80,12 @@ Create `tests/<device>/test_<platform>_<device>.c`:

static void Test_Foo_SomeRegister(void)
{
size_t val = 0;
uint32_t val = 0;
/* Read the register block base from the platform's singleton (extern-declared
* in the driver header; defined in the driver .c from the WHAL_CFG_<PLAT>_<X>_DEV
* initializer in wolfHAL_board.h). For vtable-dispatched drivers, use
* BOARD_FOO_DEV->base instead. */
whal_Reg_Get(whal_<Platform>_Foo_Dev.base, REG_OFFSET, MASK, POS, &val);
whal_Reg32_Get(whal_<Platform>_Foo_Dev.base, REG_OFFSET, MASK, POS, &val);
WHAL_ASSERT_EQ(val, EXPECTED);
}

Expand Down
6 changes: 3 additions & 3 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Most device types share the same three fields in their struct
- `.cfg` — driver-specific configuration settings (pins, baud rate, etc.).
```c
struct whal_Uart {
const size_t base; /* register block address */
const uintptr_t base; /* register block address */
const whal_UartDriver *driver; /* driver vtable */
void *cfg; /* driver-specific config */
};
Expand Down Expand Up @@ -95,7 +95,7 @@ from the device handle the caller passes in:
```c
whal_Error whal_Stm32wb_Uart_Send(whal_Uart *dev, ...)
{
size_t base = dev->base;
uintptr_t base = dev->base;
whal_Stm32wb_Uart_Cfg *cfg = (whal_Stm32wb_Uart_Cfg *)dev->cfg;
/* ... */
}
Expand All @@ -114,7 +114,7 @@ const whal_Rng whal_Stm32wb_Rng_Dev = WHAL_CFG_STM32WB_RNG_DEV;

whal_Error whal_Stm32wb_Rng_Generate(whal_Rng *dev, ...)
{
size_t base = whal_Stm32wb_Rng_Dev.base;
uintptr_t base = whal_Stm32wb_Rng_Dev.base;
(void)dev;
/* ... */
}
Expand Down
69 changes: 44 additions & 25 deletions docs/writing_a_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ wolfHAL has three 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:
`whal_Reg32_*` / `whal_Reg64_*` helpers to read and write peripheral
registers. Examples:
`stm32wb_uart`, `stm32wb_gpio`, `stm32wb_dma`.

**Peripheral drivers** communicate with external chips over a bus (SPI, I2C,
Expand Down Expand Up @@ -155,7 +156,7 @@ whal_Error whal_Myplatform_Uart_Init(whal_Uart *uartDev)
{
const whal_Myplatform_Uart_Cfg *cfg =
(const whal_Myplatform_Uart_Cfg *)whal_Myplatform_Uart_Dev.cfg;
size_t base = whal_Myplatform_Uart_Dev.base;
uintptr_t base = whal_Myplatform_Uart_Dev.base;
(void)uartDev;
/* ... */
}
Expand All @@ -176,7 +177,7 @@ whal_Error whal_Myplatform_Uart_Init(whal_Uart *uartDev)
{
const whal_Myplatform_Uart_Cfg *cfg =
(const whal_Myplatform_Uart_Cfg *)uartDev->cfg;
size_t base = uartDev->base;
uintptr_t base = uartDev->base;
/* ... */
}
```
Expand All @@ -203,7 +204,7 @@ const whal_Uart whal_Myplatform_Uart_Dev = WHAL_CFG_MYPLATFORM_UART_DEV;
whal_Error whal_Myplatform_Uart_Init(whal_Uart *uartDev)
{
const whal_Myplatform_Uart_Cfg *cfg;
size_t base;
uintptr_t base;
#ifdef WHAL_CFG_MYPLATFORM_UART_SINGLE_INSTANCE
cfg = (const whal_Myplatform_Uart_Cfg *)whal_Myplatform_Uart_Dev.cfg;
base = whal_Myplatform_Uart_Dev.base;
Expand Down Expand Up @@ -232,17 +233,34 @@ There are two exceptions:

### Register Access

wolfHAL provides register access helpers in `wolfHAL/reg.h`:
wolfHAL provides register access helpers in `wolfHAL/reg.h`. Pick the set
that matches the register's width in the reference manual:

- `whal_Reg_Write()` — write a full register value
- `whal_Reg_Read()` — read a full register value
- `whal_Reg_Update()` — read-modify-write a specific field within a register
- `whal_Reg_Get()` — read and extract a masked field from a register
- `whal_Reg32_*` — 32-bit registers, `uint32_t` values. Always available.
- `whal_Reg64_*` — 64-bit registers, `uint64_t` values. Only where a 64-bit
access is a single access (`WHAL_HAVE_REG64`, set when `uintptr_t` is
wider than 32 bits).

Each set has:

- `Write()` — write a full register value
- `Read()` — read a full register value
- `Update()` — read-modify-write a specific field within a register
- `Get()` — read a masked field from a register, shifted down to bit 0
- `ReadPoll()` — poll a register until a field matches (see below)

Use `Write` and `Read` for whole-register access. Use `Update` and `Get` when
you need to modify or read individual fields within a register without
disturbing other bits.

```c
whal_Reg32_Update(base, UART_CR_REG, UART_CR_EN_Msk, UART_CR_EN_Msk);
whal_Reg32_Get(base, UART_FR_REG, UART_FR_CNT_Msk, UART_FR_CNT_Pos,
&rxCount);
```

The base is a `uintptr_t` and the offset a `uint32_t`.

### Timeouts

Most drivers poll hardware status registers in busy-wait loops (e.g., waiting
Expand Down Expand Up @@ -270,28 +288,29 @@ do not need to know the tick rate.
The tick fields are 32-bit by default; define `WHAL_CFG_64BIT_TICK` to widen
them to 64-bit (see "64-bit Ticks" below).

#### whal_Reg_ReadPoll
#### whal_Reg32_ReadPoll

For the common case of polling a register bit, use `whal_Reg_ReadPoll` from
`wolfHAL/reg.h`:
For the common case of polling a register bit, use `whal_Reg32_ReadPoll`
(or `whal_Reg64_ReadPoll`) from `wolfHAL/reg.h`:

```c
whal_Error whal_Reg_ReadPoll(size_t base, size_t offset,
size_t mask, size_t value,
whal_Timeout *timeout);
whal_Error whal_Reg32_ReadPoll(uintptr_t base, uint32_t offset,
uint32_t mask, uint32_t value,
whal_Timeout *timeout);
```

This polls until `(reg & mask) == value` or the timeout expires. Pass the mask
as the value to wait for bits to be set, or `0` to wait for bits to be clear:
as the value to wait for bits to be set, or `0` to wait for bits to be clear.
A value with bits outside the mask never matches:

```c
/* Wait for TXE flag to be set */
err = whal_Reg_ReadPoll(base, SPI_SR_REG, SPI_SR_TXE_Msk,
SPI_SR_TXE_Msk, cfg->timeout);
err = whal_Reg32_ReadPoll(base, SPI_SR_REG, SPI_SR_TXE_Msk,
SPI_SR_TXE_Msk, cfg->timeout);

/* Wait for BSY flag to be clear */
err = whal_Reg_ReadPoll(base, SPI_SR_REG, SPI_SR_BSY_Msk,
0, cfg->timeout);
err = whal_Reg32_ReadPoll(base, SPI_SR_REG, SPI_SR_BSY_Msk,
0, cfg->timeout);
```

A NULL timeout pointer means unbounded wait (poll forever).
Expand All @@ -305,16 +324,16 @@ before returning. Use a `goto cleanup` pattern:
```c
whal_Error err = WHAL_SUCCESS;

whal_Reg_Update(base, CR_REG, PG_Msk, 1); /* enable programming mode */
whal_Reg32_Update(base, CR_REG, PG_Msk, PG_Msk); /* enable programming */

for (...) {
err = whal_Reg_ReadPoll(base, SR_REG, BSY_Msk, 0, cfg->timeout);
err = whal_Reg32_ReadPoll(base, SR_REG, BSY_Msk, 0, cfg->timeout);
if (err)
goto cleanup;
}

cleanup:
whal_Reg_Update(base, CR_REG, PG_Msk, 0); /* always disable */
whal_Reg32_Update(base, CR_REG, PG_Msk, 0); /* always disable */
return err;
```

Expand Down Expand Up @@ -1121,7 +1140,7 @@ in the dispatch path.

```c
struct whal_Crypto {
const size_t base;
const uintptr_t base;
const whal_CryptoDriver *driver;
const void *cfg;
};
Expand Down Expand Up @@ -1436,7 +1455,7 @@ whal_Error whal_Myplatform_AesGcm_Oneshot(whal_AesGcm *dev,
const void *in, void *out, size_t sz,
void *tag, size_t tagSz)
{
size_t base = dev->crypto->base;
uintptr_t base = dev->crypto->base;
whal_Myplatform_Aes_Cfg *cfg =
(whal_Myplatform_Aes_Cfg *)dev->crypto->cfg;
/* Load key, IV, process AAD, encrypt/decrypt, compute tag */
Expand Down
Loading
Loading