Use the cached value of useDshotTelemetry to ensure consistent runtime use if dshot_b...
[betaflight.git] / src / main / drivers / flash_w25n01g.c
blob84c6bc2d665e784008fdabc8949b9785c4877d2d
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
20 * Author: jflyper
23 #include <stdbool.h>
24 #include <stdint.h>
26 #include "platform.h"
28 #ifdef USE_FLASH_W25N01G
30 #include "flash.h"
31 #include "flash_impl.h"
32 #include "flash_w25n01g.h"
33 #include "drivers/bus_spi.h"
34 #include "drivers/bus_quadspi.h"
35 #include "drivers/io.h"
36 #include "drivers/time.h"
38 // Device size parameters
39 #define W25N01G_PAGE_SIZE 2048
40 #define W25N01G_PAGES_PER_BLOCK 64
41 #define W25N01G_BLOCKS_PER_DIE 1024
43 // BB replacement area
44 #define W25N01G_BB_MARKER_BLOCKS 1
45 #define W25N01G_BB_REPLACEMENT_BLOCKS 20
46 #define W25N01G_BB_MANAGEMENT_BLOCKS (W25N01G_BB_REPLACEMENT_BLOCKS + W25N01G_BB_MARKER_BLOCKS)
47 // blocks are zero-based index
48 #define W25N01G_BB_REPLACEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_REPLACEMENT_BLOCKS)
49 #define W25N01G_BB_MANAGEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_MANAGEMENT_BLOCKS)
50 #define W25N01G_BB_MARKER_BLOCK (W25N01G_BB_REPLACEMENT_START_BLOCK - W25N01G_BB_MARKER_BLOCKS)
52 // Instructions
54 #define W25N01G_INSTRUCTION_RDID 0x9F
55 #define W25N01G_INSTRUCTION_DEVICE_RESET 0xFF
56 #define W25N01G_INSTRUCTION_READ_STATUS_REG 0x05
57 #define W25N01G_INSTRUCTION_READ_STATUS_ALTERNATE_REG 0x0F
58 #define W25N01G_INSTRUCTION_WRITE_STATUS_REG 0x01
59 #define W25N01G_INSTRUCTION_WRITE_STATUS_ALTERNATE_REG 0x1F
60 #define W25N01G_INSTRUCTION_WRITE_ENABLE 0x06
61 #define W25N01G_INSTRUCTION_DIE_SELECT 0xC2
62 #define W25N01G_INSTRUCTION_BLOCK_ERASE 0xD8
63 #define W25N01G_INSTRUCTION_READ_BBM_LUT 0xA5
64 #define W25N01G_INSTRUCTION_BB_MANAGEMENT 0xA1
65 #define W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD 0x02
66 #define W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD 0x84
67 #define W25N01G_INSTRUCTION_PROGRAM_EXECUTE 0x10
68 #define W25N01G_INSTRUCTION_PAGE_DATA_READ 0x13
69 #define W25N01G_INSTRUCTION_READ_DATA 0x03
70 #define W25N01G_INSTRUCTION_FAST_READ 0x1B
71 #define W25N01G_INSTRUCTION_FAST_READ_QUAD_OUTPUT 0x6B
73 // Config/status register addresses
74 #define W25N01G_PROT_REG 0xA0
75 #define W25N01G_CONF_REG 0xB0
76 #define W25N01G_STAT_REG 0xC0
78 // Bits in config/status register 1 (W25N01G_PROT_REG)
79 #define W25N01G_PROT_CLEAR (0)
80 #define W25N01G_PROT_SRP1_ENABLE (1 << 0)
81 #define W25N01G_PROT_WP_E_ENABLE (1 << 1)
82 #define W25N01G_PROT_TB_ENABLE (1 << 2)
83 #define W25N01G_PROT_PB0_ENABLE (1 << 3)
84 #define W25N01G_PROT_PB1_ENABLE (1 << 4)
85 #define W25N01G_PROT_PB2_ENABLE (1 << 5)
86 #define W25N01G_PROT_PB3_ENABLE (1 << 6)
87 #define W25N01G_PROT_SRP2_ENABLE (1 << 7)
89 // Bits in config/status register 2 (W25N01G_CONF_REG)
90 #define W25N01G_CONFIG_ECC_ENABLE (1 << 4)
91 #define W25N01G_CONFIG_BUFFER_READ_MODE (1 << 3)
93 // Bits in config/status register 3 (W25N01G_STATREG)
94 #define W25N01G_STATUS_BBM_LUT_FULL (1 << 6)
95 #define W25N01G_STATUS_FLAG_ECC_POS 4
96 #define W25N01G_STATUS_FLAG_ECC_MASK ((1 << 5)|(1 << 4))
97 #define W25N01G_STATUS_FLAG_ECC(status) (((status) & W25N01G_STATUS_FLAG_ECC_MASK) >> 4)
98 #define W25N01G_STATUS_PROGRAM_FAIL (1 << 3)
99 #define W25N01G_STATUS_ERASE_FAIL (1 << 2)
100 #define W25N01G_STATUS_FLAG_WRITE_ENABLED (1 << 1)
101 #define W25N01G_STATUS_FLAG_BUSY (1 << 0)
103 #define W25N01G_BBLUT_TABLE_ENTRY_COUNT 20
104 #define W25N01G_BBLUT_TABLE_ENTRY_SIZE 4 // in bytes
106 // Bits in LBA for BB LUT
107 #define W25N01G_BBLUT_STATUS_ENABLED (1 << 15)
108 #define W25N01G_BBLUT_STATUS_INVALID (1 << 14)
109 #define W25N01G_BBLUT_STATUS_MASK (W25N01G_BBLUT_STATUS_ENABLED | W25N01G_BBLUT_STATUS_INVALID)
111 // Some useful defs and macros
112 #define W25N01G_LINEAR_TO_COLUMN(laddr) ((laddr) % W25N01G_PAGE_SIZE)
113 #define W25N01G_LINEAR_TO_PAGE(laddr) ((laddr) / W25N01G_PAGE_SIZE)
114 #define W25N01G_LINEAR_TO_BLOCK(laddr) (W25N01G_LINEAR_TO_PAGE(laddr) / W25N01G_PAGES_PER_BLOCK)
115 #define W25N01G_BLOCK_TO_PAGE(block) ((block) * W25N01G_PAGES_PER_BLOCK)
116 #define W25N01G_BLOCK_TO_LINEAR(block) (W25N01G_BLOCK_TO_PAGE(block) * W25N01G_PAGE_SIZE)
118 // IMPORTANT: Timeout values are currently required to be set to the highest value required by any of the supported flash chips by this driver
120 // The timeout values (2ms minimum to avoid 1 tick advance in consecutive calls to millis).
121 #define W25N01G_TIMEOUT_PAGE_READ_MS 2 // tREmax = 60us (ECC enabled)
122 #define W25N01G_TIMEOUT_PAGE_PROGRAM_MS 2 // tPPmax = 700us
123 #define W25N01G_TIMEOUT_BLOCK_ERASE_MS 15 // tBEmax = 10ms
124 #define W25N01G_TIMEOUT_RESET_MS 500 // tRSTmax = 500ms
126 // Sizes (in bits)
127 #define W25N01G_STATUS_REGISTER_SIZE 8
128 #define W25N01G_STATUS_PAGE_ADDRESS_SIZE 16
129 #define W25N01G_STATUS_COLUMN_ADDRESS_SIZE 16
131 typedef struct bblut_s {
132 uint16_t pba;
133 uint16_t lba;
134 } bblut_t;
136 static bool w25n01g_waitForReady(flashDevice_t *fdevice);
138 static void w25n01g_setTimeout(flashDevice_t *fdevice, uint32_t timeoutMillis)
140 uint32_t now = millis();
141 fdevice->timeoutAt = now + timeoutMillis;
145 * Send the given command byte to the device.
147 static void w25n01g_performOneByteCommand(flashDeviceIO_t *io, uint8_t command)
149 if (io->mode == FLASHIO_SPI) {
150 extDevice_t *dev = io->handle.dev;
152 busSegment_t segments[] = {
153 {.u.buffers = {&command, NULL}, sizeof(command), true, NULL},
154 {.u.link = {NULL, NULL}, 0, true, NULL},
157 spiSequence(dev, &segments[0]);
159 // Block pending completion of SPI access
160 spiWait(dev);
162 #ifdef USE_QUADSPI
163 else if (io->mode == FLASHIO_QUADSPI) {
164 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
165 quadSpiTransmit1LINE(quadSpi, command, 0, NULL, 0);
167 #endif
170 static void w25n01g_performCommandWithPageAddress(flashDeviceIO_t *io, uint8_t command, uint32_t pageAddress)
172 if (io->mode == FLASHIO_SPI) {
173 extDevice_t *dev = io->handle.dev;
175 uint8_t cmd[] = { command, 0, (pageAddress >> 8) & 0xff, (pageAddress >> 0) & 0xff};
177 busSegment_t segments[] = {
178 {.u.buffers = {cmd, NULL}, sizeof(cmd), true, NULL},
179 {.u.link = {NULL, NULL}, 0, true, NULL},
182 spiSequence(dev, &segments[0]);
184 // Block pending completion of SPI access
185 spiWait(dev);
187 #ifdef USE_QUADSPI
188 else if (io->mode == FLASHIO_QUADSPI) {
189 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
191 quadSpiInstructionWithAddress1LINE(quadSpi, command, 0, pageAddress & 0xffff, W25N01G_STATUS_PAGE_ADDRESS_SIZE + 8);
193 #endif
196 static uint8_t w25n01g_readRegister(flashDeviceIO_t *io, uint8_t reg)
198 if (io->mode == FLASHIO_SPI) {
199 extDevice_t *dev = io->handle.dev;
201 uint8_t cmd[3] = { W25N01G_INSTRUCTION_READ_STATUS_REG, reg, 0 };
202 uint8_t in[3];
204 busSegment_t segments[] = {
205 {.u.buffers = {cmd, in}, sizeof(cmd), true, NULL},
206 {.u.link = {NULL, NULL}, 0, true, NULL},
209 // Ensure any prior DMA has completed before continuing
210 spiWait(dev);
212 spiSequence(dev, &segments[0]);
214 // Block pending completion of SPI access
215 spiWait(dev);
217 return in[2];
219 #ifdef USE_QUADSPI
220 else if (io->mode == FLASHIO_QUADSPI) {
222 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
224 uint8_t in[W25N01G_STATUS_REGISTER_SIZE / 8];
225 quadSpiReceiveWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_READ_STATUS_REG, 0, reg, W25N01G_STATUS_REGISTER_SIZE, in, sizeof(in));
227 return in[0];
229 #endif
230 return 0;
233 static void w25n01g_writeRegister(flashDeviceIO_t *io, uint8_t reg, uint8_t data)
235 if (io->mode == FLASHIO_SPI) {
236 extDevice_t *dev = io->handle.dev;
237 uint8_t cmd[3] = { W25N01G_INSTRUCTION_WRITE_STATUS_REG, reg, data };
239 busSegment_t segments[] = {
240 {.u.buffers = {cmd, NULL}, sizeof(cmd), true, NULL},
241 {.u.link = {NULL, NULL}, 0, true, NULL},
244 // Ensure any prior DMA has completed before continuing
245 spiWait(dev);
247 spiSequence(dev, &segments[0]);
249 // Block pending completion of SPI access
250 spiWait(dev);
252 #ifdef USE_QUADSPI
253 else if (io->mode == FLASHIO_QUADSPI) {
254 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
256 quadSpiTransmitWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_WRITE_STATUS_REG, 0, reg, W25N01G_STATUS_REGISTER_SIZE, &data, 1);
258 #endif
262 static void w25n01g_deviceReset(flashDevice_t *fdevice)
264 flashDeviceIO_t *io = &fdevice->io;
266 w25n01g_performOneByteCommand(io, W25N01G_INSTRUCTION_DEVICE_RESET);
268 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_RESET_MS);
269 w25n01g_waitForReady(fdevice);
271 // Protection for upper 1/32 (BP[3:0] = 0101, TB=0), WP-E on; to protect bad block replacement area
272 // DON'T DO THIS. This will prevent writes through the bblut as well.
273 // w25n01g_writeRegister(dev, W25N01G_PROT_REG, W25N01G_PROT_PB0_ENABLE|W25N01G_PROT_PB2_ENABLE|W25N01G_PROT_WP_E_ENABLE);
275 // No protection, WP-E off, WP-E prevents use of IO2
276 w25n01g_writeRegister(io, W25N01G_PROT_REG, W25N01G_PROT_CLEAR);
278 // Buffered read mode (BUF = 1), ECC enabled (ECC = 1)
279 w25n01g_writeRegister(io, W25N01G_CONF_REG, W25N01G_CONFIG_ECC_ENABLE|W25N01G_CONFIG_BUFFER_READ_MODE);
282 bool w25n01g_isReady(flashDevice_t *fdevice)
284 // If we're waiting on DMA completion, then SPI is busy
285 if (fdevice->io.mode == FLASHIO_SPI) {
286 if (fdevice->io.handle.dev->bus->useDMA && spiIsBusy(fdevice->io.handle.dev)) {
287 return false;
291 // Irrespective of the current state of fdevice->couldBeBusy read the status or device blocks
293 // Poll the FLASH device to see if it's busy
294 fdevice->couldBeBusy = ((w25n01g_readRegister(&fdevice->io, W25N01G_STAT_REG) & W25N01G_STATUS_FLAG_BUSY) != 0);
296 return !fdevice->couldBeBusy;
299 static bool w25n01g_waitForReady(flashDevice_t *fdevice)
301 while (!w25n01g_isReady(fdevice)) {
302 uint32_t now = millis();
303 if (cmp32(now, fdevice->timeoutAt) >= 0) {
304 return false;
307 fdevice->timeoutAt = 0;
309 return true;
313 * The flash requires this write enable command to be sent before commands that would cause
314 * a write like program and erase.
316 static void w25n01g_writeEnable(flashDevice_t *fdevice)
318 w25n01g_performOneByteCommand(&fdevice->io, W25N01G_INSTRUCTION_WRITE_ENABLE);
320 // Assume that we're about to do some writing, so the device is just about to become busy
321 fdevice->couldBeBusy = true;
324 const flashVTable_t w25n01g_vTable;
326 bool w25n01g_identify(flashDevice_t *fdevice, uint32_t jedecID)
328 switch (jedecID) {
329 case JEDEC_ID_WINBOND_W25N01GV:
330 fdevice->geometry.sectors = 1024; // Blocks
331 fdevice->geometry.pagesPerSector = 64; // Pages/Blocks
332 fdevice->geometry.pageSize = 2048;
333 break;
335 default:
336 // Unsupported chip
337 fdevice->geometry.sectors = 0;
338 fdevice->geometry.pagesPerSector = 0;
340 fdevice->geometry.sectorSize = 0;
341 fdevice->geometry.totalSize = 0;
342 return false;
345 fdevice->geometry.flashType = FLASH_TYPE_NAND;
346 fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize;
347 fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors;
349 flashPartitionSet(FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT,
350 W25N01G_BB_MANAGEMENT_START_BLOCK,
351 W25N01G_BB_MANAGEMENT_START_BLOCK + W25N01G_BB_MANAGEMENT_BLOCKS - 1);
353 fdevice->couldBeBusy = true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be
354 fdevice->vTable = &w25n01g_vTable;
356 return true;
359 static void w25n01g_deviceInit(flashDevice_t *flashdev);
362 void w25n01g_configure(flashDevice_t *fdevice, uint32_t configurationFlags)
364 if (configurationFlags & FLASH_CF_SYSTEM_IS_MEMORY_MAPPED) {
365 return;
368 w25n01g_deviceReset(fdevice);
370 // Upper 4MB (32 blocks * 128KB/block) will be used for bad block replacement area.
372 // Blocks in this area are only written through bad block LUT,
373 // and factory written bad block marker in unused blocks are retained.
375 // When a replacement block is required,
376 // (1) "Read BB LUT" command is used to obtain the last block mapped,
377 // (2) blocks after the last block is scanned for a good block,
378 // (3) the first good block is used for replacement, and the BB LUT is updated.
380 // There are only 20 BB LUT entries, and there are 32 replacement blocks.
381 // There will be a least chance of running out of replacement blocks.
382 // If it ever run out, the device becomes unusable.
384 if (fdevice->io.mode == FLASHIO_SPI) { // Need to set clock speed for 8kHz logging support with SPI
385 spiSetClkDivisor(fdevice->io.handle.dev, spiCalculateDivider(100000000));
388 w25n01g_deviceInit(fdevice);
392 * Erase a sector full of bytes to all 1's at the given byte offset in the flash chip.
394 void w25n01g_eraseSector(flashDevice_t *fdevice, uint32_t address)
397 w25n01g_waitForReady(fdevice);
399 w25n01g_writeEnable(fdevice);
401 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_BLOCK_ERASE, W25N01G_LINEAR_TO_PAGE(address));
403 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_BLOCK_ERASE_MS);
407 // W25N01G does not support full chip erase.
408 // Call eraseSector repeatedly.
410 void w25n01g_eraseCompletely(flashDevice_t *fdevice)
412 for (uint32_t block = 0; block < fdevice->geometry.sectors; block++) {
413 w25n01g_eraseSector(fdevice, W25N01G_BLOCK_TO_LINEAR(block));
417 #ifdef USE_QUADSPI
418 static void w25n01g_programDataLoad(flashDevice_t *fdevice, uint16_t columnAddress, const uint8_t *data, int length)
421 w25n01g_waitForReady(fdevice);
423 if (fdevice->io.mode == FLASHIO_SPI) {
424 extDevice_t *dev = fdevice->io.handle.dev;
425 uint8_t cmd[] = { W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD, columnAddress >> 8, columnAddress & 0xff };
427 busSegment_t segments[] = {
428 {.u.buffers = {cmd, NULL}, sizeof(cmd), false, NULL},
429 {.u.buffers = {(uint8_t *)data, NULL}, length, true, NULL},
430 {.u.link = {NULL, NULL}, 0, true, NULL},
433 spiSequence(dev, &segments[0]);
435 // Block pending completion of SPI access
436 spiWait(dev);
438 #ifdef USE_QUADSPI
439 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
440 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
442 quadSpiTransmitWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD, 0, columnAddress, W25N01G_STATUS_COLUMN_ADDRESS_SIZE, data, length);
444 #endif
446 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
449 static void w25n01g_randomProgramDataLoad(flashDevice_t *fdevice, uint16_t columnAddress, const uint8_t *data, int length)
451 uint8_t cmd[] = { W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD, columnAddress >> 8, columnAddress & 0xff };
453 w25n01g_waitForReady(fdevice);
455 if (fdevice->io.mode == FLASHIO_SPI) {
456 extDevice_t *dev = fdevice->io.handle.dev;
458 busSegment_t segments[] = {
459 {.u.buffers = {cmd, NULL}, sizeof(cmd), false, NULL},
460 {.u.buffers = {(uint8_t *)data, NULL}, length, true, NULL},
461 {.u.link = {NULL, NULL}, 0, true, NULL},
464 spiSequence(dev, &segments[0]);
466 // Block pending completion of SPI access
467 spiWait(dev);
469 #ifdef USE_QUADSPI
470 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
471 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
473 quadSpiTransmitWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD, 0, columnAddress, W25N01G_STATUS_COLUMN_ADDRESS_SIZE, data, length);
475 #endif
477 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
480 #endif
482 static void w25n01g_programExecute(flashDevice_t *fdevice, uint32_t pageAddress)
484 w25n01g_waitForReady(fdevice);
486 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_PROGRAM_EXECUTE, pageAddress);
488 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
492 // Writes are done in three steps:
493 // (1) Load internal data buffer with data to write
494 // - We use "Random Load Program Data", as "Load Program Data" resets unused data bytes in the buffer to 0xff.
495 // - Each "Random Load Program Data" instruction must be accompanied by at least a single data.
496 // - Each "Random Load Program Data" instruction terminates at the rising of CS.
497 // (2) Enable write
498 // (3) Issue "Execute Program"
502 flashfs page program behavior
503 - Single program never crosses page boundary.
504 - Except for this characteristic, it program arbitral size.
505 - Write address is, naturally, not a page boundary.
507 To cope with this behavior.
509 If buffer is dirty and programLoadAddress != address, then the last page is a partial write;
510 issue PAGE_PROGRAM_EXECUTE to flash buffer contents, clear dirty and record the address as programLoadAddress and programStartAddress.
512 Mark buffer as dirty.
513 If programLoadAddress is on page boundary, then issue PROGRAM_LOAD_DATA, else issue RANDOM_PROGRAM_LOAD_DATA.
514 Update programLoadAddress.
515 Optionally observe the programLoadAddress, and if it's on page boundary, issue PAGE_PROGRAM_EXECUTE.
517 Observe programLoadAddress. If it's on page boundary, issue PAGE_PROGRAM_EXECUTE and clear dirty, else just return.
518 If pageProgramContinue observes the page boundary, then do nothing(?).
521 static uint32_t programStartAddress;
522 static uint32_t programLoadAddress;
523 bool bufferDirty = false;
525 #ifdef USE_QUADSPI
526 bool isProgramming = false;
528 void w25n01g_pageProgramBegin(flashDevice_t *fdevice, uint32_t address, void (*callback)(uint32_t length))
530 fdevice->callback = callback;
532 if (bufferDirty) {
533 if (address != programLoadAddress) {
534 w25n01g_waitForReady(fdevice);
536 isProgramming = false;
538 w25n01g_writeEnable(fdevice);
540 w25n01g_programExecute(fdevice, W25N01G_LINEAR_TO_PAGE(programStartAddress));
542 bufferDirty = false;
543 isProgramming = true;
545 } else {
546 programStartAddress = programLoadAddress = address;
550 uint32_t w25n01g_pageProgramContinue(flashDevice_t *fdevice, uint8_t const **buffers, uint32_t *bufferSizes, uint32_t bufferCount)
552 if (bufferCount < 1) {
553 fdevice->callback(0);
554 return 0;
557 w25n01g_waitForReady(fdevice);
559 w25n01g_writeEnable(fdevice);
561 isProgramming = false;
563 if (!bufferDirty) {
564 w25n01g_programDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), buffers[0], bufferSizes[0]);
565 } else {
566 w25n01g_randomProgramDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), buffers[0], bufferSizes[0]);
569 // XXX Test if write enable is reset after each data loading.
571 bufferDirty = true;
572 programLoadAddress += bufferSizes[0];
574 if (fdevice->callback) {
575 fdevice->callback(bufferSizes[0]);
578 return bufferSizes[0];
581 static uint32_t currentPage = UINT32_MAX;
583 void w25n01g_pageProgramFinish(flashDevice_t *fdevice)
585 if (bufferDirty && W25N01G_LINEAR_TO_COLUMN(programLoadAddress) == 0) {
587 currentPage = W25N01G_LINEAR_TO_PAGE(programStartAddress); // reset page to the page being written
589 w25n01g_programExecute(fdevice, W25N01G_LINEAR_TO_PAGE(programStartAddress));
591 bufferDirty = false;
592 isProgramming = true;
594 programStartAddress = programLoadAddress;
597 #else
598 void w25n01g_pageProgramBegin(flashDevice_t *fdevice, uint32_t address, void (*callback)(uint32_t length))
600 fdevice->callback = callback;
601 fdevice->currentWriteAddress = address;
605 static uint32_t currentPage = UINT32_MAX;
607 // Called in ISR context
608 // Check if the status was busy and if so repeat the poll
609 busStatus_e w25n01g_callbackReady(uint32_t arg)
611 flashDevice_t *fdevice = (flashDevice_t *)arg;
612 extDevice_t *dev = fdevice->io.handle.dev;
614 uint8_t readyPoll = dev->bus->curSegment->u.buffers.rxData[2];
616 if (readyPoll & W25N01G_STATUS_FLAG_BUSY) {
617 return BUS_BUSY;
620 // Bus is now known not to be busy
621 fdevice->couldBeBusy = false;
623 return BUS_READY;
626 // Called in ISR context
627 // A write enable has just been issued
628 busStatus_e w25n01g_callbackWriteEnable(uint32_t arg)
630 flashDevice_t *fdevice = (flashDevice_t *)arg;
632 // As a write has just occurred, the device could be busy
633 fdevice->couldBeBusy = true;
635 return BUS_READY;
638 // Called in ISR context
639 // Write operation has just completed
640 busStatus_e w25n01g_callbackWriteComplete(uint32_t arg)
642 flashDevice_t *fdevice = (flashDevice_t *)arg;
644 fdevice->currentWriteAddress += fdevice->callbackArg;
645 // Call transfer completion callback
646 if (fdevice->callback) {
647 fdevice->callback(fdevice->callbackArg);
650 return BUS_READY;
653 uint32_t w25n01g_pageProgramContinue(flashDevice_t *fdevice, uint8_t const **buffers, uint32_t *bufferSizes, uint32_t bufferCount)
655 if (bufferCount < 1) {
656 fdevice->callback(0);
657 return 0;
660 // The segment list cannot be in automatic storage as this routine is non-blocking
661 STATIC_DMA_DATA_AUTO uint8_t readStatus[] = { W25N01G_INSTRUCTION_READ_STATUS_REG, W25N01G_STAT_REG, 0 };
662 STATIC_DMA_DATA_AUTO uint8_t readyStatus[3];
663 STATIC_DMA_DATA_AUTO uint8_t writeEnable[] = { W25N01G_INSTRUCTION_WRITE_ENABLE };
664 STATIC_DMA_DATA_AUTO uint8_t progExecCmd[] = { W25N01G_INSTRUCTION_PROGRAM_EXECUTE, 0, 0, 0};
665 STATIC_DMA_DATA_AUTO uint8_t progExecDataLoad[] = { W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD, 0, 0};
666 STATIC_DMA_DATA_AUTO uint8_t progRandomProgDataLoad[] = { W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD, 0, 0};
668 static busSegment_t segmentsDataLoad[] = {
669 {.u.buffers = {readStatus, readyStatus}, sizeof(readStatus), true, w25n01g_callbackReady},
670 {.u.buffers = {writeEnable, NULL}, sizeof(writeEnable), true, w25n01g_callbackWriteEnable},
671 {.u.buffers = {progExecDataLoad, NULL}, sizeof(progExecDataLoad), false, NULL},
672 {.u.link = {NULL, NULL}, 0, true, NULL},
675 static busSegment_t segmentsRandomDataLoad[] = {
676 {.u.buffers = {readStatus, readyStatus}, sizeof(readStatus), true, w25n01g_callbackReady},
677 {.u.buffers = {writeEnable, NULL}, sizeof(writeEnable), true, w25n01g_callbackWriteEnable},
678 {.u.buffers = {progRandomProgDataLoad, NULL}, sizeof(progRandomProgDataLoad), false, NULL},
679 {.u.link = {NULL, NULL}, 0, true, NULL},
682 static busSegment_t segmentsBuffer[] = {
683 {.u.buffers = {NULL, NULL}, 0, true, NULL},
684 {.u.link = {NULL, NULL}, 0, true, NULL},
687 static busSegment_t segmentsFlash[] = {
688 {.u.buffers = {readStatus, readyStatus}, sizeof(readStatus), true, w25n01g_callbackReady},
689 {.u.buffers = {writeEnable, NULL}, sizeof(writeEnable), true, w25n01g_callbackWriteEnable},
690 {.u.buffers = {progExecCmd, NULL}, sizeof(progExecCmd), true, w25n01g_callbackWriteComplete},
691 {.u.link = {NULL, NULL}, 0, true, NULL},
694 busSegment_t *programSegment;
696 // Ensure any prior DMA has completed before continuing
697 spiWait(fdevice->io.handle.dev);
699 uint32_t columnAddress;
701 if (bufferDirty) {
702 columnAddress = W25N01G_LINEAR_TO_COLUMN(programLoadAddress);
703 // Set the address and buffer details for the random data load
704 progRandomProgDataLoad[1] = (columnAddress >> 8) & 0xff;
705 progRandomProgDataLoad[2] = columnAddress & 0xff;
706 programSegment = segmentsRandomDataLoad;
707 } else {
708 programStartAddress = programLoadAddress = fdevice->currentWriteAddress;
709 columnAddress = W25N01G_LINEAR_TO_COLUMN(programLoadAddress);
710 // Set the address and buffer details for the data load
711 progExecDataLoad[1] = (columnAddress >> 8) & 0xff;
712 progExecDataLoad[2] = columnAddress & 0xff;
713 programSegment = segmentsDataLoad;
716 // Add the data buffer
717 segmentsBuffer[0].u.buffers.txData = (uint8_t *)buffers[0];
718 segmentsBuffer[0].len = bufferSizes[0];
719 segmentsBuffer[0].callback = NULL;
721 spiLinkSegments(fdevice->io.handle.dev, programSegment, segmentsBuffer);
723 bufferDirty = true;
724 programLoadAddress += bufferSizes[0];
726 if (W25N01G_LINEAR_TO_COLUMN(programLoadAddress) == 0) {
727 // Flash the loaded data
728 currentPage = W25N01G_LINEAR_TO_PAGE(programStartAddress);
730 progExecCmd[2] = (currentPage >> 8) & 0xff;
731 progExecCmd[3] = currentPage & 0xff;
733 spiLinkSegments(fdevice->io.handle.dev, segmentsBuffer, segmentsFlash);
735 bufferDirty = false;
737 programStartAddress = programLoadAddress;
738 } else {
739 // Callback on completion of data load
740 segmentsBuffer[0].callback = w25n01g_callbackWriteComplete;
743 if (!fdevice->couldBeBusy) {
744 // Skip the ready check
745 programSegment++;
748 fdevice->callbackArg = bufferSizes[0];
750 spiSequence(fdevice->io.handle.dev, programSegment);
752 if (fdevice->callback == NULL) {
753 // No callback was provided so block
754 // Block pending completion of SPI access
755 spiWait(fdevice->io.handle.dev);
758 return fdevice->callbackArg;
761 void w25n01g_pageProgramFinish(flashDevice_t *fdevice)
763 UNUSED(fdevice);
765 #endif // USE_QUADSPI
768 * Write bytes to a flash page. Address must not cross a page boundary.
770 * Bits can only be set to zero, not from zero back to one again. In order to set bits to 1, use the erase command.
772 * Length must be smaller than the page size.
774 * This will wait for the flash to become ready before writing begins.
776 * Datasheet indicates typical programming time is 0.8ms for 256 bytes, 0.2ms for 64 bytes, 0.05ms for 16 bytes.
777 * (Although the maximum possible write time is noted as 5ms).
779 * If you want to write multiple buffers (whose sum of sizes is still not more than the page size) then you can
780 * break this operation up into one beginProgram call, one or more continueProgram calls, and one finishProgram call.
783 void w25n01g_pageProgram(flashDevice_t *fdevice, uint32_t address, const uint8_t *data, uint32_t length, void (*callback)(uint32_t length))
785 w25n01g_pageProgramBegin(fdevice, address, callback);
786 w25n01g_pageProgramContinue(fdevice, &data, &length, 1);
787 w25n01g_pageProgramFinish(fdevice);
790 void w25n01g_flush(flashDevice_t *fdevice)
792 if (bufferDirty) {
793 currentPage = W25N01G_LINEAR_TO_PAGE(programStartAddress); // reset page to the page being written
795 w25n01g_programExecute(fdevice, W25N01G_LINEAR_TO_PAGE(programStartAddress));
797 bufferDirty = false;
801 void w25n01g_addError(uint32_t address, uint8_t code)
803 UNUSED(address);
804 UNUSED(code);
808 * Read `length` bytes into the provided `buffer` from the flash starting from the given `address` (which need not lie
809 * on a page boundary).
811 * Waits up to W25N01G_TIMEOUT_PAGE_READ_MS milliseconds for the flash to become ready before reading.
813 * The number of bytes actually read is returned, which can be zero if an error or timeout occurred.
816 // Continuous read mode (BUF = 0):
817 // (1) "Page Data Read" command is executed for the page pointed by address
818 // (2) "Read Data" command is executed for bytes not requested and data are discarded
819 // (3) "Read Data" command is executed and data are stored directly into caller's buffer
821 // Buffered read mode (BUF = 1), non-read ahead
822 // (1) If currentBufferPage != requested page, then issue PAGE_DATA_READ on requested page.
823 // (2) Compute transferLength as smaller of remaining length and requested length.
824 // (3) Issue READ_DATA on column address.
825 // (4) Return transferLength.
827 int w25n01g_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, uint32_t length)
829 uint32_t targetPage = W25N01G_LINEAR_TO_PAGE(address);
831 if (currentPage != targetPage) {
832 if (!w25n01g_waitForReady(fdevice)) {
833 return 0;
836 currentPage = UINT32_MAX;
838 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_PAGE_DATA_READ, targetPage);
840 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_READ_MS);
841 if (!w25n01g_waitForReady(fdevice)) {
842 return 0;
845 currentPage = targetPage;
848 uint32_t column = W25N01G_LINEAR_TO_COLUMN(address);
849 uint16_t transferLength;
851 if (length > W25N01G_PAGE_SIZE - column) {
852 transferLength = W25N01G_PAGE_SIZE - column;
853 } else {
854 transferLength = length;
857 if (fdevice->io.mode == FLASHIO_SPI) {
858 extDevice_t *dev = fdevice->io.handle.dev;
860 uint8_t cmd[4];
861 cmd[0] = W25N01G_INSTRUCTION_READ_DATA;
862 cmd[1] = (column >> 8) & 0xff;
863 cmd[2] = (column >> 0) & 0xff;
864 cmd[3] = 0;
866 busSegment_t segments[] = {
867 {.u.buffers = {cmd, NULL}, sizeof(cmd), false, NULL},
868 {.u.buffers = {NULL, buffer}, length, true, NULL},
869 {.u.link = {NULL, NULL}, 0, true, NULL},
872 spiSequence(dev, &segments[0]);
874 // Block pending completion of SPI access
875 spiWait(dev);
877 #ifdef USE_QUADSPI
878 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
879 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
881 //quadSpiReceiveWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_READ_DATA, 8, column, W25N01G_STATUS_COLUMN_ADDRESS_SIZE, buffer, length);
882 quadSpiReceiveWithAddress4LINES(quadSpi, W25N01G_INSTRUCTION_FAST_READ_QUAD_OUTPUT, 8, column, W25N01G_STATUS_COLUMN_ADDRESS_SIZE, buffer, length);
884 #endif
886 // XXX Don't need this?
887 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_READ_MS);
888 if (!w25n01g_waitForReady(fdevice)) {
889 return 0;
892 // Check ECC
894 uint8_t statReg = w25n01g_readRegister(&fdevice->io, W25N01G_STAT_REG);
895 uint8_t eccCode = W25N01G_STATUS_FLAG_ECC(statReg);
897 switch (eccCode) {
898 case 0: // Successful read, no ECC correction
899 break;
900 case 1: // Successful read with ECC correction
901 case 2: // Uncorrectable ECC in a single page
902 case 3: // Uncorrectable ECC in multiple pages
903 w25n01g_addError(address, eccCode);
904 w25n01g_deviceReset(fdevice);
905 break;
908 return transferLength;
911 int w25n01g_readExtensionBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, int length)
914 if (!w25n01g_waitForReady(fdevice)) {
915 return 0;
918 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_PAGE_DATA_READ, W25N01G_LINEAR_TO_PAGE(address));
920 uint32_t column = 2048;
922 if (fdevice->io.mode == FLASHIO_SPI) {
923 extDevice_t *dev = fdevice->io.handle.dev;
925 uint8_t cmd[4];
926 cmd[0] = W25N01G_INSTRUCTION_READ_DATA;
927 cmd[1] = (column >> 8) & 0xff;
928 cmd[2] = (column >> 0) & 0xff;
929 cmd[3] = 0;
931 busSegment_t segments[] = {
932 {.u.buffers = {cmd, NULL}, sizeof(cmd), false, NULL},
933 {.u.buffers = {NULL, buffer}, length, true, NULL},
934 {.u.link = {NULL, NULL}, 0, true, NULL},
937 // Ensure any prior DMA has completed before continuing
938 spiWait(dev);
940 spiSequence(dev, &segments[0]);
942 // Block pending completion of SPI access
943 spiWait(dev);
946 #ifdef USE_QUADSPI
947 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
948 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
950 quadSpiReceiveWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_READ_DATA, 8, column, W25N01G_STATUS_COLUMN_ADDRESS_SIZE, buffer, length);
952 #endif
954 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_READ_MS);
956 return length;
960 * Fetch information about the detected flash chip layout.
962 * Can be called before calling w25n01g_init() (the result would have totalSize = 0).
964 const flashGeometry_t* w25n01g_getGeometry(flashDevice_t *fdevice)
966 return &fdevice->geometry;
969 const flashVTable_t w25n01g_vTable = {
970 .configure = w25n01g_configure,
971 .isReady = w25n01g_isReady,
972 .waitForReady = w25n01g_waitForReady,
973 .eraseSector = w25n01g_eraseSector,
974 .eraseCompletely = w25n01g_eraseCompletely,
975 .pageProgramBegin = w25n01g_pageProgramBegin,
976 .pageProgramContinue = w25n01g_pageProgramContinue,
977 .pageProgramFinish = w25n01g_pageProgramFinish,
978 .pageProgram = w25n01g_pageProgram,
979 .flush = w25n01g_flush,
980 .readBytes = w25n01g_readBytes,
981 .getGeometry = w25n01g_getGeometry,
984 typedef volatile struct cb_context_s {
985 flashDevice_t *fdevice;
986 bblut_t *bblut;
987 int lutsize;
988 int lutindex;
989 } cb_context_t;
991 // Called in ISR context
992 // Read of BBLUT entry has just completed
993 busStatus_e w25n01g_readBBLUTCallback(uint32_t arg)
995 cb_context_t *cb_context = (cb_context_t *)arg;
996 flashDevice_t *fdevice = cb_context->fdevice;
997 uint8_t *rxData = fdevice->io.handle.dev->bus->curSegment->u.buffers.rxData;
1000 cb_context->bblut->pba = (rxData[0] << 16)|rxData[1];
1001 cb_context->bblut->lba = (rxData[2] << 16)|rxData[3];
1003 if (++cb_context->lutindex < cb_context->lutsize) {
1004 cb_context->bblut++;
1005 return BUS_BUSY; // Repeat the operation
1008 return BUS_READY; // All done
1012 void w25n01g_readBBLUT(flashDevice_t *fdevice, bblut_t *bblut, int lutsize)
1014 cb_context_t cb_context;
1015 uint8_t in[4];
1017 cb_context.fdevice = fdevice;
1018 fdevice->callbackArg = (uint32_t)&cb_context;
1020 if (fdevice->io.mode == FLASHIO_SPI) {
1021 extDevice_t *dev = fdevice->io.handle.dev;
1023 uint8_t cmd[4];
1025 cmd[0] = W25N01G_INSTRUCTION_READ_BBM_LUT;
1026 cmd[1] = 0;
1028 cb_context.bblut = &bblut[0];
1029 cb_context.lutsize = lutsize;
1030 cb_context.lutindex = 0;
1032 busSegment_t segments[] = {
1033 {.u.buffers = {cmd, NULL}, sizeof(cmd), false, NULL},
1034 {.u.buffers = {NULL, in}, sizeof(in), true, w25n01g_readBBLUTCallback},
1035 {.u.link = {NULL, NULL}, 0, true, NULL},
1038 spiSequence(dev, &segments[0]);
1040 // Block pending completion of SPI access
1041 spiWait(dev);
1043 #ifdef USE_QUADSPI
1044 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
1045 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
1047 // Note: Using HAL QuadSPI there doesn't appear to be a way to send 2 bytes, then blocks of 4 bytes, while keeping the CS line LOW
1048 // thus, we have to read the entire BBLUT in one go and process the result.
1050 uint8_t bblutBuffer[W25N01G_BBLUT_TABLE_ENTRY_COUNT * W25N01G_BBLUT_TABLE_ENTRY_SIZE];
1051 quadSpiReceive1LINE(quadSpi, W25N01G_INSTRUCTION_READ_BBM_LUT, 8, bblutBuffer, sizeof(bblutBuffer));
1053 for (int i = 0, offset = 0 ; i < lutsize ; i++, offset += 4) {
1054 if (i < W25N01G_BBLUT_TABLE_ENTRY_COUNT) {
1055 bblut[i].pba = (in[offset + 0] << 16)|in[offset + 1];
1056 bblut[i].lba = (in[offset + 2] << 16)|in[offset + 3];
1060 #endif
1063 void w25n01g_writeBBLUT(flashDevice_t *fdevice, uint16_t lba, uint16_t pba)
1065 w25n01g_waitForReady(fdevice);
1067 if (fdevice->io.mode == FLASHIO_SPI) {
1068 extDevice_t *dev = fdevice->io.handle.dev;
1070 uint8_t cmd[5] = { W25N01G_INSTRUCTION_BB_MANAGEMENT, lba >> 8, lba, pba >> 8, pba };
1072 busSegment_t segments[] = {
1073 {.u.buffers = {cmd, NULL}, sizeof(cmd), true, NULL},
1074 {.u.link = {NULL, NULL}, 0, true, NULL},
1077 // Ensure any prior DMA has completed before continuing
1078 spiWait(dev);
1080 spiSequence(dev, &segments[0]);
1082 // Block pending completion of SPI access
1083 spiWait(dev);
1085 #ifdef USE_QUADSPI
1086 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
1087 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
1089 uint8_t data[4] = { lba >> 8, lba, pba >> 8, pba };
1090 quadSpiInstructionWithData1LINE(quadSpi, W25N01G_INSTRUCTION_BB_MANAGEMENT, 0, data, sizeof(data));
1092 #endif
1094 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
1097 static void w25n01g_deviceInit(flashDevice_t *flashdev)
1099 UNUSED(flashdev);
1101 #endif