diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4426f28..11c898b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,33 +9,32 @@ on: jobs: core-tests: runs-on: ubuntu-latest + strategy: + matrix: + extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"] steps: - uses: actions/checkout@v4 - name: Build and run core tests working-directory: tests/core - run: make run + run: CFLAGS="${{ matrix.extra_cflags }}" make run cross-compile: runs-on: ubuntu-latest + strategy: + matrix: + board: [stm32wb55xx_nucleo, pic32cz_curiosity_ultra] + extra_cflags: ["", "-DWHAL_CFG_NO_TIMEOUT"] steps: - uses: actions/checkout@v4 - name: Install ARM toolchain run: sudo apt-get update && sudo apt-get install -y gcc-arm-none-eabi - - name: Build blinky (STM32WB) + - name: Build blinky working-directory: examples/blinky - run: make BOARD=stm32wb55xx_nucleo + run: CFLAGS="${{ matrix.extra_cflags }}" make BOARD=${{ matrix.board }} - - name: Build blinky (PIC32CZ) - working-directory: examples/blinky - run: make BOARD=pic32cz_curiosity_ultra - - - name: Build tests (STM32WB) - working-directory: tests - run: make BOARD=stm32wb55xx_nucleo - - - name: Build tests (PIC32CZ) + - name: Build tests working-directory: tests - run: make BOARD=pic32cz_curiosity_ultra + run: CFLAGS="${{ matrix.extra_cflags }}" make BOARD=${{ matrix.board }} diff --git a/boards/pic32cz_curiosity_ultra/board.c b/boards/pic32cz_curiosity_ultra/board.c index a78df0a..637a09a 100644 --- a/boards/pic32cz_curiosity_ultra/board.c +++ b/boards/pic32cz_curiosity_ultra/board.c @@ -115,13 +115,13 @@ whal_Flash g_whalFlash = { }; /* SysTick timing */ -volatile size_t g_tick = 0; +volatile uint32_t g_tick = 0; volatile uint8_t g_waiting = 0; volatile uint8_t g_tickOverflow = 0; void SysTick_Handler() { - size_t tickBefore = g_tick++; + uint32_t tickBefore = g_tick++; if (g_waiting) { if (tickBefore > g_tick) g_tickOverflow = 1; @@ -130,12 +130,12 @@ void SysTick_Handler() void Board_WaitMs(size_t ms) { - size_t startCount = g_tick; + uint32_t startCount = g_tick; g_waiting = 1; while (1) { - size_t currentCount = g_tick; + uint32_t currentCount = g_tick; if (g_tickOverflow) { - if ((SIZE_MAX - startCount) + currentCount > ms) { + if ((UINT32_MAX - startCount) + currentCount > ms) { break; } } else if (currentCount - startCount > ms) { diff --git a/boards/pic32cz_curiosity_ultra/board.h b/boards/pic32cz_curiosity_ultra/board.h index 5b44ef1..581a125 100644 --- a/boards/pic32cz_curiosity_ultra/board.h +++ b/boards/pic32cz_curiosity_ultra/board.h @@ -11,7 +11,7 @@ extern whal_Timer g_whalTimer; extern whal_Uart g_whalUart; extern whal_Flash g_whalFlash; -extern volatile size_t g_tick; +extern volatile uint32_t g_tick; #define BOARD_LED_PIN 0 #define BOARD_FLASH_TEST_ADDR 0x0C000000 diff --git a/boards/stm32wb55xx_nucleo/board.c b/boards/stm32wb55xx_nucleo/board.c index 8c55745..b52a327 100644 --- a/boards/stm32wb55xx_nucleo/board.c +++ b/boards/stm32wb55xx_nucleo/board.c @@ -5,6 +5,30 @@ #include "board.h" #include +/* SysTick timing */ +volatile uint32_t g_tick = 0; +volatile uint8_t g_waiting = 0; +volatile uint8_t g_tickOverflow = 0; + +void SysTick_Handler() +{ + uint32_t tickBefore = g_tick++; + if (g_waiting) { + if (tickBefore > g_tick) + g_tickOverflow = 1; + } +} + +uint32_t Board_GetTick(void) +{ + return g_tick; +} + +whal_Timeout g_whalTimeout = { + .timeoutTicks = 5, /* 5ms timeout */ + .GetTick = Board_GetTick, +}; + /* Clock */ whal_Clock g_whalClock = { WHAL_STM32WB55_RCC_PLL_DEVICE, @@ -95,6 +119,7 @@ whal_Uart g_whalUart = { .cfg = &(whal_Stm32wbUart_Cfg) { .clkCtrl = &g_whalClock, .clk = &(whal_Stm32wbRcc_Clk) {WHAL_STM32WB55_UART1_CLOCK}, + .timeout = &g_whalTimeout, .baud = 115200, }, @@ -107,6 +132,7 @@ whal_Flash g_whalFlash = { .cfg = &(whal_Stm32wbFlash_Cfg) { .clkCtrl = &g_whalClock, .clk = &(whal_Stm32wbRcc_Clk) {WHAL_STM32WB55_FLASH_CLOCK}, + .timeout = &g_whalTimeout, .startAddr = 0x08000000, .size = 0x100000, @@ -120,6 +146,7 @@ whal_Rng g_whalRng = { .cfg = &(whal_Stm32wbRng_Cfg) { .clkCtrl = &g_whalClock, .clk = &(whal_Stm32wbRcc_Clk) {WHAL_STM32WB55_RNG_CLOCK}, + .timeout = &g_whalTimeout, }, }; @@ -142,31 +169,18 @@ whal_Crypto g_whalCrypto = { .cfg = &(whal_Stm32wbAes_Cfg) { .clkCtrl = &g_whalClock, .clk = &(whal_Stm32wbRcc_Clk) {WHAL_STM32WB55_AES1_CLOCK}, + .timeout = &g_whalTimeout, }, }; -/* SysTick timing */ -volatile size_t g_tick = 0; -volatile uint8_t g_waiting = 0; -volatile uint8_t g_tickOverflow = 0; - -void SysTick_Handler() -{ - size_t tickBefore = g_tick++; - if (g_waiting) { - if (tickBefore > g_tick) - g_tickOverflow = 1; - } -} - void Board_WaitMs(size_t ms) { - size_t startCount = g_tick; + uint32_t startCount = g_tick; g_waiting = 1; while (1) { - size_t currentCount = g_tick; + uint32_t currentCount = g_tick; if (g_tickOverflow) { - if ((SIZE_MAX - startCount) + currentCount > ms) { + if ((UINT32_MAX - startCount) + currentCount > ms) { break; } } else if (currentCount - startCount > ms) { diff --git a/boards/stm32wb55xx_nucleo/board.h b/boards/stm32wb55xx_nucleo/board.h index dc6d8af..30093ff 100644 --- a/boards/stm32wb55xx_nucleo/board.h +++ b/boards/stm32wb55xx_nucleo/board.h @@ -13,7 +13,7 @@ extern whal_Flash g_whalFlash; extern whal_Rng g_whalRng; extern whal_Crypto g_whalCrypto; -extern volatile size_t g_tick; +extern volatile uint32_t g_tick; #define BOARD_LED_PIN 0 #define BOARD_FLASH_TEST_ADDR 0x08080000 diff --git a/docs/adding_a_board.md b/docs/adding_a_board.md index 1a82788..c8be036 100644 --- a/docs/adding_a_board.md +++ b/docs/adding_a_board.md @@ -19,11 +19,12 @@ Exports global peripheral instances and board-specific constants: #include -extern whal_Clock g_whalClock; -extern whal_Gpio g_whalGpio; -extern whal_Uart g_whalUart; -extern whal_Timer g_whalTimer; -extern whal_Flash g_whalFlash; +extern whal_Clock g_whalClock; +extern whal_Gpio g_whalGpio; +extern whal_Uart g_whalUart; +extern whal_Timer g_whalTimer; +extern whal_Flash g_whalFlash; +extern whal_Timeout g_whalTimeout; #define BOARD_LED_PIN 0 diff --git a/docs/getting_started.md b/docs/getting_started.md index d1fc521..8fb39d1 100644 --- a/docs/getting_started.md +++ b/docs/getting_started.md @@ -126,6 +126,7 @@ whal_Uart g_whalUart = { .cfg = &(whal_Stm32wbUart_Cfg) { .clkCtrl = &g_whalClock, .clk = &(whal_Stm32wbRcc_Clk){WHAL_STM32WB55_UART1_CLOCK}, + .timeout = &g_whalTimeout, .baud = 115200, }, }; @@ -202,6 +203,7 @@ operation completed. The error codes are: | `WHAL_EINVAL` | Invalid argument or unsupported operation | | `WHAL_ENOTREADY` | Resource is busy or not yet available | | `WHAL_EHARDWARE` | Hardware error (e.g., RNG entropy failure) | +| `WHAL_ETIMEOUT` | Operation timed out waiting for hardware | ## Optimizing for Size diff --git a/docs/writing_a_driver.md b/docs/writing_a_driver.md index 7d0d5f6..23f5247 100644 --- a/docs/writing_a_driver.md +++ b/docs/writing_a_driver.md @@ -62,6 +62,124 @@ 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. +### Timeouts + +Most drivers poll hardware status registers in busy-wait loops (e.g., waiting +for a DMA transfer to complete, a flash erase to finish, or an AES computation +to produce a result). wolfHAL provides an optional timeout mechanism to bound +these waits and prevent infinite hangs if hardware misbehaves. + +#### Timeout Struct + +The board creates a `whal_Timeout` instance with a tick source and a timeout +duration. Drivers receive a pointer to it through their configuration struct: + +```c +typedef struct { + uint32_t timeoutTicks; /* max ticks before timeout */ + uint32_t startTick; /* snapshot, set by START */ + uint32_t (*GetTick)(void); /* board-provided tick source */ +} whal_Timeout; +``` + +The tick units are determined by the board's `GetTick` implementation. A 1 kHz +SysTick gives millisecond ticks; a 1 MHz timer gives microsecond ticks. Drivers +do not need to know the tick rate. + +#### whal_Reg_ReadPoll + +For the common case of polling a register bit, use `whal_Reg_ReadPoll` from +`wolfHAL/regmap.h`: + +```c +whal_Error whal_Reg_ReadPoll(size_t base, size_t offset, + size_t mask, size_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: + +```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); + +/* Wait for BSY flag to be clear */ +err = whal_Reg_ReadPoll(base, SPI_SR_REG, SPI_SR_BSY_Msk, + 0, cfg->timeout); +``` + +A NULL timeout pointer means unbounded wait (poll forever). + +#### Driver-Specific Helpers + +When a driver has many polling sites that also need post-poll cleanup (e.g., +clearing a flag), wrap the pattern in a local helper to avoid code duplication: + +```c +static whal_Error WaitForCCF(size_t base, whal_Timeout *timeout) +{ + whal_Error err; + err = whal_Reg_ReadPoll(base, AES_SR_REG, AES_SR_CCF_Msk, + AES_SR_CCF_Msk, timeout); + if (err) + return err; + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + return WHAL_SUCCESS; +} +``` + +This keeps code size small — one function body shared across all call sites +instead of inlined polling loops at each location. + +#### Cleanup on Timeout + +When a timeout occurs during an operation that has enabled a hardware mode +(e.g., flash programming mode, AES enable), the driver must still clean up +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 */ + +for (...) { + err = whal_Reg_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 */ + return err; +``` + +Never return directly from inside a polling loop if the peripheral is in a +mode that requires cleanup. + +#### Compile-Time Disable + +Define `WHAL_CFG_NO_TIMEOUT` to remove all timeout logic from the binary. +When defined, `WHAL_TIMEOUT_START` becomes a no-op and `WHAL_TIMEOUT_EXPIRED` +always evaluates to `0`, so polling loops run until the hardware condition is +met with no overhead. + +#### Adding Timeout to a Config Struct + +Driver config structs that use polling should include an optional timeout +pointer: + +```c +typedef struct { + /* ... other config fields ... */ + whal_Timeout *timeout; +} whal_MyplatformFoo_Cfg; +``` + +The timeout is optional — if the board does not set it (NULL), all waits are +unbounded. + ### Avoiding Bloat When a peripheral has multiple distinct operating modes or configurations, diff --git a/src/crypto/stm32wb_aes.c b/src/crypto/stm32wb_aes.c index ea8a5cc..df71af0 100644 --- a/src/crypto/stm32wb_aes.c +++ b/src/crypto/stm32wb_aes.c @@ -138,6 +138,17 @@ static void ReadBlock(size_t base, uint8_t *out) whal_StoreBe32(out + 12, whal_Reg_Read(base, AES_DOUTR_REG)); } +static whal_Error WaitForCCF(size_t base, whal_Timeout *timeout) +{ + whal_Error err; + err = whal_Reg_ReadPoll(base, AES_SR_REG, AES_SR_CCF_Msk, + AES_SR_CCF_Msk, timeout); + if (err) + return err; + whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + return WHAL_SUCCESS; +} + whal_Error whal_Stm32wbAes_Init(whal_Crypto *cryptoDev) { @@ -184,7 +195,9 @@ whal_Error whal_Stm32wbAes_Deinit(whal_Crypto *cryptoDev) whal_Error whal_Stm32wbAes_AesEcb(whal_Crypto *cryptoDev, void *opArgs) { + whal_Error err = WHAL_SUCCESS; whal_Crypto_AesEcbArgs *args; + const whal_Stm32wbAes_Cfg *cfg; size_t base; size_t mode; size_t keySizeBit; @@ -204,6 +217,7 @@ whal_Error whal_Stm32wbAes_AesEcb(whal_Crypto *cryptoDev, void *opArgs) if (args->sz == 0 || (args->sz & 0xF) != 0) return WHAL_EINVAL; + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; base = cryptoDev->regmap.base; keySizeBit = (args->keySz == 32) ? 1 : 0; @@ -236,20 +250,24 @@ whal_Error whal_Stm32wbAes_AesEcb(whal_Crypto *cryptoDev, void *opArgs) uint8_t *out = args->out + i; WriteBlock(base, in); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; ReadBlock(base, out); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); } +cleanup: /* Disable AES */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); - return WHAL_SUCCESS; + return err; } whal_Error whal_Stm32wbAes_AesCbc(whal_Crypto *cryptoDev, void *opArgs) { + whal_Error err = WHAL_SUCCESS; whal_Crypto_AesCbcArgs *args; + const whal_Stm32wbAes_Cfg *cfg; size_t base; size_t mode; size_t keySizeBit; @@ -269,6 +287,7 @@ whal_Error whal_Stm32wbAes_AesCbc(whal_Crypto *cryptoDev, void *opArgs) if (args->sz == 0 || (args->sz & 0xF) != 0) return WHAL_EINVAL; + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; base = cryptoDev->regmap.base; keySizeBit = (args->keySz == 32) ? 1 : 0; @@ -302,20 +321,24 @@ whal_Error whal_Stm32wbAes_AesCbc(whal_Crypto *cryptoDev, void *opArgs) uint8_t *out = args->out + i; WriteBlock(base, in); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; ReadBlock(base, out); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); } +cleanup: /* Disable AES */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); - return WHAL_SUCCESS; + return err; } whal_Error whal_Stm32wbAes_AesCtr(whal_Crypto *cryptoDev, void *opArgs) { + whal_Error err = WHAL_SUCCESS; whal_Crypto_AesCtrArgs *args; + const whal_Stm32wbAes_Cfg *cfg; size_t base; size_t keySizeBit; size_t i; @@ -334,6 +357,7 @@ whal_Error whal_Stm32wbAes_AesCtr(whal_Crypto *cryptoDev, void *opArgs) if (args->sz == 0 || (args->sz & 0xF) != 0) return WHAL_EINVAL; + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; base = cryptoDev->regmap.base; keySizeBit = (args->keySz == 32) ? 1 : 0; @@ -365,20 +389,24 @@ whal_Error whal_Stm32wbAes_AesCtr(whal_Crypto *cryptoDev, void *opArgs) uint8_t *out = args->out + i; WriteBlock(base, in); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; ReadBlock(base, out); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); } +cleanup: /* Disable AES */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); - return WHAL_SUCCESS; + return err; } whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) { + whal_Error err = WHAL_SUCCESS; whal_Crypto_AesGcmArgs *args; + const whal_Stm32wbAes_Cfg *cfg; size_t base; size_t mode; size_t keySizeBit; @@ -408,6 +436,7 @@ whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) if (args->tagSz == 0 || args->tagSz > 16) return WHAL_EINVAL; + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; base = cryptoDev->regmap.base; keySizeBit = (args->keySz == 32) ? 1 : 0; @@ -444,8 +473,9 @@ whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) /* Enable AES — init phase runs, EN auto-clears when done */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; /* --- Header phase: process AAD --- */ if (args->aadSz > 0) { @@ -472,9 +502,9 @@ whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) WriteBlock(base, block); } - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, - AES_CR_CCFC_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; } } @@ -504,7 +534,9 @@ whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) WriteBlock(base, block); } - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; if (remain >= 16) { ReadBlock(base, out); @@ -513,9 +545,6 @@ whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) for (j = 0; j < remain; j++) out[j] = block[j]; } - - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, - AES_CR_CCFC_Msk); } } @@ -536,7 +565,9 @@ whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) whal_Reg_Write(base, AES_DINR_REG, 0); whal_Reg_Write(base, AES_DINR_REG, (uint32_t)(args->sz * 8)); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; /* Read tag from DOUTR */ ReadBlock(base, tagBuf); @@ -544,17 +575,18 @@ whal_Error whal_Stm32wbAes_AesGcm(whal_Crypto *cryptoDev, void *opArgs) for (i = 0; i < args->tagSz; i++) args->tag[i] = tagBuf[i]; - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); - +cleanup: /* Disable AES */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); - return WHAL_SUCCESS; + return err; } whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs) { + whal_Error err = WHAL_SUCCESS; whal_Crypto_AesGmacArgs *args; + const whal_Stm32wbAes_Cfg *cfg; size_t base; size_t keySizeBit; size_t i; @@ -580,6 +612,7 @@ whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs) if (args->tagSz == 0 || args->tagSz > 16) return WHAL_EINVAL; + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; base = cryptoDev->regmap.base; keySizeBit = (args->keySz == 32) ? 1 : 0; @@ -613,8 +646,9 @@ whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs) /* Enable — init phase runs, EN auto-clears */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; /* --- Header phase: process AAD --- */ if (args->aadSz > 0) { @@ -641,9 +675,9 @@ whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs) WriteBlock(base, block); } - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, - AES_CR_CCFC_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; } } @@ -664,7 +698,9 @@ whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs) whal_Reg_Write(base, AES_DINR_REG, 0); whal_Reg_Write(base, AES_DINR_REG, 0); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; /* Read tag from DOUTR */ ReadBlock(base, tagBuf); @@ -672,17 +708,18 @@ whal_Error whal_Stm32wbAes_AesGmac(whal_Crypto *cryptoDev, void *opArgs) for (i = 0; i < args->tagSz; i++) args->tag[i] = tagBuf[i]; - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); - +cleanup: /* Disable AES */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); - return WHAL_SUCCESS; + return err; } whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) { + whal_Error err = WHAL_SUCCESS; whal_Crypto_AesCcmArgs *args; + const whal_Stm32wbAes_Cfg *cfg; size_t base; size_t mode; size_t keySizeBit; @@ -714,6 +751,7 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) if (args->tagSz < 4 || args->tagSz > 16 || (args->tagSz & 1) != 0) return WHAL_EINVAL; + cfg = (const whal_Stm32wbAes_Cfg *)cryptoDev->cfg; base = cryptoDev->regmap.base; keySizeBit = (args->keySz == 32) ? 1 : 0; @@ -772,8 +810,9 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) /* Enable — init phase runs, EN auto-clears */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, AES_CR_EN_Msk); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; /* --- Header phase: process AAD with length prefix --- */ if (args->aadSz > 0) { @@ -809,9 +848,9 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) /* Write first block */ WriteBlock(base, hdrBuf); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, - AES_CR_CCFC_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; /* Process remaining AAD in 16-byte blocks */ while (aadOff < args->aadSz) { @@ -822,9 +861,9 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) block[j] = args->aad[aadOff++]; WriteBlock(base, block); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, - AES_CR_CCFC_Msk); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; } } } @@ -856,7 +895,9 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) WriteBlock(base, block); } - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; if (remain >= 16) { ReadBlock(base, out); @@ -865,9 +906,6 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) for (j = 0; j < remain; j++) out[j] = block[j]; } - - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, - AES_CR_CCFC_Msk); } } @@ -888,7 +926,9 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) whal_Reg_Write(base, AES_DINR_REG, 0); whal_Reg_Write(base, AES_DINR_REG, 0); - while (!(whal_Reg_Read(base, AES_SR_REG) & AES_SR_CCF_Msk)); + err = WaitForCCF(base, cfg->timeout); + if (err) + goto cleanup; /* Read tag from DOUTR */ ReadBlock(base, tagBuf); @@ -896,12 +936,11 @@ whal_Error whal_Stm32wbAes_AesCcm(whal_Crypto *cryptoDev, void *opArgs) for (i = 0; i < args->tagSz; i++) args->tag[i] = tagBuf[i]; - whal_Reg_Update(base, AES_CR_REG, AES_CR_CCFC_Msk, AES_CR_CCFC_Msk); - +cleanup: /* Disable AES */ whal_Reg_Update(base, AES_CR_REG, AES_CR_EN_Msk, 0); - return WHAL_SUCCESS; + return err; } const whal_CryptoDriver whal_Stm32wbAes_Driver = { diff --git a/src/flash/pic32cz_flash.c b/src/flash/pic32cz_flash.c index 23217cc..d975120 100644 --- a/src/flash/pic32cz_flash.c +++ b/src/flash/pic32cz_flash.c @@ -4,6 +4,7 @@ #include #include #include +#include /* * PIC32CZ FCW (Flash Controller Write) Register Definitions @@ -93,16 +94,20 @@ #define FCW_DWORD_SIZE 8 #define FCW_QDWORD_SIZE 32 -static void whal_Pic32czFlash_MutexLock(const whal_Regmap *reg) +static whal_Error whal_Pic32czFlash_MutexLock(const whal_Regmap *reg, + whal_Timeout *timeout) { - size_t locked = 1; - while (locked) { - whal_Reg_Get(reg->base, FCW_MUTEX_REG, FCW_MUTEX_LOCK_Msk, FCW_MUTEX_LOCK_Pos, &locked); + WHAL_TIMEOUT_START(timeout); + while (whal_Reg_Read(reg->base, FCW_MUTEX_REG) & FCW_MUTEX_LOCK_Msk) { + if (WHAL_TIMEOUT_EXPIRED(timeout)) + return WHAL_ETIMEOUT; } whal_Reg_Update(reg->base, FCW_MUTEX_REG, FCW_MUTEX_LOCK_Msk | FCW_MUTEX_OWNER_Msk, whal_SetBits(FCW_MUTEX_LOCK_Msk, FCW_MUTEX_LOCK_Pos, 1) | whal_SetBits(FCW_MUTEX_OWNER_Msk, FCW_MUTEX_OWNER_Pos, 1)); + + return WHAL_SUCCESS; } static void whal_Pic32czFlash_MutexUnlock(const whal_Regmap *reg) @@ -112,20 +117,26 @@ static void whal_Pic32czFlash_MutexUnlock(const whal_Regmap *reg) whal_SetBits(FCW_MUTEX_OWNER_Msk, FCW_MUTEX_OWNER_Pos, 1)); } -static void whal_Pic32czFlash_WaitBusy(const whal_Regmap *reg) +static whal_Error whal_Pic32czFlash_WaitBusy(const whal_Regmap *reg, + whal_Timeout *timeout) { - size_t busy = 1; - while (busy) { - whal_Reg_Get(reg->base, FCW_STATUS_REG, FCW_STATUS_BUSY_Msk, FCW_STATUS_BUSY_Pos, &busy); + WHAL_TIMEOUT_START(timeout); + while (whal_Reg_Read(reg->base, FCW_STATUS_REG) & FCW_STATUS_BUSY_Msk) { + if (WHAL_TIMEOUT_EXPIRED(timeout)) + return WHAL_ETIMEOUT; } + + return WHAL_SUCCESS; } /* * 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) +static whal_Error whal_Pic32czFlash_ExecCmd(const whal_Regmap *reg, size_t cmd, + whal_Timeout *timeout) { + whal_Error err; size_t errFlags; /* Write unlock key */ @@ -137,7 +148,9 @@ static whal_Error whal_Pic32czFlash_ExecCmd(const whal_Regmap *reg, size_t cmd) whal_SetBits(FCW_CTRLA_NVMOP_Msk, FCW_CTRLA_NVMOP_Pos, cmd) | FCW_CTRLA_PREPG_Msk); /* Wait for completion */ - whal_Pic32czFlash_WaitBusy(reg); + err = whal_Pic32czFlash_WaitBusy(reg, timeout); + if (err) + return err; /* Check for errors */ whal_Reg_Get(reg->base, FCW_INTFLAG_REG, FCW_INTFLAG_ALL_ERR, 0, &errFlags); @@ -233,7 +246,9 @@ whal_Error whal_Pic32czFlash_Read(whal_Flash *flashDev, size_t addr, uint8_t *da size_t dataSz) { const whal_Regmap *reg; + whal_Pic32czFlash_Cfg *cfg = flashDev->cfg; uint8_t *flashAddr = (uint8_t *)addr; + whal_Error err; size_t i; if (!flashDev || !data) { @@ -242,7 +257,10 @@ whal_Error whal_Pic32czFlash_Read(whal_Flash *flashDev, size_t addr, uint8_t *da reg = &flashDev->regmap; - whal_Pic32czFlash_MutexLock(reg); + + err = whal_Pic32czFlash_MutexLock(reg, cfg->timeout); + if (err) + return err; /* Flash is memory-mapped; read directly */ for (i = 0; i < dataSz; i++) { @@ -258,6 +276,7 @@ whal_Error whal_Pic32czFlash_Write(whal_Flash *flashDev, size_t addr, const uint size_t dataSz) { const whal_Regmap *reg; + whal_Pic32czFlash_Cfg *cfg = flashDev->cfg; const uint32_t *src; whal_Error err; size_t offset = 0; @@ -274,13 +293,20 @@ whal_Error whal_Pic32czFlash_Write(whal_Flash *flashDev, size_t addr, const uint reg = &flashDev->regmap; src = (const uint32_t *)data; - whal_Pic32czFlash_MutexLock(reg); + + err = whal_Pic32czFlash_MutexLock(reg, cfg->timeout); + if (err) + return err; while (offset < dataSz) { size_t curAddr = addr + offset; size_t remaining = dataSz - offset; - whal_Pic32czFlash_WaitBusy(reg); + err = whal_Pic32czFlash_WaitBusy(reg, cfg->timeout); + if (err) { + whal_Pic32czFlash_MutexUnlock(reg); + return err; + } if (!(curAddr & 0x1F) && remaining >= FCW_QDWORD_SIZE) { /* Quad double word write (32 bytes) */ @@ -292,7 +318,8 @@ whal_Error whal_Pic32czFlash_Write(whal_Flash *flashDev, size_t addr, const uint whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, curAddr); err = whal_Pic32czFlash_ExecCmd(reg, - FCW_CTRLA_NVMOP_QUAD_DWORD); + FCW_CTRLA_NVMOP_QUAD_DWORD, + cfg->timeout); if (err) { whal_Pic32czFlash_MutexUnlock(reg); return err; @@ -307,7 +334,8 @@ whal_Error whal_Pic32czFlash_Write(whal_Flash *flashDev, size_t addr, const uint whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, curAddr); err = whal_Pic32czFlash_ExecCmd(reg, - FCW_CTRLA_NVMOP_SINGLE_DWORD); + FCW_CTRLA_NVMOP_SINGLE_DWORD, + cfg->timeout); if (err) { whal_Pic32czFlash_MutexUnlock(reg); return err; @@ -325,6 +353,7 @@ whal_Error whal_Pic32czFlash_Write(whal_Flash *flashDev, size_t addr, const uint whal_Error whal_Pic32czFlash_Erase(whal_Flash *flashDev, size_t addr, size_t dataSz) { const whal_Regmap *reg; + whal_Pic32czFlash_Cfg *cfg = flashDev->cfg; whal_Error err; size_t pageAddr; size_t endAddr; @@ -339,14 +368,22 @@ whal_Error whal_Pic32czFlash_Erase(whal_Flash *flashDev, size_t addr, size_t dat pageAddr = addr & ~(FCW_PAGE_SIZE - 1); endAddr = addr + dataSz; - whal_Pic32czFlash_MutexLock(reg); + + err = whal_Pic32czFlash_MutexLock(reg, cfg->timeout); + if (err) + return err; while (pageAddr < endAddr) { - whal_Pic32czFlash_WaitBusy(reg); + err = whal_Pic32czFlash_WaitBusy(reg, cfg->timeout); + if (err) { + whal_Pic32czFlash_MutexUnlock(reg); + return err; + } whal_Reg_Update(reg->base, FCW_ADDR_REG, 0xFFFFFFFF, pageAddr); - err = whal_Pic32czFlash_ExecCmd(reg, FCW_CTRLA_NVMOP_PAGE_ERASE); + err = whal_Pic32czFlash_ExecCmd(reg, FCW_CTRLA_NVMOP_PAGE_ERASE, + cfg->timeout); if (err) { whal_Pic32czFlash_MutexUnlock(reg); return err; diff --git a/src/flash/stm32wb_flash.c b/src/flash/stm32wb_flash.c index f1ecf15..b2ee071 100644 --- a/src/flash/stm32wb_flash.c +++ b/src/flash/stm32wb_flash.c @@ -5,6 +5,7 @@ #include #include #include +#include /* * STM32WB Flash Register Definitions @@ -172,7 +173,6 @@ static whal_Error whal_Stm32wbFlash_WriteOrErase(whal_Flash *flashDev, size_t ad const whal_Regmap *regmap = &flashDev->regmap; size_t bsy; size_t pesd; - size_t cfgbsy = 0; /* Validate address alignment and bounds */ if (addr & 0xf || addr < cfg->startAddr || addr + dataSz > cfg->startAddr + cfg->size) { @@ -190,6 +190,8 @@ static whal_Error whal_Stm32wbFlash_WriteOrErase(whal_Flash *flashDev, size_t ad /* Clear all error flags by writing 1 to each */ whal_Reg_Update(regmap->base, FLASH_SR_REG, FLASH_SR_ALL_ERR, 0xffffffff); + whal_Error err = WHAL_SUCCESS; + if (write) { /* Enable flash programming mode */ whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PG_Msk, 1); @@ -204,9 +206,10 @@ static whal_Error whal_Stm32wbFlash_WriteOrErase(whal_Flash *flashDev, size_t ad flashAddr[1] = dataAddr[1]; /* Wait for programming to complete */ - do { - whal_Reg_Get(regmap->base, FLASH_SR_REG, FLASH_SR_CFGBSY_Msk, FLASH_SR_CFGBSY_Pos, &cfgbsy); - } while (cfgbsy); + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, + FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); + if (err) + goto cleanup; } } else { @@ -230,9 +233,10 @@ static whal_Error whal_Stm32wbFlash_WriteOrErase(whal_Flash *flashDev, size_t ad whal_SetBits(FLASH_CR_STRT_Msk, FLASH_CR_STRT_Pos, 1)); /* Wait for erase to complete */ - do { - whal_Reg_Get(regmap->base, FLASH_SR_REG, FLASH_SR_CFGBSY_Msk, FLASH_SR_CFGBSY_Pos, &cfgbsy); - } while (cfgbsy); + err = whal_Reg_ReadPoll(regmap->base, FLASH_SR_REG, + FLASH_SR_CFGBSY_Msk, 0, cfg->timeout); + if (err) + goto cleanup; } /* Disable page erase mode */ @@ -240,10 +244,11 @@ static whal_Error whal_Stm32wbFlash_WriteOrErase(whal_Flash *flashDev, size_t ad whal_SetBits(FLASH_CR_PER_Msk, FLASH_CR_PER_Pos, 0)); } +cleanup: /* Disable flash programming mode */ whal_Reg_Update(regmap->base, FLASH_CR_REG, FLASH_CR_PG_Msk, 0); - return WHAL_SUCCESS; + return err; } whal_Error whal_Stm32wbFlash_Write(whal_Flash *flashDev, size_t addr, const uint8_t *data, diff --git a/src/rng/stm32wb_rng.c b/src/rng/stm32wb_rng.c index a595324..685cf6d 100644 --- a/src/rng/stm32wb_rng.c +++ b/src/rng/stm32wb_rng.c @@ -81,14 +81,19 @@ whal_Error whal_Stm32wbRng_Deinit(whal_Rng *rngDev) whal_Error whal_Stm32wbRng_Generate(whal_Rng *rngDev, uint8_t *rngData, size_t rngDataSz) { - if (!rngDev || !rngData) { - return WHAL_EINVAL; - } whal_Error err = WHAL_SUCCESS; + whal_Stm32wbRng_Cfg *cfg = (whal_Stm32wbRng_Cfg *)rngDev->cfg; const whal_Regmap *reg = &rngDev->regmap; - size_t status; + size_t sr; size_t offset = 0; +#ifdef WHAL_CFG_NO_TIMEOUT + (void)(cfg); +#endif + + if (!rngDev || !rngData) { + return WHAL_EINVAL; + } /* Enable the RNG peripheral */ whal_Reg_Update(reg->base, RNG_CR_REG, RNG_CR_RNGEN_Msk, @@ -96,21 +101,28 @@ whal_Error whal_Stm32wbRng_Generate(whal_Rng *rngDev, uint8_t *rngData, size_t r while (offset < rngDataSz) { /* Wait for a random value to be ready */ - do { + WHAL_TIMEOUT_START(cfg->timeout); + while (1) { + if (WHAL_TIMEOUT_EXPIRED(cfg->timeout)) { + err = WHAL_ETIMEOUT; + goto exit; + } + + sr = whal_Reg_Read(reg->base, RNG_SR_REG); + /* Check for seed or clock error */ - whal_Reg_Get(reg->base, RNG_SR_REG, RNG_SR_SECS_Msk, RNG_SR_SECS_Pos, &status); - if (status) { + if (sr & RNG_SR_SECS_Msk) { err = WHAL_EHARDWARE; goto exit; } - whal_Reg_Get(reg->base, RNG_SR_REG, RNG_SR_CECS_Msk, RNG_SR_CECS_Pos, &status); - if (status) { + if (sr & RNG_SR_CECS_Msk) { err = WHAL_EHARDWARE; goto exit; } - whal_Reg_Get(reg->base, RNG_SR_REG, RNG_SR_DRDY_Msk, RNG_SR_DRDY_Pos, &status); - } while (!status); + if (sr & RNG_SR_DRDY_Msk) + break; + } /* Read 32-bit random value */ uint32_t rnd = *(volatile uint32_t *)(reg->base + RNG_DR_REG); diff --git a/src/spi/stm32wb_spi.c b/src/spi/stm32wb_spi.c index 1066933..779cbd0 100644 --- a/src/spi/stm32wb_spi.c +++ b/src/spi/stm32wb_spi.c @@ -197,7 +197,6 @@ whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uin cfg = (whal_Stm32wbSpi_Cfg *)spiDev->cfg; comCfg = (whal_Stm32wbSpi_ComCfg *)spiComCfg; size_t totalLen = txLen > rxLen ? txLen : rxLen; - size_t status; size_t d; whal_Stm32wbSpi_ApplyComCfg(reg, cfg, comCfg); @@ -205,9 +204,12 @@ whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uin for (size_t i = 0; i < totalLen; i++) { if (txLen && tx) { /* Wait for TX buffer empty */ - do { - whal_Reg_Get(reg->base, SPI_SR_REG, SPI_SR_TXE_Msk, SPI_SR_TXE_Pos, &status); - } while (!status); + whal_Error txErr = whal_Reg_ReadPoll(reg->base, SPI_SR_REG, + SPI_SR_TXE_Msk, + SPI_SR_TXE_Msk, + cfg->timeout); + if (txErr) + return txErr; /* Write data or dummy byte */ uint8_t txByte = (i >= txLen) ? tx[txLen-1] : tx[i]; @@ -216,9 +218,12 @@ whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uin if (rxLen && rx) { /* Wait for RX buffer not empty */ - do { - whal_Reg_Get(reg->base, SPI_SR_REG, SPI_SR_RXNE_Msk, SPI_SR_RXNE_Pos, &status); - } while (!status); + whal_Error rxErr = whal_Reg_ReadPoll(reg->base, SPI_SR_REG, + SPI_SR_RXNE_Msk, + SPI_SR_RXNE_Msk, + cfg->timeout); + if (rxErr) + return rxErr; /* Read received byte */ d = *(volatile uint8_t *)(reg->base + SPI_DR_REG); @@ -229,11 +234,8 @@ whal_Error whal_Stm32wbSpi_SendRecv(whal_Spi *spiDev, void *spiComCfg, const uin } /* Wait for not busy */ - do { - whal_Reg_Get(reg->base, SPI_SR_REG, SPI_SR_BSY_Msk, SPI_SR_BSY_Pos, &status); - } while (status); - - return WHAL_SUCCESS; + return whal_Reg_ReadPoll(reg->base, SPI_SR_REG, SPI_SR_BSY_Msk, 0, + cfg->timeout); } whal_Error whal_Stm32wbSpi_Send(whal_Spi *spiDev, void *spiComCfg, const uint8_t *data, diff --git a/src/uart/pic32cz_uart.c b/src/uart/pic32cz_uart.c index 2df420e..8b398e0 100644 --- a/src/uart/pic32cz_uart.c +++ b/src/uart/pic32cz_uart.c @@ -160,14 +160,6 @@ #define USART_DATA_Pos 0 #define USART_DATA_Msk (WHAL_BITMASK(9) << USART_DATA_Pos) -static void whal_Pic32czUart_WaitSync(const whal_Regmap *reg, size_t mask, size_t pos) -{ - size_t busy = 1; - while (busy) { - whal_Reg_Get(reg->base, USART_SYNCBUSY_REG, mask, pos, &busy); - } -} - whal_Error whal_Pic32czUart_Init(whal_Uart *uartDev) { whal_Error err; @@ -214,7 +206,10 @@ whal_Error whal_Pic32czUart_Init(whal_Uart *uartDev) whal_SetBits(USART_CTRLB_PMODE_Msk, USART_CTRLB_PMODE_Pos, 0)); /* Wait for CTRLB sync */ - whal_Pic32czUart_WaitSync(reg, USART_SYNCBUSY_CTRLB_Msk, USART_SYNCBUSY_CTRLB_Pos); + err = whal_Reg_ReadPoll(reg->base, USART_SYNCBUSY_REG, + USART_SYNCBUSY_CTRLB_Msk, 0, cfg->timeout); + if (err != WHAL_SUCCESS) + return err; /* Set baud rate */ whal_Reg_Update(reg->base, USART_BAUD_REG, @@ -228,7 +223,10 @@ whal_Error whal_Pic32czUart_Init(whal_Uart *uartDev) whal_SetBits(USART_CTRLB_RXEN_Msk, USART_CTRLB_RXEN_Pos, 1)); /* Wait for CTRLB sync */ - whal_Pic32czUart_WaitSync(reg, USART_SYNCBUSY_CTRLB_Msk, USART_SYNCBUSY_CTRLB_Pos); + err = whal_Reg_ReadPoll(reg->base, USART_SYNCBUSY_REG, + USART_SYNCBUSY_CTRLB_Msk, 0, cfg->timeout); + if (err != WHAL_SUCCESS) + return err; /* Enable SERCOM USART */ whal_Reg_Update(reg->base, USART_CTRLA_REG, @@ -236,7 +234,10 @@ whal_Error whal_Pic32czUart_Init(whal_Uart *uartDev) whal_SetBits(USART_CTRLA_ENABLE_Msk, USART_CTRLA_ENABLE_Pos, 1)); /* Wait for enable sync */ - whal_Pic32czUart_WaitSync(reg, USART_SYNCBUSY_ENABLE_Msk, USART_SYNCBUSY_ENABLE_Pos); + err = whal_Reg_ReadPoll(reg->base, USART_SYNCBUSY_REG, + USART_SYNCBUSY_ENABLE_Msk, 0, cfg->timeout); + if (err != WHAL_SUCCESS) + return err; return WHAL_SUCCESS; } @@ -260,7 +261,10 @@ whal_Error whal_Pic32czUart_Deinit(whal_Uart *uartDev) whal_SetBits(USART_CTRLA_ENABLE_Msk, USART_CTRLA_ENABLE_Pos, 0)); /* Wait for disable sync */ - whal_Pic32czUart_WaitSync(reg, USART_SYNCBUSY_ENABLE_Msk, USART_SYNCBUSY_ENABLE_Pos); + err = whal_Reg_ReadPoll(reg->base, USART_SYNCBUSY_REG, + USART_SYNCBUSY_ENABLE_Msk, 0, cfg->timeout); + if (err != WHAL_SUCCESS) + return err; /* Disable transmitter and receiver */ whal_Reg_Update(reg->base, USART_CTRLB_REG, @@ -269,7 +273,10 @@ whal_Error whal_Pic32czUart_Deinit(whal_Uart *uartDev) whal_SetBits(USART_CTRLB_RXEN_Msk, USART_CTRLB_RXEN_Pos, 0)); /* Wait for CTRLB sync */ - whal_Pic32czUart_WaitSync(reg, USART_SYNCBUSY_CTRLB_Msk, USART_SYNCBUSY_CTRLB_Pos); + err = whal_Reg_ReadPoll(reg->base, USART_SYNCBUSY_REG, + USART_SYNCBUSY_CTRLB_Msk, 0, cfg->timeout); + if (err != WHAL_SUCCESS) + return err; /* Disable peripheral clock */ err = whal_Clock_Disable(cfg->clkCtrl, cfg->clk); @@ -283,22 +290,24 @@ whal_Error whal_Pic32czUart_Deinit(whal_Uart *uartDev) whal_Error whal_Pic32czUart_Send(whal_Uart *uartDev, const void *data, size_t dataSz) { const whal_Regmap *reg; + whal_Pic32czUart_Cfg *cfg; const uint8_t *buf = data; + whal_Error err; if (!uartDev || !data) { return WHAL_EINVAL; } reg = &uartDev->regmap; + cfg = (whal_Pic32czUart_Cfg *)uartDev->cfg; for (size_t i = 0; i < dataSz; ++i) { - size_t dataRegEmpty = 0; - /* Wait for data register to be empty */ - while (!dataRegEmpty) { - whal_Reg_Get(reg->base, USART_INTFLAG_REG, - USART_INTFLAG_DRE_Msk, USART_INTFLAG_DRE_Pos, &dataRegEmpty); - } + err = whal_Reg_ReadPoll(reg->base, USART_INTFLAG_REG, + USART_INTFLAG_DRE_Msk, USART_INTFLAG_DRE_Msk, + cfg->timeout); + if (err) + return err; /* Write data to transmit register */ whal_Reg_Update(reg->base, USART_DATA_REG, @@ -307,17 +316,16 @@ whal_Error whal_Pic32czUart_Send(whal_Uart *uartDev, const void *data, size_t da } /* Wait for transmission complete */ - { - size_t txComplete = 0; - while (!txComplete) { - whal_Reg_Get(reg->base, USART_INTFLAG_REG, - USART_INTFLAG_TXC_Msk, USART_INTFLAG_TXC_Pos, &txComplete); - } - /* Clear TXC flag by writing 1 */ - whal_Reg_Update(reg->base, USART_INTFLAG_REG, - USART_INTFLAG_TXC_Msk, - whal_SetBits(USART_INTFLAG_TXC_Msk, USART_INTFLAG_TXC_Pos, 1)); - } + err = whal_Reg_ReadPoll(reg->base, USART_INTFLAG_REG, + USART_INTFLAG_TXC_Msk, USART_INTFLAG_TXC_Msk, + cfg->timeout); + if (err) + return err; + + /* Clear TXC flag by writing 1 */ + whal_Reg_Update(reg->base, USART_INTFLAG_REG, + USART_INTFLAG_TXC_Msk, + whal_SetBits(USART_INTFLAG_TXC_Msk, USART_INTFLAG_TXC_Pos, 1)); return WHAL_SUCCESS; } @@ -325,6 +333,7 @@ whal_Error whal_Pic32czUart_Send(whal_Uart *uartDev, const void *data, size_t da whal_Error whal_Pic32czUart_Recv(whal_Uart *uartDev, void *data, size_t dataSz) { const whal_Regmap *reg; + whal_Pic32czUart_Cfg *cfg; uint8_t *buf = data; if (!uartDev || !data) { @@ -332,16 +341,18 @@ whal_Error whal_Pic32czUart_Recv(whal_Uart *uartDev, void *data, size_t dataSz) } reg = &uartDev->regmap; + cfg = (whal_Pic32czUart_Cfg *)uartDev->cfg; for (size_t i = 0; i < dataSz; ++i) { - size_t dataReceived = 0; size_t rxData; + whal_Error err; /* Wait for receive complete */ - while (!dataReceived) { - whal_Reg_Get(reg->base, USART_INTFLAG_REG, - USART_INTFLAG_RXC_Msk, USART_INTFLAG_RXC_Pos, &dataReceived); - } + err = whal_Reg_ReadPoll(reg->base, USART_INTFLAG_REG, + USART_INTFLAG_RXC_Msk, USART_INTFLAG_RXC_Msk, + cfg->timeout); + if (err) + return err; /* Read received data */ whal_Reg_Get(reg->base, USART_DATA_REG, diff --git a/src/uart/stm32wb_uart.c b/src/uart/stm32wb_uart.c index 43476ea..16bfc2e 100644 --- a/src/uart/stm32wb_uart.c +++ b/src/uart/stm32wb_uart.c @@ -5,6 +5,7 @@ #include #include #include +#include #define UART_CR1_REG 0x00 #define UART_CR1_UE_Pos 0 @@ -133,17 +134,18 @@ whal_Error whal_Stm32wbUart_Deinit(whal_Uart *uartDev) whal_Error whal_Stm32wbUart_Send(whal_Uart *uartDev, const void *data, size_t dataSz) { const whal_Regmap *reg = &uartDev->regmap; + whal_Stm32wbUart_Cfg *cfg = (whal_Stm32wbUart_Cfg *)uartDev->cfg; const uint8_t *buf = data; for (size_t i = 0; i < dataSz; ++i) { - size_t txComplete = 0; - + whal_Error err; whal_Reg_Update(reg->base, UART_TDR_REG, UART_TDR_Msk, whal_SetBits(UART_TDR_Msk, UART_TDR_Pos, buf[i])); - while (!txComplete) { - whal_Reg_Get(reg->base, UART_ISR_REG, UART_ISR_TC_Msk, UART_ISR_TC_Pos, &txComplete); - } + err = whal_Reg_ReadPoll(reg->base, UART_ISR_REG, UART_ISR_TC_Msk, + UART_ISR_TC_Msk, cfg->timeout); + if (err) + return err; } return WHAL_SUCCESS; @@ -152,15 +154,16 @@ whal_Error whal_Stm32wbUart_Send(whal_Uart *uartDev, const void *data, size_t da whal_Error whal_Stm32wbUart_Recv(whal_Uart *uartDev, void *data, size_t dataSz) { const whal_Regmap *reg = &uartDev->regmap; + whal_Stm32wbUart_Cfg *cfg = (whal_Stm32wbUart_Cfg *)uartDev->cfg; uint8_t *buf = data; size_t d; for (size_t i = 0; i < dataSz; ++i) { - size_t dataReceived = 0; - - while (!dataReceived) { - whal_Reg_Get(reg->base, UART_ISR_REG, UART_ISR_RXFNE_Msk, UART_ISR_RXFNE_Pos, &dataReceived); - } + whal_Error err = whal_Reg_ReadPoll(reg->base, UART_ISR_REG, + UART_ISR_RXFNE_Msk, + UART_ISR_RXFNE_Msk, cfg->timeout); + if (err) + return err; whal_Reg_Get(reg->base, UART_RDR_REG, UART_RDR_Msk, UART_RDR_Pos, &d); diff --git a/tests/core/Makefile b/tests/core/Makefile index 2e32fee..a0be45d 100644 --- a/tests/core/Makefile +++ b/tests/core/Makefile @@ -1,9 +1,9 @@ WHAL_DIR = $(CURDIR)/../.. INCLUDE = -I$(WHAL_DIR) -CFLAGS = -Wall -Werror $(INCLUDE) -g3 +CFLAGS += -Wall -Werror $(INCLUDE) -g3 -TEST_SRC = main.c test_bitops.c test_dispatch.c test_endian.c +TEST_SRC = main.c test_bitops.c test_dispatch.c test_endian.c test_timeout.c WHAL_SRC = $(WHAL_DIR)/src/clock/clock.c \ $(WHAL_DIR)/src/gpio/gpio.c \ diff --git a/tests/core/main.c b/tests/core/main.c index 71ac87c..d067871 100644 --- a/tests/core/main.c +++ b/tests/core/main.c @@ -15,6 +15,9 @@ void whal_Test_Puts(const char *s) void whal_Test_Bitops(void); void whal_Test_Dispatch(void); void whal_Test_Endian(void); +#ifndef WHAL_CFG_NO_TIMEOUT +void whal_Test_Timeout(void); +#endif int main(void) { @@ -25,6 +28,9 @@ int main(void) whal_Test_Bitops(); whal_Test_Dispatch(); whal_Test_Endian(); +#ifndef WHAL_CFG_NO_TIMEOUT + whal_Test_Timeout(); +#endif WHAL_TEST_SUMMARY(); diff --git a/tests/core/test_timeout.c b/tests/core/test_timeout.c new file mode 100644 index 0000000..8275abf --- /dev/null +++ b/tests/core/test_timeout.c @@ -0,0 +1,141 @@ +#include +#include "../test.h" + +#ifndef WHAL_CFG_NO_TIMEOUT + +static uint32_t g_fakeTick; + +static uint32_t FakeTick(void) +{ + return g_fakeTick; +} + +static whal_Timeout g_timeout = { + .timeoutTicks = 10, + .GetTick = FakeTick, +}; + +/* Helper: get a pointer to g_timeout (avoids -Waddress on &global) */ +static whal_Timeout *timeout(void) +{ + return &g_timeout; +} + +/* WHAL_TIMEOUT_EXPIRED returns 0 when NULL */ +static void Test_Timeout_NullNotExpired(void) +{ + whal_Timeout *t = NULL; + int expired = WHAL_TIMEOUT_EXPIRED(t); + WHAL_ASSERT_EQ(expired, 0); +} + +/* START snapshots current tick */ +static void Test_Timeout_StartSnapshotsTick(void) +{ + g_fakeTick = 42; + WHAL_TIMEOUT_START(timeout()); + WHAL_ASSERT_EQ(g_timeout.startTick, 42); +} + +/* Not expired immediately after start */ +static void Test_Timeout_NotExpiredImmediately(void) +{ + g_fakeTick = 0; + WHAL_TIMEOUT_START(timeout()); + int expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_EQ(expired, 0); +} + +/* Not expired one tick before deadline */ +static void Test_Timeout_NotExpiredBeforeDeadline(void) +{ + g_fakeTick = 0; + WHAL_TIMEOUT_START(timeout()); + g_fakeTick = 9; + int expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_EQ(expired, 0); +} + +/* Expired exactly at deadline */ +static void Test_Timeout_ExpiredAtDeadline(void) +{ + g_fakeTick = 0; + WHAL_TIMEOUT_START(timeout()); + g_fakeTick = 10; + int expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_NEQ(expired, 0); +} + +/* Expired well past deadline */ +static void Test_Timeout_ExpiredPastDeadline(void) +{ + g_fakeTick = 0; + WHAL_TIMEOUT_START(timeout()); + g_fakeTick = 100; + int expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_NEQ(expired, 0); +} + +/* START resets the window */ +static void Test_Timeout_StartResetsWindow(void) +{ + int expired; + + g_fakeTick = 0; + WHAL_TIMEOUT_START(timeout()); + g_fakeTick = 10; + expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_NEQ(expired, 0); + + /* Restart — should no longer be expired */ + WHAL_TIMEOUT_START(timeout()); + expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_EQ(expired, 0); +} + +/* Non-zero start tick works correctly */ +static void Test_Timeout_NonZeroStart(void) +{ + int expired; + + g_fakeTick = 1000; + WHAL_TIMEOUT_START(timeout()); + g_fakeTick = 1005; + expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_EQ(expired, 0); + g_fakeTick = 1010; + expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_NEQ(expired, 0); +} + +/* Tick counter wrapping (unsigned subtraction handles this) */ +static void Test_Timeout_TickWrap(void) +{ + int expired; + + g_fakeTick = UINT32_MAX - 3; + WHAL_TIMEOUT_START(timeout()); + g_fakeTick = UINT32_MAX; + expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_EQ(expired, 0); + g_fakeTick = UINT32_MAX - 3 + 10; + expired = WHAL_TIMEOUT_EXPIRED(timeout()); + WHAL_ASSERT_NEQ(expired, 0); +} + +void whal_Test_Timeout(void) +{ + WHAL_TEST_SUITE_START("timeout"); + WHAL_TEST(Test_Timeout_NullNotExpired); + WHAL_TEST(Test_Timeout_StartSnapshotsTick); + WHAL_TEST(Test_Timeout_NotExpiredImmediately); + WHAL_TEST(Test_Timeout_NotExpiredBeforeDeadline); + WHAL_TEST(Test_Timeout_ExpiredAtDeadline); + WHAL_TEST(Test_Timeout_ExpiredPastDeadline); + WHAL_TEST(Test_Timeout_StartResetsWindow); + WHAL_TEST(Test_Timeout_NonZeroStart); + WHAL_TEST(Test_Timeout_TickWrap); + WHAL_TEST_SUITE_END(); +} + +#endif /* !WHAL_CFG_NO_TIMEOUT */ diff --git a/wolfHAL/crypto/stm32wb_aes.h b/wolfHAL/crypto/stm32wb_aes.h index 57cbbc2..37da851 100644 --- a/wolfHAL/crypto/stm32wb_aes.h +++ b/wolfHAL/crypto/stm32wb_aes.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * @file stm32wb_aes.h @@ -20,7 +21,7 @@ typedef struct { whal_Clock *clkCtrl; const void *clk; - + whal_Timeout *timeout; } whal_Stm32wbAes_Cfg; /* diff --git a/wolfHAL/error.h b/wolfHAL/error.h index 52c5c52..c55a31c 100644 --- a/wolfHAL/error.h +++ b/wolfHAL/error.h @@ -18,6 +18,8 @@ enum { WHAL_ENOTREADY = -4001, /* Hardware device error. */ WHAL_EHARDWARE = -4002, + /* Operation timed out. */ + WHAL_ETIMEOUT = -4003, }; #endif /* WHAL_ERROR_H */ diff --git a/wolfHAL/flash/pic32cz_flash.h b/wolfHAL/flash/pic32cz_flash.h index f22c1fa..00679c3 100644 --- a/wolfHAL/flash/pic32cz_flash.h +++ b/wolfHAL/flash/pic32cz_flash.h @@ -3,6 +3,7 @@ #include #include +#include /* * @file pic32cz_flash.h @@ -29,6 +30,7 @@ typedef struct whal_Pic32czFlash_Cfg { size_t startAddr; size_t size; + whal_Timeout *timeout; } whal_Pic32czFlash_Cfg; /* diff --git a/wolfHAL/flash/stm32wb_flash.h b/wolfHAL/flash/stm32wb_flash.h index ed49830..e5e2d0b 100644 --- a/wolfHAL/flash/stm32wb_flash.h +++ b/wolfHAL/flash/stm32wb_flash.h @@ -3,6 +3,7 @@ #include #include +#include /* * @file stm32wb_flash.h @@ -28,6 +29,7 @@ typedef struct whal_Stm32wbFlash_Cfg { const void *clk; /* Clock descriptor */ size_t startAddr; /* Flash base address (typically 0x08000000) */ size_t size; /* Flash size in bytes */ + whal_Timeout *timeout; } whal_Stm32wbFlash_Cfg; /* diff --git a/wolfHAL/regmap.h b/wolfHAL/regmap.h index c04b4a3..e53a0a4 100644 --- a/wolfHAL/regmap.h +++ b/wolfHAL/regmap.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * @file regmap.h @@ -81,4 +82,28 @@ static inline size_t whal_Reg_Read(size_t base, size_t offset) return *(volatile size_t *)(base + offset); } +/* + * @brief Poll a register until (reg & mask) == value, or timeout. + * + * @param base Register block base address. + * @param offset Register offset. + * @param mask Bit mask to extract the field. + * @param value Expected value of the masked field. + * @param timeout Timeout instance (NULL for unbounded wait). + */ +static inline whal_Error whal_Reg_ReadPoll(size_t base, size_t offset, + size_t mask, size_t value, + whal_Timeout *timeout) +{ +#ifdef WHAL_CFG_NO_TIMEOUT + (void)(timeout); +#endif + WHAL_TIMEOUT_START(timeout); + while ((whal_Reg_Read(base, offset) & mask) != value) { + if (WHAL_TIMEOUT_EXPIRED(timeout)) + return WHAL_ETIMEOUT; + } + return WHAL_SUCCESS; +} + #endif /* WHAL_REGMAP_H */ diff --git a/wolfHAL/rng/stm32wb_rng.h b/wolfHAL/rng/stm32wb_rng.h index 7c47284..305e5f4 100644 --- a/wolfHAL/rng/stm32wb_rng.h +++ b/wolfHAL/rng/stm32wb_rng.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * @file stm32wb_rng.h @@ -20,6 +21,7 @@ typedef struct whal_Stm32wbRng_Cfg { whal_Clock *clkCtrl; /* Clock controller for RNG peripheral clock */ const void *clk; /* Clock descriptor */ + whal_Timeout *timeout; } whal_Stm32wbRng_Cfg; /* diff --git a/wolfHAL/spi/stm32wb_spi.h b/wolfHAL/spi/stm32wb_spi.h index 5c70936..4415409 100644 --- a/wolfHAL/spi/stm32wb_spi.h +++ b/wolfHAL/spi/stm32wb_spi.h @@ -5,6 +5,7 @@ #include #include #include +#include /* * @file stm32wb_spi.h @@ -35,6 +36,7 @@ typedef enum { typedef struct whal_Stm32wbSpi_Cfg { whal_Clock *clkCtrl; /* Clock controller for SPI peripheral clock */ const void *clk; /* Clock descriptor */ + whal_Timeout *timeout; } whal_Stm32wbSpi_Cfg; /* diff --git a/wolfHAL/timeout.h b/wolfHAL/timeout.h new file mode 100644 index 0000000..7c03c4a --- /dev/null +++ b/wolfHAL/timeout.h @@ -0,0 +1,53 @@ +#ifndef WHAL_TIMEOUT_H +#define WHAL_TIMEOUT_H + +#include +#include +#include + +/* + * @file timeout.h + * @brief Timeout abstraction for bounded polling and delays. + * + * The board sets timeoutTicks and a GetTick callback directly on a + * whal_Timeout instance. Drivers use WHAL_TIMEOUT_START / WHAL_TIMEOUT_EXPIRED + * macros for zero-overhead polling guards. When WHAL_CFG_NO_TIMEOUT is + * defined, all timeout operations compile away completely. + */ + +typedef struct { + uint32_t timeoutTicks; + uint32_t startTick; + uint32_t (*GetTick)(void); +} whal_Timeout; + +#ifdef WHAL_CFG_NO_TIMEOUT + +#define WHAL_TIMEOUT_START(t) ((void)(0)) +#define WHAL_TIMEOUT_EXPIRED(t) (0) + +#else /* !WHAL_CFG_NO_TIMEOUT */ + +/* + * @brief Snapshot the current tick. + * + * If @p t is NULL, this is a no-op so drivers can leave the timeout + * pointer unset for unbounded polling. + */ +#define WHAL_TIMEOUT_START(t) do { \ + if (t) { \ + (t)->startTick = (t)->GetTick(); \ + } \ +} while (0) + +/* + * @brief Evaluate to nonzero if the timeout has expired. + * + * Safe to call with a NULL pointer — returns 0 (not expired). + */ +#define WHAL_TIMEOUT_EXPIRED(t) \ + ((t) && ((uint32_t)((t)->GetTick() - (t)->startTick) >= (t)->timeoutTicks)) + +#endif /* WHAL_CFG_NO_TIMEOUT */ + +#endif /* WHAL_TIMEOUT_H */ diff --git a/wolfHAL/uart/pic32cz_uart.h b/wolfHAL/uart/pic32cz_uart.h index d3fae5b..ba25441 100644 --- a/wolfHAL/uart/pic32cz_uart.h +++ b/wolfHAL/uart/pic32cz_uart.h @@ -5,6 +5,7 @@ #include #include #include +#include /* * @file pic32cz_uart.h @@ -42,6 +43,7 @@ typedef struct whal_Pic32czUart_Cfg { uint32_t baud; whal_Pic32czUart_TxPad txPad; whal_Pic32czUart_RxPad rxPad; + whal_Timeout *timeout; } whal_Pic32czUart_Cfg; /* diff --git a/wolfHAL/uart/stm32wb_uart.h b/wolfHAL/uart/stm32wb_uart.h index d5b7f8a..99b94b2 100644 --- a/wolfHAL/uart/stm32wb_uart.h +++ b/wolfHAL/uart/stm32wb_uart.h @@ -4,6 +4,7 @@ #include #include #include +#include #include /* @@ -18,6 +19,7 @@ typedef struct whal_Stm32wbUart_Cfg { whal_Clock *clkCtrl; void *clk; uint32_t baud; + whal_Timeout *timeout; } whal_Stm32wbUart_Cfg; /* diff --git a/wolfHAL/wolfHAL.h b/wolfHAL/wolfHAL.h index 716a1e8..f6643f7 100644 --- a/wolfHAL/wolfHAL.h +++ b/wolfHAL/wolfHAL.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #endif /* WOLFHAL_H */