8#include "W25QFlashQSPI.hpp"
10extern QSPI_HandleTypeDef hqspi;
21QSPI_CommandTypeDef makeBaseCommand() {
22 QSPI_CommandTypeDef cmd = {0};
23 cmd.InstructionMode = QSPI_INSTRUCTION_1_LINE;
24 cmd.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
26 cmd.DdrMode = QSPI_DDR_MODE_DISABLE;
27 cmd.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
28 cmd.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
37HAL_StatusTypeDef W25QFlashQSPI::runCommand(uint8_t instruction) {
38 QSPI_CommandTypeDef cmd = makeBaseCommand();
39 cmd.Instruction = instruction;
40 cmd.AddressMode = QSPI_ADDRESS_NONE;
41 cmd.DataMode = QSPI_DATA_NONE;
43 HAL_StatusTypeDef status = HAL_QSPI_Command(_hqspi, &cmd, _qspiTimeoutMs);
47HAL_StatusTypeDef W25QFlashQSPI::readCommand(uint8_t instruction, uint8_t *resp, uint32_t len) {
48 QSPI_CommandTypeDef cmd = makeBaseCommand();
49 cmd.Instruction = instruction;
50 cmd.AddressMode = QSPI_ADDRESS_NONE;
51 cmd.DataMode = (len > 0) ? QSPI_DATA_1_LINE : QSPI_DATA_NONE;
54 HAL_StatusTypeDef status = HAL_QSPI_Command(_hqspi, &cmd, _qspiTimeoutMs);
55 if (status == HAL_OK && len > 0) {
56 status = HAL_QSPI_Receive(_hqspi, resp, _qspiTimeoutMs);
61HAL_StatusTypeDef W25QFlashQSPI::writeCommand(uint8_t instruction,
const uint8_t *data, uint32_t len) {
62 QSPI_CommandTypeDef cmd = makeBaseCommand();
63 cmd.Instruction = instruction;
64 cmd.AddressMode = QSPI_ADDRESS_NONE;
65 cmd.DataMode = (len > 0) ? QSPI_DATA_1_LINE : QSPI_DATA_NONE;
68 HAL_StatusTypeDef status = HAL_QSPI_Command(_hqspi, &cmd, _qspiTimeoutMs);
69 if (status == HAL_OK && len > 0) {
70 status = HAL_QSPI_Transmit(_hqspi,
const_cast<uint8_t *
>(data), _qspiTimeoutMs);
75HAL_StatusTypeDef W25QFlashQSPI::eraseCommand(uint8_t instruction, uint32_t addr) {
76 HAL_StatusTypeDef status = writeEnable();
77 if (status != HAL_OK) {
81 QSPI_CommandTypeDef cmd = makeBaseCommand();
82 cmd.Instruction = instruction;
83 cmd.AddressMode = QSPI_ADDRESS_1_LINE;
84 cmd.AddressSize = QSPI_ADDRESS_24_BITS;
86 cmd.DataMode = QSPI_DATA_NONE;
88 status = HAL_QSPI_Command(_hqspi, &cmd, _qspiTimeoutMs);
92HAL_StatusTypeDef W25QFlashQSPI::writeEnable() {
93 HAL_StatusTypeDef status = runCommand(W25Q_CMD_WRITE_ENABLE);
101 HAL_StatusTypeDef status = runCommand(W25Q_CMD_ENABLE_RESET);
102 if (status != HAL_OK) {
106 status = runCommand(W25Q_CMD_RESET);
107 if (status != HAL_OK) {
118 bool detected = ((
id >> 16) & 0xFF) == W25Q_JEDEC_MANUFACTURER_ID;
127 uint8_t resp[3] = { 0, 0, 0 };
128 HAL_StatusTypeDef status = readCommand(W25Q_CMD_READ_JEDEC_ID, resp,
sizeof(resp));
129 if (status != HAL_OK) {
133 id = ((uint32_t)resp[0] << 16) | ((uint32_t)resp[1] << 8) | resp[2];
138 HAL_StatusTypeDef status = readCommand(W25Q_CMD_READ_STATUS1, &status1, 1);
139 if (status != HAL_OK) {
143 status = readCommand(W25Q_CMD_READ_STATUS2, &status2, 1);
144 if (status != HAL_OK) {
152 uint32_t start = HAL_GetTick();
153 uint8_t chipStatus = 0;
156 HAL_StatusTypeDef status = readCommand(W25Q_CMD_READ_STATUS1, &chipStatus, 1);
157 if (status != HAL_OK) {
161 if ((chipStatus & 0x01) == 0) {
164 }
while ((HAL_GetTick() - start) < timeout_ms);
171 HAL_StatusTypeDef status = eraseCommand(W25Q_CMD_ERASE_SECTOR, addr);
172 if (status != HAL_OK) {
185 uint32_t firstSector = addr / W25Q_SECTOR_SIZE;
186 uint32_t lastSector = (addr + len - 1) / W25Q_SECTOR_SIZE;
188 for (uint32_t sector = firstSector; sector <= lastSector; sector++) {
198 HAL_StatusTypeDef status = eraseCommand(W25Q_CMD_ERASE_BLOCK, addr);
199 if (status != HAL_OK) {
208 HAL_StatusTypeDef status = writeEnable();
209 if (status != HAL_OK) {
213 status = runCommand(W25Q_CMD_ERASE_CHIP);
214 if (status != HAL_OK) {
225 QSPI_CommandTypeDef cmd = makeBaseCommand();
226 cmd.Instruction = W25Q_CMD_READ;
227 cmd.AddressMode = QSPI_ADDRESS_1_LINE;
228 cmd.AddressSize = QSPI_ADDRESS_24_BITS;
230 cmd.DataMode = QSPI_DATA_1_LINE;
233 HAL_StatusTypeDef status = HAL_QSPI_Command(_hqspi, &cmd, _qspiTimeoutMs);
234 if (status == HAL_OK) {
235 status = HAL_QSPI_Receive(_hqspi, buf, _qspiTimeoutMs);
238 return status == HAL_OK;
242 uint32_t written = 0;
244 while (written < len) {
245 uint32_t pageOffset = (addr + written) % W25Q_PAGE_SIZE;
246 uint32_t chunk = W25Q_PAGE_SIZE - pageOffset;
247 if (chunk > (len - written)) {
248 chunk = len - written;
251 HAL_StatusTypeDef status = writeEnable();
252 if (status != HAL_OK) {
256 QSPI_CommandTypeDef cmd = makeBaseCommand();
257 cmd.Instruction = W25Q_CMD_PAGE_PROGRAM;
258 cmd.AddressMode = QSPI_ADDRESS_1_LINE;
259 cmd.AddressSize = QSPI_ADDRESS_24_BITS;
260 cmd.Address = addr + written;
261 cmd.DataMode = QSPI_DATA_1_LINE;
264 status = HAL_QSPI_Command(_hqspi, &cmd, _qspiTimeoutMs);
265 if (status == HAL_OK) {
266 status = HAL_QSPI_Transmit(_hqspi,
const_cast<uint8_t *
>(data + written), _qspiTimeoutMs);
269 if (status != HAL_OK) {
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 eraseBlock(uint32_t addr)
Erases the single 64KB block containing the given address.
W25QFlashQSPI(uint32_t qspiTimeoutMs=100)
Constructs the driver.
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 Progra...
bool readJEDECID(uint32_t &id)
Reads the 3-byte JEDEC ID (manufacturer, memory type, capacity).
bool eraseChip()
Erases the entire chip. Can take tens of seconds on larger capacities – verify the timeout against th...
bool readBuffer(uint32_t addr, uint8_t *buf, uint32_t len)
Reads len bytes starting at addr into buf.
bool eraseRange(uint32_t addr, uint32_t len)
Erases every sector spanned by [addr, addr + len), computing the sector boundaries automatically – th...
bool Init()
Resets the chip and verifies communication via the JEDEC ID.
bool eraseSector(uint32_t addr)
Erases the single 4KB sector containing the given address.