|
H753_CPP_W25Q_QSPI_Flash_Read_Write_01 1.0
STM32H753 W25Q QSPI flash (Adafruit 5632/5633/5634) read/write tutorial
|
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. | |
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.
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.
|
explicit |
Constructs the driver.
| qspiTimeoutMs | Per-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.
| bool W25QFlashQSPI::eraseBlock | ( | uint32_t | addr | ) |
Erases the single 64KB block containing the given address.
| addr | Any address within the block to erase. |
| true | on 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().
| 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).
| true | on 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().
| 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.
| addr | Starting address of the range to erase. |
| len | Length of the range, in bytes. |
| true | on 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().
| bool W25QFlashQSPI::eraseSector | ( | uint32_t | addr | ) |
Erases the single 4KB sector containing the given address.
| addr | Any address within the sector to erase. |
| true | on 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().
| 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.
| true | if a W25Q-family JEDEC manufacturer ID (0xEF) was read back. |
Definition at line 97 of file W25QFlashQSPI.cpp.
References readJEDECID().
| bool W25QFlashQSPI::readBuffer | ( | uint32_t | addr, |
| uint8_t * | buf, | ||
| uint32_t | len ) |
Reads len bytes starting at addr into buf.
| addr | Starting flash address to read from. |
| buf | Destination buffer, must be at least len bytes. |
| len | Number of bytes to read. |
| true | on 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.
| 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.
| id | Destination for the 24-bit JEDEC ID (manufacturer byte in bits [23:16]). Left unmodified if this returns false. |
| true | if 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().
| bool W25QFlashQSPI::readStatus | ( | uint8_t & | status1, |
| uint8_t & | status2 ) |
Reads both status registers.
| status1 | Destination for Status Register 1 (BUSY, WEL, block-protect bits). |
| status2 | Destination for Status Register 2 (QE and other bits). |
| true | on 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.
| bool W25QFlashQSPI::waitUntilReady | ( | uint32_t | timeout_ms = 100 | ) |
Polls Status Register 1's BUSY bit until clear or timeout.
| timeout_ms | Maximum time to wait, in milliseconds. |
| true | if the chip became ready before the timeout. |
Definition at line 151 of file W25QFlashQSPI.cpp.
Referenced by eraseBlock(), eraseChip(), eraseSector(), and 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.
| addr | Starting 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. |
| data | Source buffer of len bytes to write. |
| len | Number of bytes to write. |
| true | on 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().