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
4 changes: 3 additions & 1 deletion examples/pic32cz/Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
WHAL_DIR = $(PWD)/../../
INCLUDE = -I$(WHAL_DIR)
CFLAGS = -Wall -Werror $(INCLUDE) -g3 \
-ffreestanding -nostdlib -mcpu=cortex-m33 \
-ffreestanding -nostdlib -mcpu=cortex-m7 \
-MMD -MF $(DEPDIR)/$*.d
LDFLAGS = --omagic -static

Expand All @@ -12,8 +12,10 @@ SOURCE += $(wildcard $(WHAL_DIR)/src/*.c)

SOURCE += $(wildcard $(WHAL_DIR)/src/*/gpio.c)
SOURCE += $(wildcard $(WHAL_DIR)/src/*/clock.c)
SOURCE += $(wildcard $(WHAL_DIR)/src/*/timer.c)
SOURCE += $(wildcard $(WHAL_DIR)/src/*/supply.c)
SOURCE += $(wildcard $(WHAL_DIR)/src/*/pic32cz_*.c)
SOURCE += $(wildcard $(WHAL_DIR)/src/*/systick.c)

OBJECTS = $(patsubst %.c,%.o,$(SOURCE))

Expand Down
48 changes: 26 additions & 22 deletions examples/pic32cz/ivt.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,6 @@ void Default_Handler(void)
}
}

void Reset_Handler(void)
{
uint32_t* src = &_sidata;
uint32_t* dst = &_sdata;

while (dst < &_edata) {
*dst++ = *src++;
}

dst = &_sbss;
while (dst < &_ebss) {
*dst++ = 0;
}

/* Call main */
main();

/* Never return */
while (1) {
}
}

/* Vector table */
__attribute__((section(".isr_vectors"))) const void* vector_table[] = {
/* Stack pointer */
Expand All @@ -70,3 +48,29 @@ __attribute__((section(".isr_vectors"))) const void* vector_table[] = {
PendSV_Handler,
SysTick_Handler,
};

void Reset_Handler(void)
{
uint32_t* src = &_sidata;
uint32_t* dst = &_sdata;

while (dst < &_edata) {
*dst++ = *src++;
}

dst = &_sbss;
while (dst < &_ebss) {
*dst++ = 0;
}

/* Point VTOR to our vector table (SCB->VTOR = 0xE000ED08) */
*(volatile uint32_t *)0xE000ED08 = (uint32_t)vector_table;

/* Call main */
main();

/* Never return */
while (1) {
}
}

48 changes: 47 additions & 1 deletion examples/pic32cz/main.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,38 @@
#include <wolfHAL/wolfHAL.h>
#include "pic32cz_curiosity_ultra.h"

volatile size_t g_tick = 0;
volatile uint8_t g_waiting = 0;
volatile uint8_t g_tickOverflow = 0;

Comment on lines 1 to +7
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

examples/pic32cz/main.c now uses uint8_t and SIZE_MAX, but the file doesn't include a header that defines them. This will fail to compile (or fail under -Werror) depending on the toolchain. Include the appropriate standard header(s) (e.g., <stdint.h> for uint8_t and SIZE_MAX).

Copilot uses AI. Check for mistakes.
void SysTick_Handler()
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SysTick_Handler() is defined with an empty parameter list, which is not a prototype in C and typically triggers -Wstrict-prototypes (and becomes an error with -Werror, which this Makefile enables). Define it with an explicit (void) parameter list to match the vector table declaration and avoid the warning.

Suggested change
void SysTick_Handler()
void SysTick_Handler(void)

Copilot uses AI. Check for mistakes.
{
size_t tickBefore = g_tick++;
if (g_waiting) {
if (tickBefore > g_tick)
g_tickOverflow = 1;
}
}

void WaitMs(size_t ms)
{
size_t startCount = g_tick;
g_waiting = 1;
while (1) {
size_t currentCount = g_tick;
if (g_tickOverflow) {
if ((SIZE_MAX - startCount) + currentCount > ms) {
break;
}
} else if (currentCount - startCount > ms) {
break;
}
}

g_waiting = 0;
g_tickOverflow = 0;
Comment on lines +10 to +33
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WaitMs() uses extra shared flags (g_waiting/g_tickOverflow) and a non-atomic handshake that can miss an overflow if wrap happens between startCount = g_tick; and g_waiting = 1;, causing an immediate underflow in currentCount - startCount. You can simplify and make this wrap-safe by relying on unsigned wraparound: loop until (size_t)(g_tick - startCount) >= ms (also fixes the current off-by-one from using > instead of >=).

Suggested change
size_t tickBefore = g_tick++;
if (g_waiting) {
if (tickBefore > g_tick)
g_tickOverflow = 1;
}
}
void WaitMs(size_t ms)
{
size_t startCount = g_tick;
g_waiting = 1;
while (1) {
size_t currentCount = g_tick;
if (g_tickOverflow) {
if ((SIZE_MAX - startCount) + currentCount > ms) {
break;
}
} else if (currentCount - startCount > ms) {
break;
}
}
g_waiting = 0;
g_tickOverflow = 0;
/* Increment the millisecond tick counter. Wraparound is handled in WaitMs. */
g_tick++;
}
void WaitMs(size_t ms)
{
size_t startCount = g_tick;
/* Busy-wait until the requested number of milliseconds has elapsed.
* This uses unsigned wraparound: the difference (g_tick - startCount)
* is well-defined even if g_tick wraps between calls. */
while ((size_t)(g_tick - startCount) < ms) {
/* spin */
}

Copilot uses AI. Check for mistakes.
}

void main(void)
{
whal_Error err;
Expand All @@ -15,7 +47,21 @@ void main(void)
goto loop;
}

whal_Gpio_Set(&gpio, 0, 1);
err = whal_Timer_Init(&g_whalTimer);
if (err) {
goto loop;
}

whal_Timer_Start(&g_whalTimer);

while (1) {
whal_Gpio_Set(&gpio, 0, 1);

WaitMs(1000);
whal_Gpio_Set(&gpio, 0, 0);
WaitMs(1000);
}


loop:
while (1);
Expand Down
14 changes: 12 additions & 2 deletions examples/pic32cz/pic32cz_curiosity_ultra.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ whal_Gpio gpio = {
.cfg = &(whal_Pic32czGpio_Cfg) {
.pinCfgCount = 1,
.pinCfg = &(whal_Pic32czGpio_PinCfg) {
.port = 0,
.pin = 0,
.port = 1,
.pin = 21,
.dir = WHAL_PIC32CZ_DIR_OUTPUT,
.out = 0,
},
Expand All @@ -60,3 +60,13 @@ whal_Pic32czClock_Clk periphClock = {
.mclkEnableInst = 0,
.mclkEnableMask = 0,
};

whal_Timer g_whalTimer = {
WHAL_CORTEX_M7_SYSTICK_DEVICE,

.cfg = &(whal_SysTick_Cfg) {
.cyclesPerTick = 300000000 / 1000,
.clkSrc = WHAL_SYSTICK_CLKSRC_SYSCLK,
.tickInt = WHAL_SYSTICK_TICKINT_ENABLED,
},
};
1 change: 1 addition & 0 deletions examples/pic32cz/pic32cz_curiosity_ultra.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
extern whal_Supply supply;
extern whal_Clock clock;
extern whal_Gpio gpio;
extern whal_Timer g_whalTimer;

#endif /* WHAL_PIC32CZ_CURIOSITY_ULTRA */
35 changes: 33 additions & 2 deletions src/clock/pic32cz_clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,15 @@
#define PIC32CZ_OSCCTRL_PLLxPOSTDIVA_POSTDIV0 WHAL_MASK_RANGE(5, 0) /* Output 0 divider */
#define PIC32CZ_OSCCTRL_PLLxPOSTDIVA_OUTEN0 WHAL_MASK(7) /* Output 0 enable */

/* OSCCTRL Status Register - PLL lock and oscillator ready flags */
#define PIC32CZ_OSCCTRL_STATUS_REG (PIC32CZ_OSCCTRL + 0x10)
#define PIC32CZ_OSCCTRL_STATUS_PLLxLOCK(pllInst) WHAL_MASK((24 + (pllInst)))

/* GCLK - Generic Clock Controller (base offset 0x10000) */
#define PIC32CZ_GCLK 0x10000

/* Generator Control Register - configures clock source and divider per generator */
#define PIC32CZ_GCLK_GENCTRLx_REG(gclkInst) (PIC32CZ_GCLK + 0x20 + (gclkInst * 0x4))
#define PIC32CZ_GCLK_GENCTRLx_REG(gclkInst) ((PIC32CZ_GCLK + 0x20 + (gclkInst * 0x4)))
#define PIC32CZ_GCLK_GENCTRLx_SRC WHAL_MASK_RANGE(4, 0) /* Source selection */
#define PIC32CZ_GCLK_GENCTRLx_GENEN WHAL_MASK(8) /* Generator enable */
#define PIC32CZ_GCLK_GENCTRLx_DIV WHAL_MASK_RANGE(31, 16) /* Division factor */
Expand All @@ -48,11 +52,19 @@
#define PIC32CZ_GCLK_PCHCTRLx_GEN WHAL_MASK_RANGE(3, 0) /* Generator selection */
#define PIC32CZ_GCLK_PCHCTRLx_CHEN WHAL_MASK(6) /* Channel enable */

/* GCLK Synchronization Busy Register - poll after writing GENCTRLx */
#define PIC32CZ_GCLK_SYNCBUSY_REG (PIC32CZ_GCLK + 0x04)
#define PIC32CZ_GCLK_SYNCBUSY_GENCTRLx(gclkInst) WHAL_MASK((2 + (gclkInst)))

/* MCLK - Main Clock Controller (base offset 0x12000) */
#define PIC32CZ_MCLK 0x12000

/* MCLK Interrupt Flag Register - clock ready status */
#define PIC32CZ_MCLK_INTFLAG_REG (PIC32CZ_MCLK + 0x08)
#define PIC32CZ_MCLK_INTFLAG_CKRDY WHAL_MASK(0) /* Clock ready */

/* CPU Clock Divider Register */
#define PIC32CZ_MCLK_DIV1_REG (PIC32CZ_MCLK + 0x14)
#define PIC32CZ_MCLK_DIV1_REG (PIC32CZ_MCLK + 0x10)
#define PIC32CZ_MCLK_DIV1 WHAL_MASK_RANGE(7, 0) /* CPU clock divider */

/* Peripheral Clock Mask Registers - enable/disable bus clocks to peripherals */
Expand Down Expand Up @@ -109,6 +121,7 @@ whal_Error whal_Pic32czClockPll_Init(whal_Clock *clkDev)
size_t PLLxFBDIV_REG;
size_t PLLxREFDIV_REG;
size_t PLLxPOSTDIVA_REG;
size_t status;

if (!clkDev) {
return WHAL_EINVAL;
Expand Down Expand Up @@ -151,10 +164,22 @@ whal_Error whal_Pic32czClockPll_Init(whal_Clock *clkDev)
whal_SetBits(PIC32CZ_OSCCTRL_PLLxCTRL_REFSEL, oscCtrlCfg->refSel) |
whal_SetBits(PIC32CZ_OSCCTRL_PLLxCTRL_BWSEL, oscCtrlCfg->bwSel));

/* Wait for PLL to lock */
do {
whal_Reg_Get(clkDev->regmap.base, PIC32CZ_OSCCTRL_STATUS_REG,
PIC32CZ_OSCCTRL_STATUS_PLLxLOCK(oscCtrlCfg->pllInst), &status);
} while (!status);

/* Configure CPU clock divider in MCLK */
whal_Reg_Update(clkDev->regmap.base, PIC32CZ_MCLK_DIV1_REG, PIC32CZ_MCLK_DIV1,
whal_SetBits(PIC32CZ_MCLK_DIV1, mclkCfg->div));

/* Wait for clock divider change to take effect */
do {
whal_Reg_Get(clkDev->regmap.base, PIC32CZ_MCLK_INTFLAG_REG,
PIC32CZ_MCLK_INTFLAG_CKRDY, &status);
} while (!status);

/* Configure each GCLK generator with its source and divider */
for (uint8_t i = 0; i < cfg->gclkCfgCount; ++i) {
whal_Pic32czClock_GclkCfg *gclkCfg = &cfg->gclkCfg[i];
Expand All @@ -163,6 +188,12 @@ whal_Error whal_Pic32czClockPll_Init(whal_Clock *clkDev)
whal_SetBits(PIC32CZ_GCLK_GENCTRLx_SRC, gclkCfg->genSrc) |
whal_SetBits(PIC32CZ_GCLK_GENCTRLx_GENEN, 1) |
whal_SetBits(PIC32CZ_GCLK_GENCTRLx_DIV, gclkCfg->genDiv));

/* Wait for generator synchronization */
do {
whal_Reg_Get(clkDev->regmap.base, PIC32CZ_GCLK_SYNCBUSY_REG,
PIC32CZ_GCLK_SYNCBUSY_GENCTRLx(gclkCfg->gen), &status);
} while (status);
}
Comment on lines 167 to 197
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The busy-wait polling loops added for PLL lock / CKRDY / GCLK SYNCBUSY have no timeout or failure path, so a misconfiguration or hardware fault will hang the system inside whal_Pic32czClockPll_Init(). Consider adding a bounded retry counter (or time-based timeout if a timebase exists) and return an error (e.g., WHAL_ENOTREADY) when the status bit never reaches the expected state.

Copilot uses AI. Check for mistakes.

return WHAL_SUCCESS;
Expand Down
48 changes: 29 additions & 19 deletions src/gpio/pic32cz_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,23 @@
* Each byte contains two 4-bit PMUX fields:
* - Lower nibble (bits 3:0): Even pin PMUX
* - Upper nibble (bits 7:4): Odd pin PMUX
*
* The APB bridge only supports 32-bit access, so the offset is word-aligned
* and the shift positions the pin's nibble within the 32-bit word.
*/
#define PIC32CZ_PMUXx_REG(port, pin) ((0x30 + ((pin) / 2)) + (port * 0x80))
#define PIC32CZ_PMUXx_REG(port, pin) ((0x30 + (((pin) / 8) * 4)) + ((port) * 0x80))
#define PIC32CZ_PMUXx_MASK(pin) (0xFul << (((pin) % 8) * 4))

/* Pin configuration register - one byte per pin */
#define PIC32CZ_PINCFGx_REG(port, pin) ((0x40 + (pin)) + (port * 0x80))
#define PIC32CZ_PINCFGx_PMUXEN WHAL_MASK(0) /* Enable peripheral mux */
#define PIC32CZ_PINCFGx_INEN WHAL_MASK(1) /* Enable input buffer */
#define PIC32CZ_PINCFGx_PULLEN WHAL_MASK(2) /* Enable pull resistor */
/*
* Pin configuration register - one byte per pin.
*
* Word-aligned for 32-bit access through the APB bridge. The pin argument
* positions each field's mask within the 32-bit word.
*/
#define PIC32CZ_PINCFGx_REG(port, pin) ((0x40 + ((pin) & ~3)) + ((port) * 0x80))
#define PIC32CZ_PINCFGx_PMUXEN(pin) (WHAL_MASK(0) << (((pin) & 3) * 8))
#define PIC32CZ_PINCFGx_INEN(pin) (WHAL_MASK(1) << (((pin) & 3) * 8))
#define PIC32CZ_PINCFGx_PULLEN(pin) (WHAL_MASK(2) << (((pin) & 3) * 8))

whal_Error whal_Pic32czGpio_Init(whal_Gpio *gpioDev)
{
Expand All @@ -53,13 +62,9 @@ whal_Error whal_Pic32czGpio_Init(whal_Gpio *gpioDev)
* Configure pin for peripheral function:
* 1. Set the PMUX value to select the peripheral function
* 2. Enable PMUXEN in PINCFG to route pin to peripheral
*
* PMUX register packs two 4-bit fields per byte:
* - Even pins use bits 3:0
* - Odd pins use bits 7:4
*/
uint8_t maskBit = (pinCfg->pin & 1) * 4;
size_t pmuxMask = WHAL_MASK_RANGE(maskBit + 3, maskBit);
size_t pmuxMask = PIC32CZ_PMUXx_MASK(pinCfg->pin);
size_t pmuxenMask = PIC32CZ_PINCFGx_PMUXEN(pinCfg->pin);

whal_Reg_Update(gpioDev->regmap.base,
PIC32CZ_PMUXx_REG(pinCfg->port, pinCfg->pin),
Expand All @@ -68,8 +73,8 @@ whal_Error whal_Pic32czGpio_Init(whal_Gpio *gpioDev)

whal_Reg_Update(gpioDev->regmap.base,
PIC32CZ_PINCFGx_REG(pinCfg->port, pinCfg->pin),
PIC32CZ_PINCFGx_PMUXEN,
whal_SetBits(PIC32CZ_PINCFGx_PMUXEN, 1));
pmuxenMask,
whal_SetBits(pmuxenMask, 1));

continue;
}
Expand All @@ -92,11 +97,16 @@ whal_Error whal_Pic32czGpio_Init(whal_Gpio *gpioDev)
whal_SetBits(pinMask, pinCfg->out));

/* Configure input buffer and pull resistor */
whal_Reg_Update(gpioDev->regmap.base,
PIC32CZ_PINCFGx_REG(pinCfg->port, pinCfg->pin),
PIC32CZ_PINCFGx_INEN | PIC32CZ_PINCFGx_PULLEN,
whal_SetBits(PIC32CZ_PINCFGx_INEN, pinCfg->inEn) |
whal_SetBits(PIC32CZ_PINCFGx_PULLEN, pinCfg->pullEn));
{
size_t inenMask = PIC32CZ_PINCFGx_INEN(pinCfg->pin);
size_t pullenMask = PIC32CZ_PINCFGx_PULLEN(pinCfg->pin);

whal_Reg_Update(gpioDev->regmap.base,
PIC32CZ_PINCFGx_REG(pinCfg->port, pinCfg->pin),
inenMask | pullenMask,
whal_SetBits(inenMask, pinCfg->inEn) |
whal_SetBits(pullenMask, pinCfg->pullEn));
}
}

return WHAL_SUCCESS;
Expand Down
1 change: 1 addition & 0 deletions src/reg.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ void whal_Reg_Get(const size_t base, const size_t offset, const size_t mask, siz
val = *(volatile size_t *)(base + offset);
*value = whal_GetBits(mask, val);
}

6 changes: 3 additions & 3 deletions src/spi/stm32wb_spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ whal_Error whal_Stm32wbSpi_Deinit(whal_Spi *spiDev)
}

whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uint8_t *tx,
size_t txLen, uint8_t *rx, size_t rxLen)
size_t txLen, uint8_t *rx, size_t rxLen)
{
(void)spiDev;
(void)spiComCfg;
Expand All @@ -34,7 +34,7 @@ whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uin
}

whal_Error whal_Stm32wbSpi_Send(whal_Spi *spiDev, void *spiComCfg, const uint8_t *data,
size_t dataSz)
size_t dataSz)
{
(void)spiDev;
(void)spiComCfg;
Expand All @@ -44,7 +44,7 @@ whal_Error whal_Stm32wbSpi_Send(whal_Spi *spiDev, void *spiComCfg, const uint8_t
}

whal_Error whal_Stm32wbSpi_Recv(whal_Spi *spiDev, void *spiComCfg, uint8_t *data,
size_t dataSz)
size_t dataSz)
{
(void)spiDev;
(void)spiComCfg;
Expand Down
13 changes: 13 additions & 0 deletions wolfHAL/platform/arm/cortex_m7.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef WHAL_CORTEX_M7_H
#define WHAL_CORTEX_M7_H

#include <wolfHAL/timer/systick.h>

#define WHAL_CORTEX_M7_SYSTICK_DEVICE \
.regmap = { \
.base = 0xE000E010, \
.size = 0x400, \
}, \
.driver = &whal_SysTick_Driver

#endif /* WHAL_CORTEX_M7_H */
1 change: 1 addition & 0 deletions wolfHAL/platform/microchip/pic32cz.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <wolfHAL/clock/pic32cz_clock.h>
#include <wolfHAL/supply/pic32cz_supc.h>
#include <wolfHAL/gpio/pic32cz_gpio.h>
#include <wolfHAL/platform/arm/cortex_m7.h>

#define WHAL_PIC32CZ_SUPPLY_DEVICE \
.regmap = { \
Expand Down