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
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ jobs:
matrix:
board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra, stm32h563zi_nucleo, stm32f411_blackpill, stm32c031_nucleo]
extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"]
include:
- board: stm32wb55xx_nucleo
extra_cflags: "-DBOARD_DMA"
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,5 @@ dkms.conf
compile_commands.json

tests/core/test_core

*.pdf
5 changes: 4 additions & 1 deletion boards/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ build configuration.
| Board | Platform | CPU | Directory |
|-------|----------|-----|-----------|
| Microchip PIC32CZ CA Curiosity Ultra | PIC32CZ | Cortex-M7 | `pic32cz_curiosity_ultra/` |
| ST STM32WB55 Nucleo | STM32WB | Cortex-M4 | `stm32wb55xx_nucleo/` |
| ST NUCLEO-C031C6 | STM32C0 | Cortex-M0+ | `stm32c031_nucleo/` |
| WeAct BlackPill STM32F411 | STM32F4 | Cortex-M4 | `stm32f411_blackpill/` |
| ST NUCLEO-H563ZI | STM32H5 | Cortex-M33 | `stm32h563zi_nucleo/` |
| ST NUCLEO-WB55RG | STM32WB | Cortex-M4 | `stm32wb55xx_nucleo/` |

## Board Directory Contents

Expand Down
6 changes: 5 additions & 1 deletion boards/stm32wb55xx_nucleo/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy

CFLAGS += -Wall -Werror $(INCLUDE) -g3 \
-ffreestanding -nostdlib -mcpu=cortex-m4 \
-DPLATFORM_STM32WB -MMD -MP
-DPLATFORM_STM32WB -MMD -MP \
$(if $(DMA),-DBOARD_DMA)
LDFLAGS = --omagic -static

LINKER_SCRIPT ?= $(_BOARD_DIR)/linker.ld
Expand All @@ -29,6 +30,9 @@ BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/spi.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/rng.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/crypto.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/block.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/dma.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/irq.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/irq/cortex_m4_nvic.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/stm32wb_*.c)
BOARD_SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c)

Expand Down
93 changes: 92 additions & 1 deletion boards/stm32wb55xx_nucleo/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <wolfHAL/platform/st/stm32wb55xx.h>
#include "peripheral.h"


/* SysTick timing */
volatile uint32_t g_tick = 0;
volatile uint8_t g_waiting = 0;
Expand All @@ -30,6 +31,11 @@ whal_Timeout g_whalTimeout = {
.GetTick = Board_GetTick,
};

/* IRQ */
whal_Irq g_whalIrq = {
WHAL_CORTEX_M4_NVIC_DEVICE,
};

/* Clock */
whal_Clock g_whalClock = {
WHAL_STM32WB55_RCC_PLL_DEVICE,
Expand Down Expand Up @@ -155,7 +161,48 @@ whal_Timer g_whalTimer = {
},
};

/* DMA */
#ifdef BOARD_DMA

whal_Dma g_whalDma1 = {
WHAL_STM32WB55_DMA1_DEVICE,
.cfg = &(whal_Stm32wbDma_Cfg){WHAL_STM32WB55_DMA1_CFG},
};

static const whal_Stm32wbRcc_Clk g_dmaClock = {WHAL_STM32WB55_DMA1_CLOCK};
static const whal_Stm32wbRcc_Clk g_dmamuxClock = {WHAL_STM32WB55_DMAMUX1_CLOCK};

void DMA1_Channel4_IRQHandler(void)
{
whal_Stm32wbDma_IRQHandler(&g_whalDma1, 3,
whal_Stm32wbUartDma_TxCallback, g_whalUart.cfg);
}

void DMA1_Channel5_IRQHandler(void)
{
whal_Stm32wbDma_IRQHandler(&g_whalDma1, 4,
whal_Stm32wbUartDma_RxCallback, g_whalUart.cfg);
}
#endif

/* UART */
#ifdef BOARD_DMA
whal_Uart g_whalUart = {
WHAL_STM32WB55_UART1_DEVICE,
.driver = &whal_Stm32wbUartDma_Driver,
.cfg = &(whal_Stm32wbUartDma_Cfg) {
.base = {
.brr = WHAL_STM32WB_UART_BRR(64000000, 115200),
.timeout = &g_whalTimeout,
},
.dma = &g_whalDma1,
.txCh = 3,
.rxCh = 4,
.txChCfg = &(whal_Stm32wbDma_ChCfg){WHAL_STM32WB55_UART1_TX_DMA_CFG},
.rxChCfg = &(whal_Stm32wbDma_ChCfg){WHAL_STM32WB55_UART1_RX_DMA_CFG},
},
};
#else
whal_Uart g_whalUart = {
WHAL_STM32WB55_UART1_DEVICE,

Expand All @@ -165,6 +212,7 @@ whal_Uart g_whalUart = {
.brr = WHAL_STM32WB_UART_BRR(64000000, 115200),
},
};
#endif

/* Flash */
whal_Flash g_whalFlash = {
Expand All @@ -174,7 +222,7 @@ whal_Flash g_whalFlash = {
.timeout = &g_whalTimeout,

.startAddr = 0x08000000,
.size = 0x100000,
.size = 0x80000, /* 512 KB (upper half reserved for BLE stack) */
},
};

Expand Down Expand Up @@ -260,6 +308,30 @@ whal_Error Board_Init(void)
return err;
}

err = whal_Irq_Init(&g_whalIrq);
if (err)
return err;

#ifdef BOARD_DMA
err = whal_Clock_Enable(&g_whalClock, &g_dmaClock);
if (err)
return err;
err = whal_Clock_Enable(&g_whalClock, &g_dmamuxClock);
if (err)
return err;
err = whal_Dma_Init(&g_whalDma1);
if (err)
return err;

/* Enable NVIC interrupts for DMA1 channel 4 (IRQ 14) and channel 5 (IRQ 15) */
err = whal_Irq_Enable(&g_whalIrq, 14, NULL);
if (err)
return err;
err = whal_Irq_Enable(&g_whalIrq, 15, NULL);
if (err)
return err;
#endif

err = whal_Gpio_Init(&g_whalGpio);
if (err) {
return err;
Expand Down Expand Up @@ -357,6 +429,25 @@ whal_Error Board_Deinit(void)
return err;
}

#ifdef BOARD_DMA
whal_Irq_Disable(&g_whalIrq, 14);
whal_Irq_Disable(&g_whalIrq, 15);

err = whal_Dma_Deinit(&g_whalDma1);
if (err)
return err;
err = whal_Clock_Disable(&g_whalClock, &g_dmamuxClock);
if (err)
return err;
err = whal_Clock_Disable(&g_whalClock, &g_dmaClock);
if (err)
return err;
#endif

err = whal_Irq_Deinit(&g_whalIrq);
if (err)
return err;

/* Disable clocks */
for (size_t i = 0; i < CLOCK_COUNT; i++) {
err = whal_Clock_Disable(&g_whalClock, &g_clocks[i]);
Expand Down
5 changes: 3 additions & 2 deletions boards/stm32wb55xx_nucleo/board.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ extern whal_Spi g_whalSpi;
extern whal_Flash g_whalFlash;
extern whal_Rng g_whalRng;
extern whal_Crypto g_whalCrypto;
extern whal_Irq g_whalIrq;

extern whal_Timeout g_whalTimeout;
extern volatile uint32_t g_tick;
Expand All @@ -32,8 +33,8 @@ enum {
#define BOARD_LED_PORT_OFFSET 0x400 /* GPIOB */
#define BOARD_LED_PIN_NUM 5
#define BOARD_FLASH_START_ADDR 0x08000000
#define BOARD_FLASH_SIZE 0x100000
#define BOARD_FLASH_TEST_ADDR 0x08080000
#define BOARD_FLASH_SIZE 0x80000 /* 512 KB (upper half reserved for BLE stack) */
#define BOARD_FLASH_TEST_ADDR 0x0807F000
#define BOARD_FLASH_SECTOR_SZ 0x1000

enum {
Expand Down
105 changes: 105 additions & 0 deletions docs/writing_a_driver.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,51 @@ Receive `dataSz` bytes into the provided buffer. For each byte:
is available
2. Read the byte from the receive data register and store it in the buffer

### SendAsync

Start a non-blocking transmit. Returns immediately after initiating the
transfer. The buffer must remain valid until the transfer completes. The
driver signals completion through a platform-specific mechanism.

Drivers that do not support async should set SendAsync to NULL in the vtable.
The dispatch layer returns WHAL_EINVAL when the caller tries to use a NULL
async function.

### RecvAsync

Start a non-blocking receive. Returns immediately after initiating the
transfer. The buffer must remain valid until the transfer completes.

The async variants are optional — a driver vtable only needs to populate
them if the platform supports non-blocking transfers. Polled-only drivers
leave these NULL.

---

## IRQ

Header: `wolfHAL/irq/irq.h`

The IRQ driver controls an interrupt controller. It provides a
platform-independent way to enable and disable individual interrupt lines.

### Init

Initialize the interrupt controller.

### Deinit

Shut down the interrupt controller.

### Enable

Enable an interrupt line. The `irqCfg` parameter is platform-specific and
can contain settings such as priority. Pass NULL for defaults.

### Disable

Disable an interrupt line.

---

## SPI
Expand Down Expand Up @@ -857,6 +902,66 @@ issue the write command and poll for completion with a timeout.

---

## DMA

Header: `wolfHAL/dma/dma.h`

The DMA driver controls a DMA controller. A single device instance represents
one controller, and individual channels are identified by index. Channel
configuration is platform-specific and passed as an opaque pointer.

DMA is a service peripheral — peripheral drivers (UART, SPI) consume it
internally. The application never calls the DMA API directly. Peripheral
drivers receive a `whal_Dma` pointer and channel number through their
configuration struct and use them to set up transfers.

### Init

Initialize the DMA controller. Clear any pending interrupt flags and reset
controller state. The board must enable the DMA controller clock before calling
Init.

### Deinit

Shut down the DMA controller.

### Configure

Configure a DMA channel for transfers. The `chCfg` parameter is a
platform-specific struct containing:

- Transfer direction (memory-to-peripheral, peripheral-to-memory, etc.)
- Source and destination addresses
- Transfer width (8, 16, 32 bit)
- Buffer address and length
- Burst size (if supported)
- Peripheral request mapping (e.g., DMAMUX request ID)

The DMA driver does not store callbacks. Instead, the board defines ISR
entries in the vector table and calls the driver's IRQ handler (e.g.,
`whal_Stm32wbDma_IRQHandler()`), passing a callback and context pointer.
The IRQ handler checks and clears the interrupt flags, then invokes the
callback. Peripheral drivers expose their completion callbacks for the
board to wire up (e.g., `whal_Stm32wbUartDma_TxCallback`).

Configure sets up all channel registers but does not start the transfer.
Call Start to begin. A channel can be reconfigured between transfers (e.g.,
to change the buffer address and length) by calling Configure again.

### Start

Start a previously configured DMA channel. This enables the channel,
beginning the transfer. The channel must have been configured via Configure
before calling Start.

### Stop

Stop a DMA channel. This aborts any in-progress transfer and disables the
channel. The peripheral driver should call Stop in its cleanup path or when
a transfer needs to be cancelled.

---

## EthPhy

Header: `wolfHAL/eth_phy/eth_phy.h`
Expand Down
47 changes: 47 additions & 0 deletions src/dma/dma.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <wolfHAL/dma/dma.h>

inline whal_Error whal_Dma_Init(whal_Dma *dmaDev)
{
if (!dmaDev || !dmaDev->driver || !dmaDev->driver->Init) {
return WHAL_EINVAL;
}

return dmaDev->driver->Init(dmaDev);
}

inline whal_Error whal_Dma_Deinit(whal_Dma *dmaDev)
{
if (!dmaDev || !dmaDev->driver || !dmaDev->driver->Deinit) {
return WHAL_EINVAL;
}

return dmaDev->driver->Deinit(dmaDev);
}

inline whal_Error whal_Dma_Configure(whal_Dma *dmaDev, size_t ch,
const void *chCfg)
{
if (!dmaDev || !dmaDev->driver || !dmaDev->driver->Configure || !chCfg) {
return WHAL_EINVAL;
}

return dmaDev->driver->Configure(dmaDev, ch, chCfg);
}

inline whal_Error whal_Dma_Start(whal_Dma *dmaDev, size_t ch)
{
if (!dmaDev || !dmaDev->driver || !dmaDev->driver->Start) {
return WHAL_EINVAL;
}

return dmaDev->driver->Start(dmaDev, ch);
}

inline whal_Error whal_Dma_Stop(whal_Dma *dmaDev, size_t ch)
{
if (!dmaDev || !dmaDev->driver || !dmaDev->driver->Stop) {
return WHAL_EINVAL;
}

return dmaDev->driver->Stop(dmaDev, ch);
}
Loading
Loading