From 9c61284b6d892a193224cc10abe8373b505a5c52 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Sun, 15 Feb 2026 09:37:25 -0500 Subject: [PATCH 1/4] [pic32cz, example] Set stack pointer in reset handler --- examples/pic32cz/ivt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/pic32cz/ivt.c b/examples/pic32cz/ivt.c index 69a622c..5493981 100644 --- a/examples/pic32cz/ivt.c +++ b/examples/pic32cz/ivt.c @@ -54,6 +54,9 @@ void Reset_Handler(void) uint32_t* src = &_sidata; uint32_t* dst = &_sdata; + __asm__("ldr r0, =_estack\n\t" + "mov sp, r0"); + while (dst < &_edata) { *dst++ = *src++; } From 663299abf4f77a880bcfc0b36afa5c79df2e7042 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Sun, 15 Feb 2026 09:42:13 -0500 Subject: [PATCH 2/4] [pic32cz, stm32wb, driver] Make all driver vtables const --- src/clock/pic32cz_clock.c | 2 +- src/flash/stm32wb_flash.c | 2 +- src/spi/stm32wb_spi.c | 2 +- src/supply/pic32cz_supc.c | 2 +- src/timer/systick.c | 2 +- src/uart/pic32cz_uart.c | 2 +- src/uart/stm32wb_uart.c | 4 ++-- wolfHAL/clock/pic32cz_clock.h | 2 +- wolfHAL/flash/stm32wb_flash.h | 2 +- wolfHAL/spi/stm32wb_spi.h | 2 +- wolfHAL/supply/pic32cz_supc.h | 2 +- wolfHAL/timer/systick.h | 2 +- wolfHAL/uart/pic32cz_uart.h | 2 +- wolfHAL/uart/stm32wb_uart.h | 4 ++-- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/clock/pic32cz_clock.c b/src/clock/pic32cz_clock.c index 7a771f2..862dd70 100644 --- a/src/clock/pic32cz_clock.c +++ b/src/clock/pic32cz_clock.c @@ -269,7 +269,7 @@ whal_Error whal_Pic32czClock_GetRate(whal_Clock *clkDev, size_t *rateOut) return WHAL_SUCCESS; } -whal_ClockDriver whal_Pic32czClockPll_Driver = { +const whal_ClockDriver whal_Pic32czClockPll_Driver = { .Init = whal_Pic32czClockPll_Init, .Deinit = whal_Pic32czClockPll_Deinit, .Enable = whal_Pic32czClock_Enable, diff --git a/src/flash/stm32wb_flash.c b/src/flash/stm32wb_flash.c index be704aa..4143dfc 100644 --- a/src/flash/stm32wb_flash.c +++ b/src/flash/stm32wb_flash.c @@ -232,7 +232,7 @@ whal_Error whal_Stm32wbFlash_Ext_SetLatency(whal_Flash *flashDev, enum whal_Stm3 return WHAL_SUCCESS; } -whal_FlashDriver whal_Stm32wbFlash_Driver = { +const whal_FlashDriver whal_Stm32wbFlash_Driver = { .Init = whal_Stm32wbFlash_Init, .Deinit = whal_Stm32wbFlash_Deinit, .Lock = whal_Stm32wbFlash_Lock, diff --git a/src/spi/stm32wb_spi.c b/src/spi/stm32wb_spi.c index 224dde7..4c1501d 100644 --- a/src/spi/stm32wb_spi.c +++ b/src/spi/stm32wb_spi.c @@ -53,7 +53,7 @@ whal_Error whal_Stm32wbSpi_Recv(whal_Spi *spiDev, void *spiComCfg, uint8_t *data return WHAL_SUCCESS; } -whal_SpiDriver whal_Stm32wbSpi_Driver = { +const whal_SpiDriver whal_Stm32wbSpi_Driver = { .Init = whal_Stm32wbSpi_Init, .Deinit = whal_Stm32wbSpi_Deinit, .SendRecv = whal_Stm32wbSpi_SendRecv, diff --git a/src/supply/pic32cz_supc.c b/src/supply/pic32cz_supc.c index adbb27d..29de61d 100644 --- a/src/supply/pic32cz_supc.c +++ b/src/supply/pic32cz_supc.c @@ -44,7 +44,7 @@ whal_Error whal_Pic32czSupc_Disable(whal_Supply *supplyCtrl, void *supply) return WHAL_SUCCESS; } -whal_SupplyDriver whal_Pic32czSupc_Driver = { +const whal_SupplyDriver whal_Pic32czSupc_Driver = { .Init = whal_Pic32czSupc_Init, .Deinit = whal_Pic32czSupc_Deinit, .Enable = whal_Pic32czSupc_Enable, diff --git a/src/timer/systick.c b/src/timer/systick.c index 6d1279d..92a41ef 100644 --- a/src/timer/systick.c +++ b/src/timer/systick.c @@ -74,7 +74,7 @@ whal_Error SysTick_Reset(whal_Timer *timerDev) return WHAL_SUCCESS; } -whal_TimerDriver whal_SysTick_Driver = { +const whal_TimerDriver whal_SysTick_Driver = { .Init = SysTick_Init, .Deinit = SysTick_Deinit, .Start = SysTick_Start, diff --git a/src/uart/pic32cz_uart.c b/src/uart/pic32cz_uart.c index 0b67a84..4656431 100644 --- a/src/uart/pic32cz_uart.c +++ b/src/uart/pic32cz_uart.c @@ -275,7 +275,7 @@ whal_Error whal_Pic32czUart_Recv(whal_Uart *uartDev, uint8_t *data, size_t dataS return WHAL_SUCCESS; } -whal_UartDriver whal_Pic32czUart_Driver = { +const whal_UartDriver whal_Pic32czUart_Driver = { .Init = whal_Pic32czUart_Init, .Deinit = whal_Pic32czUart_Deinit, .Send = whal_Pic32czUart_Send, diff --git a/src/uart/stm32wb_uart.c b/src/uart/stm32wb_uart.c index 3cfe37d..38ba914 100644 --- a/src/uart/stm32wb_uart.c +++ b/src/uart/stm32wb_uart.c @@ -156,14 +156,14 @@ whal_Error whal_Stm32wbUart_Recv(whal_Uart *uartDev, uint8_t *data, size_t dataS return WHAL_SUCCESS; } -whal_UartDriver whal_Stm32wbUart_Driver = { +const whal_UartDriver whal_Stm32wbUart_Driver = { .Init = whal_Stm32wbUart_Init, .Deinit = whal_Stm32wbUart_Deinit, .Send = whal_Stm32wbUart_Send, .Recv = whal_Stm32wbUart_Recv, }; -whal_UartDriver whal_Stm32wbLpuart_Driver = { +const whal_UartDriver whal_Stm32wbLpuart_Driver = { .Init = whal_Stm32wbLpuart_Init, .Deinit = whal_Stm32wbUart_Deinit, .Send = whal_Stm32wbUart_Send, diff --git a/wolfHAL/clock/pic32cz_clock.h b/wolfHAL/clock/pic32cz_clock.h index bf1b22b..a04fcd2 100644 --- a/wolfHAL/clock/pic32cz_clock.h +++ b/wolfHAL/clock/pic32cz_clock.h @@ -195,7 +195,7 @@ typedef struct whal_Pic32czClock_Clk { /* * @brief Driver instance for PIC32CZ oscillator clock. */ -extern whal_ClockDriver whal_Pic32czClockPll_Driver; +extern const whal_ClockDriver whal_Pic32czClockPll_Driver; /* * @brief Initialize the PIC32CZ oscillator clock. diff --git a/wolfHAL/flash/stm32wb_flash.h b/wolfHAL/flash/stm32wb_flash.h index ee6f5b8..ed49830 100644 --- a/wolfHAL/flash/stm32wb_flash.h +++ b/wolfHAL/flash/stm32wb_flash.h @@ -52,7 +52,7 @@ typedef enum whal_Stm32wbFlash_Latency { /* * @brief Driver instance for STM32 flash. */ -extern whal_FlashDriver whal_Stm32wbFlash_Driver; +extern const whal_FlashDriver whal_Stm32wbFlash_Driver; /* * @brief Initialize the STM32 flash interface. diff --git a/wolfHAL/spi/stm32wb_spi.h b/wolfHAL/spi/stm32wb_spi.h index 0558290..b5f2b9c 100644 --- a/wolfHAL/spi/stm32wb_spi.h +++ b/wolfHAL/spi/stm32wb_spi.h @@ -32,7 +32,7 @@ typedef struct whal_Stm32wbSpi_ComCfg { /* * @brief Driver instance for STM32 SPI peripheral. */ -extern whal_SpiDriver whal_Stm32wbSpi_Driver; +extern const whal_SpiDriver whal_Stm32wbSpi_Driver; /* * @brief Initialize the STM32 SPI peripheral. diff --git a/wolfHAL/supply/pic32cz_supc.h b/wolfHAL/supply/pic32cz_supc.h index d842c1a..0f0d73b 100644 --- a/wolfHAL/supply/pic32cz_supc.h +++ b/wolfHAL/supply/pic32cz_supc.h @@ -22,7 +22,7 @@ typedef struct whal_Pic32czSupc_Supply { /* * @brief Driver instance for PIC32CZ SUPC peripheral. */ -extern whal_SupplyDriver whal_Pic32czSupc_Driver; +extern const whal_SupplyDriver whal_Pic32czSupc_Driver; /* * @brief Initialize the PIC32CZ SUPC peripheral. diff --git a/wolfHAL/timer/systick.h b/wolfHAL/timer/systick.h index 021eb8c..bcdb4db 100644 --- a/wolfHAL/timer/systick.h +++ b/wolfHAL/timer/systick.h @@ -37,7 +37,7 @@ typedef struct { /* * @brief Driver instance for the Cortex-M SysTick timer. */ -extern whal_TimerDriver whal_SysTick_Driver; +extern const whal_TimerDriver whal_SysTick_Driver; /* * @brief Initialize the SysTick timer with the configured clock and reload values. diff --git a/wolfHAL/uart/pic32cz_uart.h b/wolfHAL/uart/pic32cz_uart.h index c3b2578..de55c27 100644 --- a/wolfHAL/uart/pic32cz_uart.h +++ b/wolfHAL/uart/pic32cz_uart.h @@ -47,7 +47,7 @@ typedef struct whal_Pic32czUart_Cfg { /* * @brief Driver instance for PIC32CZ UART. */ -extern whal_UartDriver whal_Pic32czUart_Driver; +extern const whal_UartDriver whal_Pic32czUart_Driver; /* * @brief Initialize the PIC32CZ UART peripheral. diff --git a/wolfHAL/uart/stm32wb_uart.h b/wolfHAL/uart/stm32wb_uart.h index 2cfc198..746e358 100644 --- a/wolfHAL/uart/stm32wb_uart.h +++ b/wolfHAL/uart/stm32wb_uart.h @@ -23,8 +23,8 @@ typedef struct whal_Stm32wbUart_Cfg { /* * @brief Driver instance for STM32 UART peripheral. */ -extern whal_UartDriver whal_Stm32wbUart_Driver; -extern whal_UartDriver whal_Stm32wbLpuart_Driver; +extern const whal_UartDriver whal_Stm32wbUart_Driver; +extern const whal_UartDriver whal_Stm32wbLpuart_Driver; /* * @brief Initialize the STM32 UART peripheral. From cbf6ea907c27f96095ac8108a418d3d105dd0d84 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Fri, 13 Feb 2026 23:09:20 -0500 Subject: [PATCH 3/4] [pic32cz, flash] Implement initial flash driver --- examples/pic32cz/Makefile | 1 + examples/pic32cz/main.c | 30 ++ examples/pic32cz/pic32cz_curiosity_ultra.c | 4 + examples/pic32cz/pic32cz_curiosity_ultra.h | 1 + src/flash/pic32cz_flash.c | 343 +++++++++++++++++++++ wolfHAL/flash/pic32cz_flash.h | 123 ++++++++ wolfHAL/platform/microchip/pic32cz.h | 18 +- 7 files changed, 515 insertions(+), 5 deletions(-) create mode 100644 src/flash/pic32cz_flash.c create mode 100644 wolfHAL/flash/pic32cz_flash.h diff --git a/examples/pic32cz/Makefile b/examples/pic32cz/Makefile index 551ff3c..bf7f55c 100644 --- a/examples/pic32cz/Makefile +++ b/examples/pic32cz/Makefile @@ -15,6 +15,7 @@ SOURCE += $(wildcard $(WHAL_DIR)/src/*/clock.c) SOURCE += $(wildcard $(WHAL_DIR)/src/*/uart.c) SOURCE += $(wildcard $(WHAL_DIR)/src/*/timer.c) SOURCE += $(wildcard $(WHAL_DIR)/src/*/supply.c) +SOURCE += $(wildcard $(WHAL_DIR)/src/*/flash.c) SOURCE += $(wildcard $(WHAL_DIR)/src/*/pic32cz_*.c) SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c) diff --git a/examples/pic32cz/main.c b/examples/pic32cz/main.c index ae50a1c..b00f2f3 100644 --- a/examples/pic32cz/main.c +++ b/examples/pic32cz/main.c @@ -37,6 +37,8 @@ void main(void) { whal_Error err; uint8_t data[] = "Hello world!\r\n"; + uint8_t test[] = "test1\r\n"; + uint8_t tmp[sizeof(test)] = {0}; err = whal_Clock_Init(&g_whalClock); if (err) { @@ -58,6 +60,34 @@ void main(void) goto loop; } + err = whal_Flash_Init(&g_whalFlash); + if (err) { + goto loop; + } + + err = whal_Flash_Erase(&g_whalFlash, 0x0C000000, 0x1000); + if (err) { + goto loop; + } + + do { + err = whal_Flash_Write(&g_whalFlash, 0x0C000000, test, sizeof(test)); + } while (err == WHAL_ENOTREADY); + + if (err) { + goto loop; + } + + err = whal_Flash_Read(&g_whalFlash, 0x0C000000, tmp, sizeof(tmp)); + if (err) { + goto loop; + } + + err = whal_Uart_Send(&g_whalUart, tmp, sizeof(tmp)); + if (err) { + goto loop; + } + err = whal_Timer_Init(&g_whalTimer); if (err) { goto loop; diff --git a/examples/pic32cz/pic32cz_curiosity_ultra.c b/examples/pic32cz/pic32cz_curiosity_ultra.c index d638392..b95b232 100644 --- a/examples/pic32cz/pic32cz_curiosity_ultra.c +++ b/examples/pic32cz/pic32cz_curiosity_ultra.c @@ -96,3 +96,7 @@ whal_Timer g_whalTimer = { .tickInt = WHAL_SYSTICK_TICKINT_ENABLED, }, }; + +whal_Flash g_whalFlash = { + WHAL_PIC32CZ_FLASH_DEVICE, +}; diff --git a/examples/pic32cz/pic32cz_curiosity_ultra.h b/examples/pic32cz/pic32cz_curiosity_ultra.h index 1142d34..da89c28 100644 --- a/examples/pic32cz/pic32cz_curiosity_ultra.h +++ b/examples/pic32cz/pic32cz_curiosity_ultra.h @@ -9,5 +9,6 @@ extern whal_Clock g_whalClock; extern whal_Gpio g_whalGpio; extern whal_Timer g_whalTimer; extern whal_Uart g_whalUart; +extern whal_Flash g_whalFlash; #endif /* WHAL_PIC32CZ_CURIOSITY_ULTRA */ diff --git a/src/flash/pic32cz_flash.c b/src/flash/pic32cz_flash.c new file mode 100644 index 0000000..9334bd2 --- /dev/null +++ b/src/flash/pic32cz_flash.c @@ -0,0 +1,343 @@ +#include +#include +#include +#include +#include +#include + +/* + * PIC32CZ FCW (Flash Controller Write) Register Definitions + * + * The PIC32CZ uses FCW for flash write/erase operations. Each operation + * requires writing an unlock key to FCW_KEY before triggering via FCW_CTRLA. + */ + +/* Register offsets */ +#define FCW_CTRLA_REG 0x00 +#define FCW_MUTEX_REG 0x08 +#define FCW_INTFLAG_REG 0x14 +#define FCW_STATUS_REG 0x18 +#define FCW_KEY_REG 0x1C +#define FCW_ADDR_REG 0x20 +#define FCW_SRCADDR_REG 0x24 +#define FCW_DATA_REG(n) (0x28 + ((n) * 4)) + +/* CTRLA: NVM operation command and pre-program bit */ +#define FCW_CTRLA_NVMOP_MASK WHAL_MASK_RANGE(3, 0) +#define FCW_CTRLA_NVMOP_SINGLE_DWORD 0x1 +#define FCW_CTRLA_NVMOP_QUAD_DWORD 0x2 +#define FCW_CTRLA_NVMOP_PAGE_ERASE 0x4 +#define FCW_CTRLA_PREPG WHAL_MASK(7) + +/* MUTEX: NVM locking and ownership values */ +#define FCW_MUTEX_LOCK WHAL_MASK(0) +#define FCW_MUTEX_OWNER WHAL_MASK_RANGE(2, 1) + +/* INTFLAG: operation completion and error flags (write-1-to-clear) */ +#define FCW_INTFLAG_DONE WHAL_MASK(0) +#define FCW_INTFLAG_KEYERR WHAL_MASK(1) +#define FCW_INTFLAG_CFGERR WHAL_MASK(2) +#define FCW_INTFLAG_FIFOERR WHAL_MASK(3) +#define FCW_INTFLAG_BUSERR WHAL_MASK(4) +#define FCW_INTFLAG_WPERR WHAL_MASK(5) +#define FCW_INTFLAG_OPERR WHAL_MASK(6) +#define FCW_INTFLAG_SECERR WHAL_MASK(7) +#define FCW_INTFLAG_HTDPGM WHAL_MASK(8) +#define FCW_INTFLAG_BORERR WHAL_MASK(12) +#define FCW_INTFLAG_WRERR WHAL_MASK(13) + +#define FCW_INTFLAG_ALL_ERR (FCW_INTFLAG_KEYERR | FCW_INTFLAG_CFGERR | \ + FCW_INTFLAG_FIFOERR | FCW_INTFLAG_BUSERR | \ + FCW_INTFLAG_WPERR | FCW_INTFLAG_OPERR | \ + FCW_INTFLAG_SECERR | FCW_INTFLAG_HTDPGM | \ + FCW_INTFLAG_BORERR | FCW_INTFLAG_WRERR) + +#define FCW_INTFLAG_ALL (FCW_INTFLAG_DONE | FCW_INTFLAG_ALL_ERR) + +/* STATUS: busy flag */ +#define FCW_STATUS_BUSY WHAL_MASK(0) + +/* KEY: unlock value for write/erase operations */ +#define FCW_UNLOCK_WRKEY 0x91C32C01 + +/* Flash geometry */ +#define FCW_PAGE_SIZE 4096 +#define FCW_DWORD_SIZE 8 +#define FCW_QDWORD_SIZE 32 + +static void whal_Pic32czFlash_MutexLock(const whal_Regmap *reg) +{ + size_t locked = 1; + while (locked) { + whal_Reg_Get(reg->base, FCW_MUTEX_REG, FCW_MUTEX_LOCK, &locked); + } + + whal_Reg_Update(reg->base, FCW_MUTEX_REG, FCW_MUTEX_LOCK | FCW_MUTEX_OWNER, + whal_SetBits(FCW_MUTEX_LOCK, 1) | + whal_SetBits(FCW_MUTEX_OWNER, 1)); +} + +static void whal_Pic32czFlash_MutexUnlock(const whal_Regmap *reg) +{ + whal_Reg_Update(reg->base, FCW_MUTEX_REG, FCW_MUTEX_LOCK | FCW_MUTEX_OWNER, + whal_SetBits(FCW_MUTEX_LOCK, 0) | + whal_SetBits(FCW_MUTEX_OWNER, 1)); +} + +static void whal_Pic32czFlash_WaitBusy(const whal_Regmap *reg) +{ + size_t busy = 1; + while (busy) { + whal_Reg_Get(reg->base, FCW_STATUS_REG, FCW_STATUS_BUSY, &busy); + } +} + +/* + * Execute an FCW command: unlock, trigger, wait, and check for errors. + * Caller must set up FCW_ADDR and FCW_DATA registers before calling. + */ +static whal_Error whal_Pic32czFlash_ExecCmd(const whal_Regmap *reg, size_t cmd) +{ + size_t errFlags; + + /* Write unlock key */ + whal_Reg_Update(reg->base, FCW_KEY_REG, 0xFFFFFFFF, FCW_UNLOCK_WRKEY); + + /* Trigger operation with pre-program enabled */ + whal_Reg_Update(reg->base, FCW_CTRLA_REG, + FCW_CTRLA_NVMOP_MASK | FCW_CTRLA_PREPG, + whal_SetBits(FCW_CTRLA_NVMOP_MASK, cmd) | FCW_CTRLA_PREPG); + + /* Wait for completion */ + whal_Pic32czFlash_WaitBusy(reg); + + /* Check for errors */ + whal_Reg_Get(reg->base, FCW_INTFLAG_REG, FCW_INTFLAG_ALL_ERR, &errFlags); + + /* Clear DONE flag */ + whal_Reg_Update(reg->base, FCW_INTFLAG_REG, FCW_INTFLAG_DONE, + FCW_INTFLAG_DONE); + + if (errFlags) { + /* Clear error flags */ + whal_Reg_Update(reg->base, FCW_INTFLAG_REG, FCW_INTFLAG_ALL_ERR, + FCW_INTFLAG_ALL_ERR); + return WHAL_EINVAL; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Pic32czFlash_Init(whal_Flash *flashDev) +{ + const whal_Regmap *reg; + + if (!flashDev) { + return WHAL_EINVAL; + } + + reg = &flashDev->regmap; + + whal_Pic32czFlash_MutexUnlock(reg); + whal_Reg_Update(reg->base, FCW_KEY_REG, 0xFFFFFFFF, 0); + whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, 0); + whal_Reg_Update(reg->base, FCW_SRCADDR_REG, 0xFFFFFFFF, 0); + + /* Clear all pending interrupt flags */ + whal_Reg_Update(reg->base, FCW_INTFLAG_REG, FCW_INTFLAG_ALL, + FCW_INTFLAG_ALL); + + return WHAL_SUCCESS; +} + +whal_Error whal_Pic32czFlash_Deinit(whal_Flash *flashDev) +{ + const whal_Regmap *reg; + + if (!flashDev) { + return WHAL_EINVAL; + } + + reg = &flashDev->regmap; + + whal_Pic32czFlash_MutexUnlock(reg); + whal_Reg_Update(reg->base, FCW_KEY_REG, 0xFFFFFFFF, 0); + whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, 0); + whal_Reg_Update(reg->base, FCW_SRCADDR_REG, 0xFFFFFFFF, 0); + + /* Clear all pending interrupt flags */ + whal_Reg_Update(reg->base, FCW_INTFLAG_REG, FCW_INTFLAG_ALL, + FCW_INTFLAG_ALL); + + return WHAL_SUCCESS; +} + +whal_Error whal_Pic32czFlash_Lock(whal_Flash *flashDev, size_t addr, size_t len) +{ + /* + * TODO: Implement using FCW_PWP[0..7] region write-protect registers. + * Each FCW operation already requires the unlock key, providing + * inherent per-operation protection. + */ + (void)addr; + (void)len; + + if (!flashDev) { + return WHAL_EINVAL; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Pic32czFlash_Unlock(whal_Flash *flashDev, size_t addr, size_t len) +{ + (void)addr; + (void)len; + + if (!flashDev) { + return WHAL_EINVAL; + } + + return WHAL_SUCCESS; +} + +whal_Error whal_Pic32czFlash_Read(whal_Flash *flashDev, size_t addr, uint8_t *data, + size_t dataSz) +{ + const whal_Regmap *reg; + uint8_t *flashAddr = (uint8_t *)addr; + size_t i; + + if (!flashDev || !data) { + return WHAL_EINVAL; + } + + reg = &flashDev->regmap; + + whal_Pic32czFlash_MutexLock(reg); + + /* Flash is memory-mapped; read directly */ + for (i = 0; i < dataSz; i++) { + data[i] = flashAddr[i]; + } + + whal_Pic32czFlash_MutexUnlock(reg); + + return WHAL_SUCCESS; +} + +whal_Error whal_Pic32czFlash_Write(whal_Flash *flashDev, size_t addr, const uint8_t *data, + size_t dataSz) +{ + const whal_Regmap *reg; + const uint32_t *src; + whal_Error err; + size_t offset = 0; + + if (!flashDev || !data) { + return WHAL_EINVAL; + } + + /* Require double-word alignment */ + if ((addr & 0x7) || (dataSz & 0x7)) { + return WHAL_EINVAL; + } + + reg = &flashDev->regmap; + src = (const uint32_t *)data; + + whal_Pic32czFlash_MutexLock(reg); + + while (offset < dataSz) { + size_t curAddr = addr + offset; + size_t remaining = dataSz - offset; + + whal_Pic32czFlash_WaitBusy(reg); + + if (!(curAddr & 0x1F) && remaining >= FCW_QDWORD_SIZE) { + /* Quad double word write (32 bytes) */ + size_t j; + for (j = 0; j < 8; j++) { + whal_Reg_Update(reg->base, FCW_DATA_REG(j), + 0xFFFFFFFF, src[offset / 4 + j]); + } + whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, curAddr); + + err = whal_Pic32czFlash_ExecCmd(reg, + FCW_CTRLA_NVMOP_QUAD_DWORD); + if (err) { + whal_Pic32czFlash_MutexUnlock(reg); + return err; + } + offset += FCW_QDWORD_SIZE; + } else { + /* Single double word write (8 bytes) */ + whal_Reg_Update(reg->base, FCW_DATA_REG(0), + 0xFFFFFFFF, src[offset / 4]); + whal_Reg_Update(reg->base, FCW_DATA_REG(1), + 0xFFFFFFFF, src[offset / 4 + 1]); + whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, curAddr); + + err = whal_Pic32czFlash_ExecCmd(reg, + FCW_CTRLA_NVMOP_SINGLE_DWORD); + if (err) { + whal_Pic32czFlash_MutexUnlock(reg); + return err; + } + offset += FCW_DWORD_SIZE; + } + + } + + whal_Pic32czFlash_MutexUnlock(reg); + + return WHAL_SUCCESS; +} + +whal_Error whal_Pic32czFlash_Erase(whal_Flash *flashDev, size_t addr, size_t dataSz) +{ + const whal_Regmap *reg; + whal_Error err; + size_t pageAddr; + size_t endAddr; + + if (!flashDev) { + return WHAL_EINVAL; + } + + reg = &flashDev->regmap; + + /* Align down to page boundary */ + pageAddr = addr & ~(FCW_PAGE_SIZE - 1); + endAddr = addr + dataSz; + + whal_Pic32czFlash_MutexLock(reg); + + while (pageAddr < endAddr) { + whal_Pic32czFlash_WaitBusy(reg); + + whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, pageAddr); + + err = whal_Pic32czFlash_ExecCmd(reg, FCW_CTRLA_NVMOP_PAGE_ERASE); + if (err) { + whal_Pic32czFlash_MutexUnlock(reg); + return err; + } + + pageAddr += FCW_PAGE_SIZE; + } + + whal_Pic32czFlash_MutexUnlock(reg); + + return WHAL_SUCCESS; +} + +const whal_FlashDriver whal_Pic32czFlash_Driver = { + .Init = whal_Pic32czFlash_Init, + .Deinit = whal_Pic32czFlash_Deinit, + .Lock = whal_Pic32czFlash_Lock, + .Unlock = whal_Pic32czFlash_Unlock, + .Read = whal_Pic32czFlash_Read, + .Write = whal_Pic32czFlash_Write, + .Erase = whal_Pic32czFlash_Erase, +}; diff --git a/wolfHAL/flash/pic32cz_flash.h b/wolfHAL/flash/pic32cz_flash.h new file mode 100644 index 0000000..f22c1fa --- /dev/null +++ b/wolfHAL/flash/pic32cz_flash.h @@ -0,0 +1,123 @@ +#ifndef WHAL_PIC32CZ_FLASH_H +#define WHAL_PIC32CZ_FLASH_H + +#include +#include + +/* + * @file pic32cz_flash.h + * @brief PIC32CZ FCW (Flash Controller Write) driver configuration. + * + * The PIC32CZ flash is organized as: + * Page (erase unit) = 4096 bytes + * Row (row-write unit) = 1024 bytes + * Quad double word = 32 bytes (8 x uint32) + * Single double word = 8 bytes (2 x uint32) + * + * Write operations require double-word (8-byte) aligned addresses and sizes. + * Erase operations erase full 4 KB pages. + * Each write/erase operation requires an unlock key written to FCW_KEY. + */ + +#define WHAL_PIC32CZ_FLASH_PAGE_SIZE 4096 +#define WHAL_PIC32CZ_FLASH_DWORD_SIZE 8 +#define WHAL_PIC32CZ_FLASH_QDWORD_SIZE 32 + +/* + * @brief Flash device configuration. + */ +typedef struct whal_Pic32czFlash_Cfg { + size_t startAddr; + size_t size; +} whal_Pic32czFlash_Cfg; + +/* + * @brief Driver instance for PIC32CZ flash. + */ +extern const whal_FlashDriver whal_Pic32czFlash_Driver; + +/* + * @brief Initialize the PIC32CZ flash interface. + * + * @param flashDev Flash device instance to initialize. + * + * @retval WHAL_SUCCESS Initialization completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Pic32czFlash_Init(whal_Flash *flashDev); +/* + * @brief Deinitialize the PIC32CZ flash interface. + * + * @param flashDev Flash device instance to deinitialize. + * + * @retval WHAL_SUCCESS Deinit completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Pic32czFlash_Deinit(whal_Flash *flashDev); +/* + * @brief Lock a flash range (stub, not yet implemented). + * + * @param flashDev Flash device instance. + * @param addr Flash address to lock. + * @param len Number of bytes to lock. + * + * @retval WHAL_SUCCESS Lock applied. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Pic32czFlash_Lock(whal_Flash *flashDev, size_t addr, size_t len); +/* + * @brief Unlock a flash range (stub, not yet implemented). + * + * @param flashDev Flash device instance. + * @param addr Flash address to unlock. + * @param len Number of bytes to unlock. + * + * @retval WHAL_SUCCESS Unlock applied. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Pic32czFlash_Unlock(whal_Flash *flashDev, size_t addr, size_t len); +/* + * @brief Read data from flash into a buffer. + * + * @param flashDev Flash device instance. + * @param addr Flash address to read. + * @param data Destination buffer. + * @param dataSz Number of bytes to read. + * + * @retval WHAL_SUCCESS Read completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Pic32czFlash_Read(whal_Flash *flashDev, size_t addr, uint8_t *data, + size_t dataSz); +/* + * @brief Write a block of data to flash. + * + * Address and size must be double-word (8-byte) aligned. Uses quad double + * word writes (32 bytes) where alignment permits, falling back to single + * double word writes (8 bytes) for the remainder. + * + * @param flashDev Flash device instance. + * @param addr Flash address to program (8-byte aligned). + * @param data Buffer to program (8-byte aligned). + * @param dataSz Number of bytes to program (multiple of 8). + * + * @retval WHAL_SUCCESS Program completed. + * @retval WHAL_EINVAL Invalid arguments or alignment. + */ +whal_Error whal_Pic32czFlash_Write(whal_Flash *flashDev, size_t addr, const uint8_t *data, + size_t dataSz); +/* + * @brief Erase flash pages covering the given range. + * + * Erases all 4 KB pages that overlap the address range [addr, addr+dataSz). + * + * @param flashDev Flash device instance. + * @param addr Flash address to start erasing. + * @param dataSz Number of bytes to erase. + * + * @retval WHAL_SUCCESS Erase completed. + * @retval WHAL_EINVAL Invalid arguments. + */ +whal_Error whal_Pic32czFlash_Erase(whal_Flash *flashDev, size_t addr, size_t dataSz); + +#endif /* WHAL_PIC32CZ_FLASH_H */ diff --git a/wolfHAL/platform/microchip/pic32cz.h b/wolfHAL/platform/microchip/pic32cz.h index bab10f9..e31bb3f 100644 --- a/wolfHAL/platform/microchip/pic32cz.h +++ b/wolfHAL/platform/microchip/pic32cz.h @@ -5,8 +5,16 @@ #include #include #include +#include #include +#define WHAL_PIC32CZ_FLASH_DEVICE \ + .regmap = { \ + .base = 0x44002000, \ + .size = 0x4000, \ + }, \ + .driver = &whal_Pic32czFlash_Driver + #define WHAL_PIC32CZ_SUPPLY_DEVICE \ .regmap = { \ .base = 0x44020000, \ @@ -28,11 +36,11 @@ }, \ .driver = &whal_Pic32czGpio_Driver -#define WHAL_PIC32CZ_SERCOM4_UART_DEVICE \ - .regmap = { \ - .base = 0x46004000, \ - .size = 0x2000, \ - }, \ +#define WHAL_PIC32CZ_SERCOM4_UART_DEVICE \ + .regmap = { \ + .base = 0x46004000, \ + .size = 0x2000, \ + }, \ .driver = &whal_Pic32czUart_Driver #define WHAL_PIC32CZ_SUPPLY_PLL \ From 00c7c6efc92c1e0c13cf7e33fa7537416a1118f4 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Sun, 15 Feb 2026 11:16:46 -0500 Subject: [PATCH 4/4] [pic32cz, tests] Add pic32cz test suite --- .github/workflows/ci.yml | 4 ++ tests/pic32cz/Makefile | 52 +++++++++++++++++ tests/pic32cz/test.xml | 56 +++++++++++++++++++ tests/pic32cz/test_clock.c | 61 ++++++++++++++++++++ tests/pic32cz/test_flash.c | 57 +++++++++++++++++++ tests/pic32cz/test_gpio.c | 62 ++++++++++++++++++++ tests/pic32cz/test_main.c | 112 +++++++++++++++++++++++++++++++++++++ tests/pic32cz/test_timer.c | 32 +++++++++++ 8 files changed, 436 insertions(+) create mode 100644 tests/pic32cz/Makefile create mode 100644 tests/pic32cz/test.xml create mode 100644 tests/pic32cz/test_clock.c create mode 100644 tests/pic32cz/test_flash.c create mode 100644 tests/pic32cz/test_gpio.c create mode 100644 tests/pic32cz/test_main.c create mode 100644 tests/pic32cz/test_timer.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cc38ba0..8c8330a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,3 +35,7 @@ jobs: - name: Build PIC32CZ example working-directory: examples/pic32cz run: make + + - name: Build PIC32CZ hardware tests + working-directory: tests/pic32cz + run: make diff --git a/tests/pic32cz/Makefile b/tests/pic32cz/Makefile new file mode 100644 index 0000000..5719913 --- /dev/null +++ b/tests/pic32cz/Makefile @@ -0,0 +1,52 @@ +WHAL_DIR = $(PWD)/../../ +EXAMPLE_DIR = $(WHAL_DIR)/examples/pic32cz + +INCLUDE = -I$(WHAL_DIR) -I$(EXAMPLE_DIR) +CFLAGS = -Wall -Werror $(INCLUDE) -g3 \ + -ffreestanding -nostdlib -mcpu=cortex-m7 \ + -MMD -MF $(DEPDIR)/$*.d +LDFLAGS = -static + +DEPDIR = .deps/ + +# Test sources +TEST_SRC = test_main.c test_clock.c test_gpio.c test_flash.c test_timer.c + +# Board config and IVT from the example +BOARD_SRC = $(EXAMPLE_DIR)/pic32cz_curiosity_ultra.c \ + $(EXAMPLE_DIR)/ivt.c + +# All wolfHAL sources (generic + platform drivers) +WHAL_SRC = $(wildcard $(WHAL_DIR)/src/*.c) \ + $(wildcard $(WHAL_DIR)/src/*/*.c) + +SOURCE = $(TEST_SRC) $(BOARD_SRC) $(WHAL_SRC) +OBJECTS = $(patsubst %.c,%.o,$(SOURCE)) +DEPENDS = $(patsubst %.c,$(DEPDIR)/%.d,$(SOURCE)) + +GCC = $(GCC_PATH)arm-none-eabi-gcc +LD = $(GCC_PATH)arm-none-eabi-ld +OBJCOPY = $(GCC_PATH)arm-none-eabi-objcopy + +LINKER_SCRIPT = $(EXAMPLE_DIR)/linker.ld + +all: test_hw.bin + +%.d: + @mkdir -p $(@D) + +%.o: %.c Makefile + $(GCC) $(CFLAGS) -c -o $@ $< + +.SECONDARY: +%.elf: $(OBJECTS) $(LINKER_SCRIPT) + $(LD) $(LDFLAGS) -T $(LINKER_SCRIPT) -o $@ $(OBJECTS) + +%.bin: %.elf + $(OBJCOPY) $^ -O binary $@ + +.PHONY: clean +clean: + rm -rf $(DEPDIR) $(OBJECTS) test_hw.bin test_hw.elf + +-include $(DEPENDS) diff --git a/tests/pic32cz/test.xml b/tests/pic32cz/test.xml new file mode 100644 index 0000000..f5ecb8d --- /dev/null +++ b/tests/pic32cz/test.xml @@ -0,0 +1,56 @@ + + + arm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/pic32cz/test_clock.c b/tests/pic32cz/test_clock.c new file mode 100644 index 0000000..336db3c --- /dev/null +++ b/tests/pic32cz/test_clock.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include "pic32cz_curiosity_ultra.h" +#include "../test.h" + +/* + * GCLK peripheral channel control register layout: + * Offset from clock base: 0x10000 + 0x80 + (channel * 4) + * GEN field: bits [3:0] + * CHEN bit: bit 6 + * + * MCLK clock mask register layout: + * Offset from clock base: 0x12000 + 0x3C + (inst * 4) + */ +#define GCLK_PCHCTRL_OFFSET(ch) (0x10000 + 0x80 + ((ch) * 4)) +#define GCLK_PCHCTRL_CHEN WHAL_MASK(6) + +#define MCLK_CLKMSK_OFFSET(inst) (0x12000 + 0x3C + ((inst) * 4)) + +static void test_clock_enable_disable(void) +{ + /* Use a test clock descriptor for SERCOM4 (same as UART clock) */ + whal_Pic32czClock_Clk testClk = { + .gclkPeriphChannel = 25, + .gclkPeriphSrc = 0, + .mclkEnableInst = 1, + .mclkEnableMask = WHAL_MASK(3), + }; + + size_t val = 0; + + WHAL_ASSERT_EQ(whal_Clock_Enable(&g_whalClock, &testClk), WHAL_SUCCESS); + + /* Readback: GCLK PCHCTRL channel 25 CHEN bit should be set */ + whal_Reg_Get(g_whalClock.regmap.base, GCLK_PCHCTRL_OFFSET(25), + GCLK_PCHCTRL_CHEN, &val); + WHAL_ASSERT_EQ(val, 1); + + /* Readback: MCLK CLKMSK1 bit 3 should be set */ + whal_Reg_Get(g_whalClock.regmap.base, MCLK_CLKMSK_OFFSET(1), + WHAL_MASK(3), &val); + WHAL_ASSERT_EQ(val, 1); + + WHAL_ASSERT_EQ(whal_Clock_Disable(&g_whalClock, &testClk), WHAL_SUCCESS); + + /* After disable: CHEN should be cleared */ + whal_Reg_Get(g_whalClock.regmap.base, GCLK_PCHCTRL_OFFSET(25), + GCLK_PCHCTRL_CHEN, &val); + WHAL_ASSERT_EQ(val, 0); + + /* Re-enable so UART still works for remaining tests */ + WHAL_ASSERT_EQ(whal_Clock_Enable(&g_whalClock, &testClk), WHAL_SUCCESS); +} + +void test_clock(void) +{ + WHAL_TEST_SUITE_START("clock"); + WHAL_TEST(test_clock_enable_disable); + WHAL_TEST_SUITE_END(); +} diff --git a/tests/pic32cz/test_flash.c b/tests/pic32cz/test_flash.c new file mode 100644 index 0000000..85903fe --- /dev/null +++ b/tests/pic32cz/test_flash.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include "pic32cz_curiosity_ultra.h" +#include "../test.h" + +/* Test address in PFM (Program Flash Memory) data area */ +#define TEST_FLASH_ADDR 0x0C000000 +#define TEST_FLASH_SIZE 0x1000 + +static void test_flash_write_read(void) +{ + uint8_t pattern[] = "wolfHAL"; /* 8 bytes, double-word aligned */ + uint8_t readback[sizeof(pattern)] = {0}; + + WHAL_ASSERT_EQ(whal_Flash_Erase(&g_whalFlash, TEST_FLASH_ADDR, + TEST_FLASH_SIZE), + WHAL_SUCCESS); + + whal_Error err; + do { + err = whal_Flash_Write(&g_whalFlash, TEST_FLASH_ADDR, pattern, + sizeof(pattern)); + } while (err == WHAL_ENOTREADY); + WHAL_ASSERT_EQ(err, WHAL_SUCCESS); + + WHAL_ASSERT_EQ(whal_Flash_Read(&g_whalFlash, TEST_FLASH_ADDR, readback, + sizeof(readback)), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(pattern, readback, sizeof(pattern)); +} + +static void test_flash_erase_blank(void) +{ + uint8_t readback[8] = {0}; + uint8_t erased[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + WHAL_ASSERT_EQ(whal_Flash_Erase(&g_whalFlash, TEST_FLASH_ADDR, + TEST_FLASH_SIZE), + WHAL_SUCCESS); + + WHAL_ASSERT_EQ(whal_Flash_Read(&g_whalFlash, TEST_FLASH_ADDR, readback, + sizeof(readback)), + WHAL_SUCCESS); + + WHAL_ASSERT_MEM_EQ(readback, erased, sizeof(erased)); +} + +void test_flash(void) +{ + WHAL_TEST_SUITE_START("flash"); + WHAL_TEST(test_flash_erase_blank); + WHAL_TEST(test_flash_write_read); + WHAL_TEST_SUITE_END(); +} diff --git a/tests/pic32cz/test_gpio.c b/tests/pic32cz/test_gpio.c new file mode 100644 index 0000000..b321a24 --- /dev/null +++ b/tests/pic32cz/test_gpio.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include "pic32cz_curiosity_ultra.h" +#include "../test.h" + +/* Pin indices matching board config pin table */ +enum { + LED_PIN, + UART_TX_PIN, + UART_RX_PIN, +}; + +/* + * PIC32CZ PORT register offsets. + * Each port group is 0x80 bytes. LED is on port B (index 1), pin 21. + */ +#define PORT_DIR_REG(port) (0x00 + ((port) * 0x80)) +#define PORT_OUT_REG(port) (0x10 + ((port) * 0x80)) + +/* LED pin: port B, pin 21 */ +#define LED_PORT 1 +#define LED_HW_PIN 21 + +static void test_gpio_dir_register(void) +{ + /* PB21 should be configured as output (bit 21 set in DIR register) */ + size_t val = 0; + whal_Reg_Get(g_whalGpio.regmap.base, PORT_DIR_REG(LED_PORT), + WHAL_MASK(LED_HW_PIN), &val); + WHAL_ASSERT_EQ(val, 1); +} + +static void test_gpio_set_high(void) +{ + WHAL_ASSERT_EQ(whal_Gpio_Set(&g_whalGpio, LED_PIN, 1), WHAL_SUCCESS); + + /* Readback OUT register bit 21 */ + size_t val = 0; + whal_Reg_Get(g_whalGpio.regmap.base, PORT_OUT_REG(LED_PORT), + WHAL_MASK(LED_HW_PIN), &val); + WHAL_ASSERT_EQ(val, 1); +} + +static void test_gpio_set_low(void) +{ + WHAL_ASSERT_EQ(whal_Gpio_Set(&g_whalGpio, LED_PIN, 0), WHAL_SUCCESS); + + size_t val = 0; + whal_Reg_Get(g_whalGpio.regmap.base, PORT_OUT_REG(LED_PORT), + WHAL_MASK(LED_HW_PIN), &val); + WHAL_ASSERT_EQ(val, 0); +} + +void test_gpio(void) +{ + WHAL_TEST_SUITE_START("gpio"); + WHAL_TEST(test_gpio_dir_register); + WHAL_TEST(test_gpio_set_high); + WHAL_TEST(test_gpio_set_low); + WHAL_TEST_SUITE_END(); +} diff --git a/tests/pic32cz/test_main.c b/tests/pic32cz/test_main.c new file mode 100644 index 0000000..e1d1149 --- /dev/null +++ b/tests/pic32cz/test_main.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include "pic32cz_curiosity_ultra.h" +#include "../test.h" + +/* Pin indices matching board config pin table */ +enum { + LED_PIN, + UART_TX_PIN, + UART_RX_PIN, +}; + +int g_whalTestPassed; +int g_whalTestFailed; +int g_whalTestCurFailed; + +volatile size_t g_tick = 0; + +void SysTick_Handler(void) +{ + g_tick++; +} + +/* whalTest_Puts: send a string over UART, translating \n to \r\n */ +void whalTest_Puts(const char *s) +{ + while (*s) { + if (*s == '\n') + whal_Uart_Send(&g_whalUart, (const uint8_t *)"\r\n", 2); + else + whal_Uart_Send(&g_whalUart, (const uint8_t *)s, 1); + s++; + } +} + +/* Busy-wait delay using SysTick */ +static void delay_ms(size_t ms) +{ + size_t start = g_tick; + while (g_tick - start < ms) + ; +} + +void test_clock(void); +void test_gpio(void); +void test_flash(void); +void test_timer(void); + +void main(void) +{ + whal_Error err; + + g_whalTestPassed = 0; + g_whalTestFailed = 0; + + /* Bootstrap: clock -> GPIO -> UART -> flash -> timer */ + err = whal_Clock_Init(&g_whalClock); + if (err) + goto fail; + + err = whal_Gpio_Init(&g_whalGpio); + if (err) + goto fail; + + /* LED on to indicate boot */ + whal_Gpio_Set(&g_whalGpio, LED_PIN, 1); + + err = whal_Uart_Init(&g_whalUart); + if (err) + goto fail; + + err = whal_Flash_Init(&g_whalFlash); + if (err) + goto fail; + + err = whal_Timer_Init(&g_whalTimer); + if (err) + goto fail; + + err = whal_Timer_Start(&g_whalTimer); + if (err) + goto fail; + + whalTest_Printf("wolfHAL HW Test Suite (PIC32CZ)\n"); + whalTest_Printf("===============================\n"); + + /* Run test suites */ + test_clock(); + test_gpio(); + test_flash(); + test_timer(); + + WHAL_TEST_SUMMARY(); + + /* Visual indication: solid LED = all pass, blink = failure */ + if (g_whalTestFailed == 0) { + whal_Gpio_Set(&g_whalGpio, LED_PIN, 1); + while (1) + ; + } + +fail: + /* Rapid blink = failure */ + while (1) { + whal_Gpio_Set(&g_whalGpio, LED_PIN, 1); + delay_ms(100); + whal_Gpio_Set(&g_whalGpio, LED_PIN, 0); + delay_ms(100); + } +} diff --git a/tests/pic32cz/test_timer.c b/tests/pic32cz/test_timer.c new file mode 100644 index 0000000..d6251a3 --- /dev/null +++ b/tests/pic32cz/test_timer.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include "pic32cz_curiosity_ultra.h" +#include "../test.h" + +/* Tick counter incremented by SysTick_Handler in test_main.c */ +extern volatile size_t g_tick; + +static void test_timer_ticks_advance(void) +{ + size_t before = g_tick; + + /* Spin for ~100ms worth of ticks. At 1ms/tick this should yield ~100. */ + volatile size_t spin = 0; + while (g_tick - before < 100) { + spin++; + } + + size_t elapsed = g_tick - before; + + /* At least 100 ticks should have passed */ + WHAL_ASSERT_NEQ(elapsed, 0); + WHAL_ASSERT_EQ(elapsed >= 100, 1); +} + +void test_timer(void) +{ + WHAL_TEST_SUITE_START("timer"); + WHAL_TEST(test_timer_ticks_advance); + WHAL_TEST_SUITE_END(); +}