|
H753_CPP_W25Q_QSPI_Flash_Read_Write_01 1.0
STM32H753 W25Q QSPI flash (Adafruit 5632/5633/5634) read/write tutorial
|
A bare-metal (no RTOS) C++ firmware for an STM32H753ZI that drives a Winbond W25Q-series NOR flash chip (Adafruit 5632/5633/5634 QSPI DIP breakout boards – W25Q16/W25Q64/W25Q128) over the STM32's dedicated QUADSPI peripheral, with a from-scratch driver class matching the public API shape of the companion SPI project's driver.
Status: written, not yet hardware-validated. The driver code, C/C++ bridge, and demo path are complete and compile, but this project has not yet been run on real hardware – the QUADSPI clock prescaler is still CubeMX's very conservative default (255), and no validation suite run has confirmed a working clock speed the way the companion SPI project's did. Treat the current clock setting as a starting point for hardware testing, not a validated value.
After clock and peripheral init, the normal (non-validation) demo path:
A separate, opt-in destructive validation suite (W25Q_VALIDATION_TEST_ENABLE in main.c) runs instead of the demo when enabled: an erased-state check, a small read/write round trip, a 20-pattern stuck-at/bit-coupling sweep, and a page-boundary write test exercising the driver's internal page-splitting. Running this suite – not just a light JEDEC-ID spot-check – is exactly how the companion SPI project's clock speed was actually validated, and is the recommended first step once this project is on real hardware.
| Peripheral | Interface | Pins | Notes |
|---|---|---|---|
| W25Q flash (Adafruit breakout) | QUADSPI (Bank 1) | PF10 (CLK) / PF8 (IO0) / PF9 (IO1) / PE2 (IO2) / PF6 (IO3) | Single-line instruction/address/data phases in this first pass – see "Firmware architecture" below |
| Chip select | QUADSPI hardware NCS | PB10 | Hardware-managed, not a manual GPIO – see "Why chip-select is hardware NCS" below |
| Debug console | USART1 | PA9 (TX) / PA10 (RX) | 19200 baud, 8N1, via external FTDI adapter (not the onboard ST-LINK VCP) |
MCU: STM32H753ZITx (LQFP144). Cortex-M7 D-Cache is disabled in this project's .ioc – required for QUADSPI safety on this core, and already handled at the peripheral-configuration level rather than left as a gotcha for later.
The companion SPI project's driver manages chip-select with a manual GPIO, because generic SPI hardware has no concept of a multi-phase command – each HAL_SPI_Transmit/Receive call is an independent transaction, so software has to bracket chip-select across several calls itself. QUADSPI's peripheral is different: it natively understands the instruction/address/ dummy-cycle/data phase structure of a single command, expressed as one QSPI_CommandTypeDef passed to HAL_QSPI_Command(), so the peripheral can safely own NCS in hardware for the whole command with no software gap to land in. Same underlying command structure as the SPI chip – solved by hardware here instead of manually, because this peripheral (unlike SPI1) actually models the concept of a command phase.
No RTOS – a single superloop in Core/Src/main.c, with the flash driver written as a C++ class bridged into plain-C main.c:
W25Q/** – the driver itself:w25q_commands.h – JEDEC command opcodes and chip geometry constants, shared verbatim with the companion SPI project (transport-agnostic).W25QFlashQSPI.hpp/.cpp – the driver class: same public API shape as the SPI version (JEDEC ID, status/ready polling, sector/block/chip erase plus eraseRange(), paged read/write). Built on HAL_QSPI_Command/Transmit/Receive in indirect mode, single-line phases only for now – not yet using the chip's 4-line Quad Read/Quad Page Program commands, which is QUADSPI's actual throughput advantage over plain SPI. Not thread-safe – see the class-level Doxygen @warning for the QSPI-specific mechanism (each individual command is hardware-atomic; a sequence of commands is not).w25q_validation.hpp/.cpp – the destructive validation suite described above, ported from the SPI project (only the constructor's parameter type differs – the suite itself is transport-agnostic).Core/Inc/entryPointCPP.hpp, Core/Src/entryPointCPP.cpp** – the C/C++ bridge: extern "C" functions wrapping the driver object, guarded against use before initW25QFlash() has run.Core/Src/main.c** – CubeMX-generated peripheral init plus the application code described above.This is an STM32CubeIDE project, but it can also be built headlessly from the command line using CubeIDE's bundled ARM GCC toolchain:
This produces H753_CPP_W25Q_QSPI_Flash_Read_Write_01.elf. Grep the make output for warning:/error: to check a change compiles cleanly. Note: the W25Q/ folder needs to be added as a source/include location in the CubeIDE project settings before this will find W25QFlashQSPI.hpp – adding the files to disk doesn't register them with the build configuration by itself.
Not yet captured – this project hasn't been run on hardware. Once working, a successful run of the normal demo path is expected to print something equivalent to the companion SPI project's output (JEDEC ID, write/read-back round trip confirmation).
Doxygen-generated documentation covers the driver, the validation suite, and the C/C++ bridge layer – including the QSPI-specific thread-safety mechanism in the class-level @warning (each individual command is hardware-atomic; a sequence of commands is not). Generate it locally with doxygen Doxyfile.
No direct commits to master – branch, open a PR, and merge. This project specifically should not be considered working until it has been tested on real hardware with the full validation suite, not just a successful compile.