8#include "W25QFlashSPI.hpp"
10extern SPI_HandleTypeDef hspi1;
15void W25QFlashSPI::csEnable() {
16 HAL_GPIO_WritePin(WQ25_CS_GPIO_Port, WQ25_CS_Pin, GPIO_PIN_RESET);
19void W25QFlashSPI::csDisable() {
20 HAL_GPIO_WritePin(WQ25_CS_GPIO_Port, WQ25_CS_Pin, GPIO_PIN_SET);
23void W25QFlashSPI::fillAddress(uint8_t *buf, uint32_t addr) {
24 buf[0] = (uint8_t)(addr >> 16);
25 buf[1] = (uint8_t)(addr >> 8);
26 buf[2] = (uint8_t)(addr);
29HAL_StatusTypeDef W25QFlashSPI::runCommand(uint8_t cmd) {
31 HAL_StatusTypeDef status = HAL_SPI_Transmit(_hspi, &cmd, 1, _spiTimeoutMs);
36HAL_StatusTypeDef W25QFlashSPI::readCommand(uint8_t cmd, uint8_t *resp, uint32_t len) {
38 HAL_StatusTypeDef status = HAL_SPI_Transmit(_hspi, &cmd, 1, _spiTimeoutMs);
39 if (status == HAL_OK && len > 0) {
40 status = HAL_SPI_Receive(_hspi, resp, len, _spiTimeoutMs);
46HAL_StatusTypeDef W25QFlashSPI::writeCommand(uint8_t cmd,
const uint8_t *data, uint32_t len) {
48 HAL_StatusTypeDef status = HAL_SPI_Transmit(_hspi, &cmd, 1, _spiTimeoutMs);
49 if (status == HAL_OK && len > 0) {
50 status = HAL_SPI_Transmit(_hspi,
const_cast<uint8_t *
>(data), len, _spiTimeoutMs);
56HAL_StatusTypeDef W25QFlashSPI::eraseCommand(uint8_t cmd, uint32_t addr) {
57 HAL_StatusTypeDef status = writeEnable();
58 if (status != HAL_OK) {
64 fillAddress(&header[1], addr);
67 status = HAL_SPI_Transmit(_hspi, header,
sizeof(header), _spiTimeoutMs);
72HAL_StatusTypeDef W25QFlashSPI::writeEnable() {
73 HAL_StatusTypeDef status = runCommand(W25Q_CMD_WRITE_ENABLE);
81 HAL_StatusTypeDef status = runCommand(W25Q_CMD_ENABLE_RESET);
82 if (status != HAL_OK) {
86 status = runCommand(W25Q_CMD_RESET);
87 if (status != HAL_OK) {
98 bool detected = ((
id >> 16) & 0xFF) == W25Q_JEDEC_MANUFACTURER_ID;
107 uint8_t resp[3] = { 0, 0, 0 };
108 HAL_StatusTypeDef status = readCommand(W25Q_CMD_READ_JEDEC_ID, resp,
sizeof(resp));
109 if (status != HAL_OK) {
113 id = ((uint32_t)resp[0] << 16) | ((uint32_t)resp[1] << 8) | resp[2];
118 HAL_StatusTypeDef status = readCommand(W25Q_CMD_READ_STATUS1, &status1, 1);
119 if (status != HAL_OK) {
123 status = readCommand(W25Q_CMD_READ_STATUS2, &status2, 1);
124 if (status != HAL_OK) {
132 uint32_t start = HAL_GetTick();
133 uint8_t chipStatus = 0;
136 HAL_StatusTypeDef status = readCommand(W25Q_CMD_READ_STATUS1, &chipStatus, 1);
137 if (status != HAL_OK) {
141 if ((chipStatus & 0x01) == 0) {
144 }
while ((HAL_GetTick() - start) < timeout_ms);
151 HAL_StatusTypeDef status = eraseCommand(W25Q_CMD_ERASE_SECTOR, addr);
152 if (status != HAL_OK) {
165 uint32_t firstSector = addr / W25Q_SECTOR_SIZE;
166 uint32_t lastSector = (addr + len - 1) / W25Q_SECTOR_SIZE;
168 for (uint32_t sector = firstSector; sector <= lastSector; sector++) {
178 HAL_StatusTypeDef status = eraseCommand(W25Q_CMD_ERASE_BLOCK, addr);
179 if (status != HAL_OK) {
188 HAL_StatusTypeDef status = writeEnable();
189 if (status != HAL_OK) {
193 status = runCommand(W25Q_CMD_ERASE_CHIP);
194 if (status != HAL_OK) {
206 header[0] = W25Q_CMD_READ;
207 fillAddress(&header[1], addr);
210 HAL_StatusTypeDef status = HAL_SPI_Transmit(_hspi, header,
sizeof(header), _spiTimeoutMs);
211 if (status == HAL_OK) {
212 status = HAL_SPI_Receive(_hspi, buf, len, _spiTimeoutMs);
216 return status == HAL_OK;
220 uint32_t written = 0;
222 while (written < len) {
223 uint32_t pageOffset = (addr + written) % W25Q_PAGE_SIZE;
224 uint32_t chunk = W25Q_PAGE_SIZE - pageOffset;
225 if (chunk > (len - written)) {
226 chunk = len - written;
229 HAL_StatusTypeDef status = writeEnable();
230 if (status != HAL_OK) {
235 header[0] = W25Q_CMD_PAGE_PROGRAM;
236 fillAddress(&header[1], addr + written);
239 status = HAL_SPI_Transmit(_hspi, header,
sizeof(header), _spiTimeoutMs);
240 if (status == HAL_OK) {
241 status = HAL_SPI_Transmit(_hspi,
const_cast<uint8_t *
>(data + written), chunk, _spiTimeoutMs);
245 if (status != HAL_OK) {
bool eraseSector(uint32_t addr)
Erases the single 4KB sector containing the given address.
W25QFlashSPI(uint32_t spiTimeoutMs=100)
Constructs the driver.
bool Init()
Resets the chip and verifies communication via the JEDEC ID.
bool eraseRange(uint32_t addr, uint32_t len)
Erases every sector spanned by [addr, addr + len), computing the sector boundaries automatically – th...
bool readBuffer(uint32_t addr, uint8_t *buf, uint32_t len)
Reads len bytes starting at addr into buf.
bool readStatus(uint8_t &status1, uint8_t &status2)
Reads both status registers.
bool eraseBlock(uint32_t addr)
Erases the single 64KB block containing the given address.
bool waitUntilReady(uint32_t timeout_ms=100)
Polls Status Register 1's BUSY bit until clear or timeout.
bool eraseChip()
Erases the entire chip. Can take tens of seconds on larger capacities – verify the timeout against th...
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).