H753_CPP_W25Q_QSPI_Flash_Read_Write_01 1.0
STM32H753 W25Q QSPI flash (Adafruit 5632/5633/5634) read/write tutorial
Loading...
Searching...
No Matches
W25QFlashQSPI Class Reference

STM32 HAL QUADSPI driver for a Winbond W25Q-series flash chip (Adafruit 5632/5633/5634), operated in indirect mode with QUADSPI's own hardware-managed NCS (see the companion SPI driver, W25QFlashSPI, for why that one manages chip-select manually instead – same underlying command structure, different peripheral capability). More...

#include <W25QFlashQSPI.hpp>

Public Member Functions

 W25QFlashQSPI (uint32_t qspiTimeoutMs=100)
 Constructs the driver.
 
bool Init ()
 Resets the chip and verifies communication via the JEDEC ID.
 
bool readJEDECID (uint32_t &id)
 Reads the 3-byte JEDEC ID (manufacturer, memory type, capacity).
 
bool readStatus (uint8_t &status1, uint8_t &status2)
 Reads both status registers.
 
bool waitUntilReady (uint32_t timeout_ms=100)
 Polls Status Register 1's BUSY bit until clear or timeout.
 
bool eraseSector (uint32_t addr)
 Erases the single 4KB sector containing the given address.
 
bool eraseRange (uint32_t addr, uint32_t len)
 Erases every sector spanned by [addr, addr + len), computing the sector boundaries automatically – the erase-side counterpart to writeBuffer()'s automatic page-splitting.
 
bool eraseBlock (uint32_t addr)
 Erases the single 64KB block containing the given address.
 
bool eraseChip ()
 Erases the entire chip. Can take tens of seconds on larger capacities – verify the timeout against the specific chip's datasheet (16/64/128 Mbit erase times differ significantly).
 
bool readBuffer (uint32_t addr, uint8_t *buf, uint32_t len)
 Reads len bytes starting at addr into buf.
 
bool writeBuffer (uint32_t addr, const uint8_t *data, uint32_t len)
 Writes len bytes starting at addr, paging internally at 256-byte boundaries as the chip's Page Program command requires.
 

Detailed Description

STM32 HAL QUADSPI driver for a Winbond W25Q-series flash chip (Adafruit 5632/5633/5634), operated in indirect mode with QUADSPI's own hardware-managed NCS (see the companion SPI driver, W25QFlashSPI, for why that one manages chip-select manually instead – same underlying command structure, different peripheral capability).

This first pass uses single-line instruction/address/data phases only (QSPI_INSTRUCTION_1_LINE / QSPI_ADDRESS_1_LINE / QSPI_DATA_1_LINE) – electrically compatible with standard SPI wiring and sufficient to prove out the command set, but not yet using W25Q_CMD_QUAD_READ / W25Q_CMD_QUAD_PAGE_PROGRAM's 4-line data phase, which is QUADSPI's actual throughput advantage over plain SPI.

Warning
Not thread-safe or ISR-safe. Each individual HAL_QSPI_Command()/HAL_QSPI_Transmit()/HAL_QSPI_Receive() pair IS atomic with respect to NCS – QUADSPI's hardware holds NCS asserted for the whole instruction/address/data sequence of a single command with no software gap to land in, unlike the SPI driver's manual brackets. But several public methods here (writeBuffer(), eraseSector(), waitUntilReady()) are themselves a sequence of multiple separate hardware-atomic commands – e.g. writeBuffer() issues Write Enable as one complete command, then Page Program as a second, separate complete command, then waitUntilReady() polls the status register as a loop of further separate commands. Only each individual command is atomic; the sequence across commands is not. If a context switch lands in the gap between two of these hardware-atomic commands – e.g. right after Write Enable completes but before Page Program is issued – and a second task's call into this same driver instance runs in that gap, its own command sequence interleaves with the first task's half-finished operation on the same physical QUADSPI peripheral. If this driver is reused in a multi-task project, the caller is responsible for serializing all access (e.g. a mutex held for the duration of each public method call, not just each individual command).

Definition at line 63 of file W25QFlashQSPI.hpp.

Constructor & Destructor Documentation

◆ W25QFlashQSPI()

W25QFlashQSPI::W25QFlashQSPI ( uint32_t qspiTimeoutMs = 100)
explicit

Constructs the driver.

Parameters
qspiTimeoutMsPer-transaction HAL_QSPI_Command/Transmit/Receive timeout, in milliseconds, used for every QUADSPI transfer this driver issues. Distinct from waitUntilReady()'s timeout, which bounds the total time spent polling the BUSY bit across many such transactions. Defaults to 100ms; pass a different value if a specific operation (e.g. a slow bus speed) needs more headroom.

Definition at line 34 of file W25QFlashQSPI.cpp.

Member Function Documentation

◆ eraseBlock()

bool W25QFlashQSPI::eraseBlock ( uint32_t addr)

Erases the single 64KB block containing the given address.

Parameters
addrAny address within the block to erase.
Return values
trueon success, false if the erase command's QUADSPI transfer failed or the BUSY-wait timed out – not escalated to Error_Handler() (see Init()).

Definition at line 197 of file W25QFlashQSPI.cpp.

References waitUntilReady().

◆ eraseChip()

bool W25QFlashQSPI::eraseChip ( )

Erases the entire chip. Can take tens of seconds on larger capacities – verify the timeout against the specific chip's datasheet (16/64/128 Mbit erase times differ significantly).

Return values
trueon success, false if the erase command's QUADSPI transfer failed or the BUSY-wait timed out – not escalated to Error_Handler() (see Init()).

Definition at line 207 of file W25QFlashQSPI.cpp.

References waitUntilReady().

◆ eraseRange()

bool W25QFlashQSPI::eraseRange ( uint32_t addr,
uint32_t len )

Erases every sector spanned by [addr, addr + len), computing the sector boundaries automatically – the erase-side counterpart to writeBuffer()'s automatic page-splitting.

Needed for any write larger than one sector (4KB): a caller who only erases the sector addr starts in, then calls writeBuffer() with a length that spans into a second sector, gets silently corrupted data in that second sector – Page Program can only clear bits, and an unerased sector still holds whatever was there before. Matching writeBuffer()'s "any length" contract on the write side without this on the erase side would leave that exact landmine for the caller to find the hard way.

Warning
Erase always operates on whole 4KB sectors – there is no finer granularity on this chip. If addr isn't sector-aligned, or addr+len doesn't end exactly on a sector boundary, this WILL also erase any other data sharing those same sectors, even data outside the [addr, len) range you asked for. This is true of eraseSector()/eraseBlock() too, but is easier to trigger by surprise here since the caller may not be thinking in sector-aligned terms at all when picking addr and len for a write. If you're storing multiple independent pieces of data on this chip, keep each one sector-aligned (or give each its own dedicated sector(s)) precisely so an erase of one doesn't silently take out another.
Parameters
addrStarting address of the range to erase.
lenLength of the range, in bytes.
Return values
trueon success, false if any sector's erase failed – not escalated to Error_Handler() (see Init()). Sectors already erased before a failing one remain erased.

Definition at line 180 of file W25QFlashQSPI.cpp.

References eraseSector().

◆ eraseSector()

bool W25QFlashQSPI::eraseSector ( uint32_t addr)

Erases the single 4KB sector containing the given address.

Parameters
addrAny address within the sector to erase.
Return values
trueon success, false if the erase command's QUADSPI transfer failed or the BUSY-wait timed out – not escalated to Error_Handler() (see Init()).

Definition at line 170 of file W25QFlashQSPI.cpp.

References waitUntilReady().

Referenced by eraseRange().

◆ Init()

bool W25QFlashQSPI::Init ( )

Resets the chip and verifies communication via the JEDEC ID.

Unlike every other public method below, a HAL-level QUADSPI failure here calls Error_Handler() rather than returning false. A communication failure on the very first transaction at startup indicates a setup problem (bad wiring, dead chip, wrong pin config) that retrying can't fix – matching how CubeMX's own generated peripheral-init code already behaves elsewhere in main.c. A wrong JEDEC ID (chip present and responding, just not a W25Q) is not treated as a HAL failure and simply returns false – that's a legitimate, non-fatal "wrong/missing chip" outcome, not a bus fault.

Return values
trueif a W25Q-family JEDEC manufacturer ID (0xEF) was read back.

Definition at line 97 of file W25QFlashQSPI.cpp.

References readJEDECID().

◆ readBuffer()

bool W25QFlashQSPI::readBuffer ( uint32_t addr,
uint8_t * buf,
uint32_t len )

Reads len bytes starting at addr into buf.

Parameters
addrStarting flash address to read from.
bufDestination buffer, must be at least len bytes.
lenNumber of bytes to read.
Return values
trueon success, false if the QUADSPI transfer failed – caller may retry; not escalated to Error_Handler() (see Init()).

Definition at line 224 of file W25QFlashQSPI.cpp.

◆ readJEDECID()

bool W25QFlashQSPI::readJEDECID ( uint32_t & id)

Reads the 3-byte JEDEC ID (manufacturer, memory type, capacity).

Distinguishes a failed QUADSPI transfer from a successful transfer that simply read back an unexpected ID (wrong/missing chip) – the return value reports the former, id's contents (valid only when this returns true) determine the latter. Not escalated to Error_Handler() – see the class-level note on Init() vs. every other method; use Init() itself for the fail-hard startup check.

Parameters
idDestination for the 24-bit JEDEC ID (manufacturer byte in bits [23:16]). Left unmodified if this returns false.
Return values
trueif the QUADSPI transfer succeeded (regardless of whether id turned out to be a genuine W25Q manufacturer ID), false if the transfer itself failed – caller may retry; not escalated to Error_Handler() (see Init()).

Definition at line 122 of file W25QFlashQSPI.cpp.

Referenced by Init().

◆ readStatus()

bool W25QFlashQSPI::readStatus ( uint8_t & status1,
uint8_t & status2 )

Reads both status registers.

Parameters
status1Destination for Status Register 1 (BUSY, WEL, block-protect bits).
status2Destination for Status Register 2 (QE and other bits).
Return values
trueon success, false if either QUADSPI transfer failed – caller may retry; not escalated to Error_Handler() (see Init()).

Definition at line 137 of file W25QFlashQSPI.cpp.

◆ waitUntilReady()

bool W25QFlashQSPI::waitUntilReady ( uint32_t timeout_ms = 100)

Polls Status Register 1's BUSY bit until clear or timeout.

Parameters
timeout_msMaximum time to wait, in milliseconds.
Return values
trueif the chip became ready before the timeout.

Definition at line 151 of file W25QFlashQSPI.cpp.

Referenced by eraseBlock(), eraseChip(), eraseSector(), and writeBuffer().

◆ writeBuffer()

bool W25QFlashQSPI::writeBuffer ( uint32_t addr,
const uint8_t * data,
uint32_t len )

Writes len bytes starting at addr, paging internally at 256-byte boundaries as the chip's Page Program command requires.

Parameters
addrStarting flash address to write to. The destination must already be erased – flash bits can only be cleared (1 -> 0), never set, outside of an erase operation.
dataSource buffer of len bytes to write.
lenNumber of bytes to write.
Return values
trueon success, false if any page's QUADSPI transfer failed or its BUSY-wait timed out – not escalated to Error_Handler() (see Init()). Pages already written before the failing one remain written; the caller can inspect/retry from the failure point.

Definition at line 241 of file W25QFlashQSPI.cpp.

References waitUntilReady().


The documentation for this class was generated from the following files: