H753_CPP_W25Q_SPI_Flash_Read_Write_01 1.0
STM32H753 W25Q SPI flash (Adafruit 5632/5633/5634) read/write tutorial
Loading...
Searching...
No Matches
W25QFlashSPI Class Reference

STM32 HAL SPI1 driver for a Winbond W25Q-series flash chip (Adafruit 5632/5633/5634), operated in standard single-line SPI mode with software-controlled chip select (WQ25_CS – see main.h for the current pin assignment). More...

#include <W25QFlashSPI.hpp>

Public Member Functions

 W25QFlashSPI (uint32_t spiTimeoutMs=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 SPI1 driver for a Winbond W25Q-series flash chip (Adafruit 5632/5633/5634), operated in standard single-line SPI mode with software-controlled chip select (WQ25_CS – see main.h for the current pin assignment).

Warning
Not thread-safe or ISR-safe. There is no mutex or reentrancy guard anywhere in this class. The specific mechanism: several public methods (writeBuffer(), eraseSector(), waitUntilReady()) are themselves made up of multiple separate csEnable()/ HAL_SPI_.../csDisable() brackets in sequence – e.g. writeBuffer() calls writeEnable() (its own CS bracket), then a second CS bracket for the Page Program command, then waitUntilReady() (a loop of further CS brackets polling the status register). Only the inside of each individual bracket is atomic. If a context switch lands in the gap between brackets – e.g. right after writeEnable() succeeds but before the Page Program command is actually sent – and a second task's call into this same driver instance runs in that gap, that task's own CS-low period and command bytes land on the wire interleaved with the first task's half-finished operation. Both share the same physical SPI1 peripheral and the same CS pin, so the chip sees a single corrupted byte stream, not two separate operations – there is no way for either task, or the chip, to tell the interleaving happened. 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 CS bracket).

Definition at line 53 of file W25QFlashSPI.hpp.

Constructor & Destructor Documentation

◆ W25QFlashSPI()

W25QFlashSPI::W25QFlashSPI ( uint32_t spiTimeoutMs = 100)
explicit

Constructs the driver.

Parameters
spiTimeoutMsPer-transaction HAL_SPI_Transmit/Receive timeout, in milliseconds, used for every SPI 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 12 of file W25QFlashSPI.cpp.

Member Function Documentation

◆ eraseBlock()

bool W25QFlashSPI::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 SPI transfer failed or the BUSY-wait timed out – not escalated to Error_Handler() (see Init()).

Definition at line 177 of file W25QFlashSPI.cpp.

References waitUntilReady().

◆ eraseChip()

bool W25QFlashSPI::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 SPI transfer failed or the BUSY-wait timed out – not escalated to Error_Handler() (see Init()).

Definition at line 187 of file W25QFlashSPI.cpp.

References waitUntilReady().

◆ eraseRange()

bool W25QFlashSPI::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 160 of file W25QFlashSPI.cpp.

References eraseSector().

◆ eraseSector()

bool W25QFlashSPI::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 SPI transfer failed or the BUSY-wait timed out – not escalated to Error_Handler() (see Init()).

Definition at line 150 of file W25QFlashSPI.cpp.

References waitUntilReady().

Referenced by eraseRange().

◆ Init()

bool W25QFlashSPI::Init ( )

Resets the chip and verifies communication via the JEDEC ID.

Unlike every other public method below, a HAL-level SPI 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 77 of file W25QFlashSPI.cpp.

References readJEDECID().

◆ readBuffer()

bool W25QFlashSPI::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 SPI transfer failed – caller may retry; not escalated to Error_Handler() (see Init()).

Definition at line 204 of file W25QFlashSPI.cpp.

◆ readJEDECID()

bool W25QFlashSPI::readJEDECID ( uint32_t & id)

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

Distinguishes a failed SPI 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 SPI 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 102 of file W25QFlashSPI.cpp.

Referenced by Init().

◆ readStatus()

bool W25QFlashSPI::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 SPI transfer failed – caller may retry; not escalated to Error_Handler() (see Init()).

Definition at line 117 of file W25QFlashSPI.cpp.

◆ waitUntilReady()

bool W25QFlashSPI::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 131 of file W25QFlashSPI.cpp.

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

◆ writeBuffer()

bool W25QFlashSPI::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 SPI 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 219 of file W25QFlashSPI.cpp.

References waitUntilReady().


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