Skip to content

Add SPI driver, block device layer, and SDHC-SPI SD card driver#18

Merged
AlexLanzano merged 2 commits intowolfSSL:mainfrom
AlexLanzano:spi-flash
Mar 25, 2026
Merged

Add SPI driver, block device layer, and SDHC-SPI SD card driver#18
AlexLanzano merged 2 commits intowolfSSL:mainfrom
AlexLanzano:spi-flash

Conversation

@AlexLanzano
Copy link
Copy Markdown
Member

No description provided.

@AlexLanzano AlexLanzano self-assigned this Mar 25, 2026
Copilot AI review requested due to automatic review settings March 25, 2026 04:42
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces a generic block-device abstraction and an SDHC/SDXC-over-SPI block driver, alongside a SPI API update to support session-based configuration (StartCom/EndCom) and corresponding board/test integration.

Changes:

  • Add whal_Block / whal_BlockDriver abstraction plus dispatch layer implementation.
  • Update the SPI API to session-based configuration (StartCom/EndCom) and adapt the STM32WB SPI driver and tests.
  • Add an SD card (SDHC/SDXC) block driver over SPI plus a peripheral-board configuration and hardware tests.

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
wolfHAL/wolfHAL.h Exposes the new block layer via the umbrella header.
wolfHAL/spi/stm32wb_spi.h Updates STM32WB SPI driver API to session-based model.
wolfHAL/spi/spi.h Adds whal_Spi_ComCfg and StartCom/EndCom; removes Send/Recv.
wolfHAL/block/sdhc_spi.h Declares the SDHC/SDXC-over-SPI block driver interface.
wolfHAL/block/block.h Defines the generic block device abstraction and vtable.
src/spi/stm32wb_spi.c Implements StartCom/EndCom and updated SendRecv behavior.
src/spi/spi.c Updates SPI dispatch functions to new vtable/API.
src/block/block.c Implements block dispatch wrappers (Init/Read/Write/Erase).
src/block/sdhc_spi.c Adds SD card over SPI implementation for the block interface.
docs/writing_a_driver.md Documents the updated SPI model and new Block driver category.
docs/getting_started.md Adds block dispatch source file to the getting-started list.
boards/stm32wb55xx_nucleo/board.h Adds SPI + timeout externs and pin enum expansion.
boards/stm32wb55xx_nucleo/board.c Adds SPI init/deinit and initializes peripheral block devices.
boards/stm32wb55xx_nucleo/Makefile.inc Adds block tests, SPI/block sources, peripheral include.
boards/pic32cz_curiosity_ultra/board.c Minor clock-count naming update for consistency.
boards/pic32cz_curiosity_ultra/Makefile.inc Adds block dispatch source to board build.
boards/peripheral/peripheral.h Introduces peripheral block-device test configuration struct.
boards/peripheral/peripheral.c Defines g_peripheralBlock[] list (with sentinel).
boards/peripheral/block/sdhc_spi_sdcard32gb.h Declares a concrete SD-over-SPI block device instance.
boards/peripheral/block/sdhc_spi_sdcard32gb.c Defines the SD-over-SPI block device instance/config.
boards/peripheral/Makefile.inc Adds optional peripheral SD-over-SPI sources and define.
tests/test.h Improves assertion diagnostics (prints file:line, evaluates args once).
tests/main.c Adds optional SPI loopback + block test suite dispatch.
tests/Makefile Adds peripheral include path for tests build.
tests/core/Makefile Adds block dispatch source to core tests build.
tests/core/test_dispatch.c Adds SPI and Block dispatch tests with mock drivers.
tests/spi_loopback/test_spi_loopback.c Adds a generic hardware SPI loopback test.
tests/flash/test_flash.c Refactors flash tests to run via configured device/address.
tests/block/test_block.c Adds block-device hardware tests (read/write/erase, multiblock).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@AlexLanzano AlexLanzano removed the request for review from wolfSSL-Fenrir-bot March 25, 2026 12:53
@AlexLanzano AlexLanzano force-pushed the spi-flash branch 2 times, most recently from b6f38ca to da6025c Compare March 25, 2026 14:05
Copilot AI review requested due to automatic review settings March 25, 2026 14:05
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@AlexLanzano AlexLanzano merged commit 6d643a7 into wolfSSL:main Mar 25, 2026
9 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +167 to +175
err = SdhcSpi_CsAssert(cfg);
if (err)
goto cleanup;
err = SdhcSpi_SendCmd(cfg, CMD0, 0x00000000, 0x95);
if (!err)
err = SdhcSpi_RecvResp(cfg, &r1);
SdhcSpi_CsDeassert(cfg);
if (err)
goto cleanup;
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

SdhcSpi_CsDeassert() returns a whal_Error but its result is ignored here. If deasserting CS fails (GPIO error), initialization will proceed as if the bus is deselected, which can break subsequent command framing. Consider checking/propagating the return value (and potentially prioritizing it if no earlier error is present).

Suggested change
err = SdhcSpi_CsAssert(cfg);
if (err)
goto cleanup;
err = SdhcSpi_SendCmd(cfg, CMD0, 0x00000000, 0x95);
if (!err)
err = SdhcSpi_RecvResp(cfg, &r1);
SdhcSpi_CsDeassert(cfg);
if (err)
goto cleanup;
{
whal_Error csErr;
err = SdhcSpi_CsAssert(cfg);
if (err)
goto cleanup;
err = SdhcSpi_SendCmd(cfg, CMD0, 0x00000000, 0x95);
if (!err)
err = SdhcSpi_RecvResp(cfg, &r1);
csErr = SdhcSpi_CsDeassert(cfg);
if (!err && csErr)
err = csErr;
}
if (err)
goto cleanup;

Copilot uses AI. Check for mistakes.
Comment on lines +57 to +62
/* Fill block 0 with pattern A, block 1 with pattern B */
for (i = 0; i < g_testBlockSz; i++)
g_testBuf[i] = patternA[i % sizeof(patternA)];
for (i = 0; i < g_testBlockSz; i++)
g_testBuf[g_testBlockSz + i] = patternB[i % sizeof(patternB)];

Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The test writes/reads up to 2 blocks via g_testBuf (e.g., indexes up to g_testBlockSz2), but it never validates that the configured buffer is large enough. Since the peripheral config also provides blockBufSz, consider asserting blockBufSz >= blockSz2 (or at least >= blockSz*blockCount used by the test) before using the buffer to avoid out-of-bounds accesses when a new peripheral is added.

Copilot uses AI. Check for mistakes.
Comment on lines +131 to 138
/* DS field encodes word size as (bits - 1); valid range 4-16 */
if (comCfg->wordSz < 4 || comCfg->wordSz > 16) {
return WHAL_EINVAL;
}

if (!spiDev || !spiDev->cfg || !spiComCfg) {
if (comCfg->mode > 3 || comCfg->dataLines != 1 || comCfg->freq == 0) {
return WHAL_EINVAL;
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

whal_Stm32wbSpi_StartCom accepts word sizes 4–16 and programs DS/FRXTH accordingly, but whal_Stm32wbSpi_SendRecv always performs 8-bit DR accesses and counts in bytes. If StartCom is called with wordSz > 8 this will transfer/consume the wrong number of bits and may not properly drain RX (potentially causing overruns). Either restrict this driver to wordSz == 8 (reject others) or implement word-size-aware transfers (16-bit DR access, lengths in words, etc.).

Copilot uses AI. Check for mistakes.
if (!spiDev || !spiDev->driver || !spiDev->driver->SendRecv) {
return WHAL_EINVAL;
}

Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The SPI API contract (spi.h) requires txLen==0 when tx==NULL and rxLen==0 when rx==NULL. whal_Spi_SendRecv currently forwards parameters without enforcing this, so invalid combinations can reach platform drivers that may not validate and could misbehave. Consider adding common argument validation here (e.g., reject (!tx && txLen) and (!rx && rxLen)) to make behavior consistent across SPI drivers.

Suggested change
if ((!tx && txLen) || (!rx && rxLen)) {
return WHAL_EINVAL;
}

Copilot uses AI. Check for mistakes.
Comment on lines 118 to +126
#define WHAL_ASSERT_EQ(a, b) \
do { \
if ((a) != (b)) { \
whal_Test_Printf(" ASSERT_EQ failed at line %d\n", __LINE__); \
whal_Test_Printf(" got: %d, expected: %d\n", \
(int)(a), (int)(b)); \
g_whalTestCurFailed = 1; \
int _a = (int)(a); \
int _b = (int)(b); \
if (_a != _b) { \
whal_Test_Printf(" ASSERT_EQ failed at %s:%d\n", \
__FILE__, __LINE__); \
whal_Test_Printf(" got: %d, expected: %d\n", \
_a, _b); \
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

WHAL_ASSERT_EQ now casts both operands to int and prints them with %d. This can truncate or sign-change values (e.g., size_t/uint32_t/uintptr_t on 64-bit core tests) and can hide differences that exist only in the upper bits. Consider using a wider integral type for capture/printing (e.g., int64_t/uint64_t with corresponding format support in whal_Test_Printf) or providing separate ASSERTs for signed/unsigned/pointer-sized values.

Copilot uses AI. Check for mistakes.
Comment on lines +324 to +327
SdhcSpi_SendCmd(cfg, CMD12, 0x00000000, 0x01);
SdhcSpi_RecvResp(cfg, &r1);
whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0);
SdhcSpi_WaitReady(cfg);
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

Multi-block stop/cleanup ignores return values from CMD12/response reads, dummy clocks, and WaitReady. If any of these fail, the card can remain in a busy or multi-block state but the function may still return WHAL_SUCCESS (or only the earlier error). Consider capturing and propagating errors from these calls when err is still WHAL_SUCCESS, and ensuring the card is reliably returned to idle state before deasserting CS.

Suggested change
SdhcSpi_SendCmd(cfg, CMD12, 0x00000000, 0x01);
SdhcSpi_RecvResp(cfg, &r1);
whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0);
SdhcSpi_WaitReady(cfg);
whal_Error stopErr = WHAL_SUCCESS;
if (!err) {
stopErr = SdhcSpi_SendCmd(cfg, CMD12, 0x00000000, 0x01);
if (!stopErr)
stopErr = SdhcSpi_RecvResp(cfg, &r1);
if (!stopErr)
stopErr = whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0);
if (!stopErr)
stopErr = SdhcSpi_WaitReady(cfg);
if (!err && stopErr)
err = stopErr;
} else {
/* Best-effort attempt to stop multi-block read even after error */
(void)SdhcSpi_SendCmd(cfg, CMD12, 0x00000000, 0x01);
(void)SdhcSpi_RecvResp(cfg, &r1);
(void)whal_Spi_SendRecv(cfg->spiDev, &dummy, 1, NULL, 0);
(void)SdhcSpi_WaitReady(cfg);
}

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants