New SPI API supporting DMA
[betaflight.git] / src / main / drivers / flash_w25n01g.c
blob96b0a3debbbf9040bf05200fe376ae004c63de8f
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 W28N01G_STATUS_REGISTER_SIZE 8
128 #define W28N01G_STATUS_PAGE_ADDRESS_SIZE 16
129 #define W28N01G_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 {&command, NULL, sizeof (command), true, NULL},
154 {NULL, NULL, 0, true, NULL},
157 // Ensure any prior DMA has completed before continuing
158 spiWait(dev);
160 spiSequence(dev, &segments[0]);
162 // Block pending completion of SPI access
163 spiWait(dev);
165 #ifdef USE_QUADSPI
166 else if (io->mode == FLASHIO_QUADSPI) {
167 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
168 quadSpiTransmit1LINE(quadSpi, command, 0, NULL, 0);
170 #endif
173 static void w25n01g_performCommandWithPageAddress(flashDeviceIO_t *io, uint8_t command, uint32_t pageAddress)
175 if (io->mode == FLASHIO_SPI) {
176 extDevice_t *dev = io->handle.dev;
178 uint8_t cmd[] = { command, 0, (pageAddress >> 8) & 0xff, (pageAddress >> 0) & 0xff};
180 busSegment_t segments[] = {
181 {cmd, NULL, sizeof (cmd), true, NULL},
182 {NULL, NULL, 0, true, NULL},
185 // Ensure any prior DMA has completed before continuing
186 spiWait(dev);
188 spiSequence(dev, &segments[0]);
190 // Block pending completion of SPI access
191 spiWait(dev);
193 #ifdef USE_QUADSPI
194 else if (io->mode == FLASHIO_QUADSPI) {
195 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
197 quadSpiInstructionWithAddress1LINE(quadSpi, command, 0, pageAddress & 0xffff, W28N01G_STATUS_PAGE_ADDRESS_SIZE + 8);
199 #endif
202 static uint8_t w25n01g_readRegister(flashDeviceIO_t *io, uint8_t reg)
204 if (io->mode == FLASHIO_SPI) {
205 extDevice_t *dev = io->handle.dev;
207 uint8_t cmd[3] = { W25N01G_INSTRUCTION_READ_STATUS_REG, reg, 0 };
208 uint8_t in[3];
210 busSegment_t segments[] = {
211 {cmd, in, sizeof (cmd), true, NULL},
212 {NULL, NULL, 0, true, NULL},
215 // Ensure any prior DMA has completed before continuing
216 spiWait(dev);
218 spiSequence(dev, &segments[0]);
220 // Block pending completion of SPI access
221 spiWait(dev);
223 return in[2];
225 #ifdef USE_QUADSPI
226 else if (io->mode == FLASHIO_QUADSPI) {
228 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
230 uint8_t in[1];
231 quadSpiReceiveWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_READ_STATUS_REG, 0, reg, W28N01G_STATUS_REGISTER_SIZE, in, sizeof(in));
233 return in[0];
235 #endif
236 return 0;
239 static void w25n01g_writeRegister(flashDeviceIO_t *io, uint8_t reg, uint8_t data)
241 if (io->mode == FLASHIO_SPI) {
242 extDevice_t *dev = io->handle.dev;
243 uint8_t cmd[3] = { W25N01G_INSTRUCTION_WRITE_STATUS_REG, reg, data };
245 busSegment_t segments[] = {
246 {cmd, NULL, sizeof (cmd), true, NULL},
247 {NULL, NULL, 0, true, NULL},
250 // Ensure any prior DMA has completed before continuing
251 spiWait(dev);
253 spiSequence(dev, &segments[0]);
255 // Block pending completion of SPI access
256 spiWait(dev);
258 #ifdef USE_QUADSPI
259 else if (io->mode == FLASHIO_QUADSPI) {
260 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
262 quadSpiTransmitWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_WRITE_STATUS_REG, 0, reg, W28N01G_STATUS_REGISTER_SIZE, &data, 1);
264 #endif
268 static void w25n01g_deviceReset(flashDevice_t *fdevice)
270 flashDeviceIO_t *io = &fdevice->io;
272 w25n01g_performOneByteCommand(io, W25N01G_INSTRUCTION_DEVICE_RESET);
274 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_RESET_MS);
275 w25n01g_waitForReady(fdevice);
277 // Protection for upper 1/32 (BP[3:0] = 0101, TB=0), WP-E on; to protect bad block replacement area
278 // DON'T DO THIS. This will prevent writes through the bblut as well.
279 // w25n01g_writeRegister(dev, W25N01G_PROT_REG, W25N01G_PROT_PB0_ENABLE|W25N01G_PROT_PB2_ENABLE|W25N01G_PROT_WP_E_ENABLE);
281 // No protection, WP-E off, WP-E prevents use of IO2
282 w25n01g_writeRegister(io, W25N01G_PROT_REG, W25N01G_PROT_CLEAR);
284 // Buffered read mode (BUF = 1), ECC enabled (ECC = 1)
285 w25n01g_writeRegister(io, W25N01G_CONF_REG, W25N01G_CONFIG_ECC_ENABLE|W25N01G_CONFIG_BUFFER_READ_MODE);
288 bool w25n01g_isReady(flashDevice_t *fdevice)
290 uint8_t status = w25n01g_readRegister(&fdevice->io, W25N01G_STAT_REG);
292 return ((status & W25N01G_STATUS_FLAG_BUSY) == 0);
295 static bool w25n01g_waitForReady(flashDevice_t *fdevice)
297 while (!w25n01g_isReady(fdevice)) {
298 uint32_t now = millis();
299 if (cmp32(now, fdevice->timeoutAt) >= 0) {
300 return false;
303 fdevice->timeoutAt = 0;
305 return true;
309 * The flash requires this write enable command to be sent before commands that would cause
310 * a write like program and erase.
312 static void w25n01g_writeEnable(flashDevice_t *fdevice)
314 w25n01g_performOneByteCommand(&fdevice->io, W25N01G_INSTRUCTION_WRITE_ENABLE);
316 // Assume that we're about to do some writing, so the device is just about to become busy
317 fdevice->couldBeBusy = true;
321 * Read chip identification and geometry information (into global `geometry`).
323 * Returns true if we get valid ident, false if something bad happened like there is no M25P16.
325 const flashVTable_t w25n01g_vTable;
327 static void w25n01g_deviceInit(flashDevice_t *flashdev);
329 bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID)
331 switch (chipID) {
332 case JEDEC_ID_WINBOND_W25N01GV:
333 fdevice->geometry.sectors = 1024; // Blocks
334 fdevice->geometry.pagesPerSector = 64; // Pages/Blocks
335 fdevice->geometry.pageSize = 2048;
336 break;
338 default:
339 // Unsupported chip
340 fdevice->geometry.sectors = 0;
341 fdevice->geometry.pagesPerSector = 0;
343 fdevice->geometry.sectorSize = 0;
344 fdevice->geometry.totalSize = 0;
345 return false;
348 fdevice->geometry.flashType = FLASH_TYPE_NAND;
349 fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize;
350 fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors;
352 flashPartitionSet(FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT,
353 W25N01G_BB_MANAGEMENT_START_BLOCK,
354 W25N01G_BB_MANAGEMENT_START_BLOCK + W25N01G_BB_MANAGEMENT_BLOCKS - 1);
356 fdevice->couldBeBusy = true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be
358 w25n01g_deviceReset(fdevice);
360 // Upper 4MB (32 blocks * 128KB/block) will be used for bad block replacement area.
362 // Blocks in this area are only written through bad block LUT,
363 // and factory written bad block marker in unused blocks are retained.
365 // When a replacement block is required,
366 // (1) "Read BB LUT" command is used to obtain the last block mapped,
367 // (2) blocks after the last block is scanned for a good block,
368 // (3) the first good block is used for replacement, and the BB LUT is updated.
370 // There are only 20 BB LUT entries, and there are 32 replacement blocks.
371 // There will be a least chance of running out of replacement blocks.
372 // If it ever run out, the device becomes unusable.
374 w25n01g_deviceInit(fdevice);
376 fdevice->vTable = &w25n01g_vTable;
378 return true;
382 * Erase a sector full of bytes to all 1's at the given byte offset in the flash chip.
384 void w25n01g_eraseSector(flashDevice_t *fdevice, uint32_t address)
387 w25n01g_waitForReady(fdevice);
389 w25n01g_writeEnable(fdevice);
391 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_BLOCK_ERASE, W25N01G_LINEAR_TO_PAGE(address));
393 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_BLOCK_ERASE_MS);
397 // W25N01G does not support full chip erase.
398 // Call eraseSector repeatedly.
400 void w25n01g_eraseCompletely(flashDevice_t *fdevice)
402 for (uint32_t block = 0; block < fdevice->geometry.sectors; block++) {
403 w25n01g_eraseSector(fdevice, W25N01G_BLOCK_TO_LINEAR(block));
407 static void w25n01g_programDataLoad(flashDevice_t *fdevice, uint16_t columnAddress, const uint8_t *data, int length)
410 w25n01g_waitForReady(fdevice);
412 if (fdevice->io.mode == FLASHIO_SPI) {
413 extDevice_t *dev = fdevice->io.handle.dev;
414 uint8_t cmd[] = { W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD, columnAddress >> 8, columnAddress & 0xff };
416 busSegment_t segments[] = {
417 {cmd, NULL, sizeof (cmd), true, NULL},
418 {(uint8_t *)data, NULL, length, true, NULL},
419 {NULL, NULL, 0, true, NULL},
422 // Ensure any prior DMA has completed before continuing
423 spiWait(dev);
425 spiSequence(dev, &segments[0]);
427 // Block pending completion of SPI access
428 spiWait(dev);
430 #ifdef USE_QUADSPI
431 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
432 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
434 quadSpiTransmitWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD, 0, columnAddress, W28N01G_STATUS_COLUMN_ADDRESS_SIZE, data, length);
436 #endif
438 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
441 static void w25n01g_randomProgramDataLoad(flashDevice_t *fdevice, uint16_t columnAddress, const uint8_t *data, int length)
443 uint8_t cmd[] = { W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD, columnAddress >> 8, columnAddress & 0xff };
445 w25n01g_waitForReady(fdevice);
447 if (fdevice->io.mode == FLASHIO_SPI) {
448 extDevice_t *dev = fdevice->io.handle.dev;
450 busSegment_t segments[] = {
451 {cmd, NULL, sizeof (cmd), true, NULL},
452 {(uint8_t *)data, NULL, length, true, NULL},
453 {NULL, NULL, 0, true, NULL},
456 // Ensure any prior DMA has completed before continuing
457 spiWait(dev);
459 spiSequence(dev, &segments[0]);
461 // Block pending completion of SPI access
462 spiWait(dev);
464 #ifdef USE_QUADSPI
465 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
466 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
468 quadSpiTransmitWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD, 0, columnAddress, W28N01G_STATUS_COLUMN_ADDRESS_SIZE, data, length);
470 #endif
472 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
476 static void w25n01g_programExecute(flashDevice_t *fdevice, uint32_t pageAddress)
478 w25n01g_waitForReady(fdevice);
480 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_PROGRAM_EXECUTE, pageAddress);
482 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
486 // Writes are done in three steps:
487 // (1) Load internal data buffer with data to write
488 // - We use "Random Load Program Data", as "Load Program Data" resets unused data bytes in the buffer to 0xff.
489 // - Each "Random Load Program Data" instruction must be accompanied by at least a single data.
490 // - Each "Random Load Program Data" instruction terminates at the rising of CS.
491 // (2) Enable write
492 // (3) Issue "Execute Program"
496 flashfs page program behavior
497 - Single program never crosses page boundary.
498 - Except for this characteristic, it program arbitral size.
499 - Write address is, naturally, not a page boundary.
501 To cope with this behavior.
503 pageProgramBegin:
504 If buffer is dirty and programLoadAddress != address, then the last page is a partial write;
505 issue PAGE_PROGRAM_EXECUTE to flash buffer contents, clear dirty and record the address as programLoadAddress and programStartAddress.
506 Else do nothing.
508 pageProgramContinue:
509 Mark buffer as dirty.
510 If programLoadAddress is on page boundary, then issue PROGRAM_LOAD_DATA, else issue RANDOM_PROGRAM_LOAD_DATA.
511 Update programLoadAddress.
512 Optionally observe the programLoadAddress, and if it's on page boundary, issue PAGE_PROGRAM_EXECUTE.
514 pageProgramFinish:
515 Observe programLoadAddress. If it's on page boundary, issue PAGE_PROGRAM_EXECUTE and clear dirty, else just return.
516 If pageProgramContinue observes the page boundary, then do nothing(?).
519 static uint32_t programStartAddress;
520 static uint32_t programLoadAddress;
521 bool bufferDirty = false;
522 bool isProgramming = false;
524 void w25n01g_pageProgramBegin(flashDevice_t *fdevice, uint32_t address)
526 if (bufferDirty) {
527 if (address != programLoadAddress) {
528 w25n01g_waitForReady(fdevice);
530 isProgramming = false;
532 w25n01g_writeEnable(fdevice);
534 w25n01g_programExecute(fdevice, W25N01G_LINEAR_TO_PAGE(programStartAddress));
536 bufferDirty = false;
537 isProgramming = true;
539 } else {
540 programStartAddress = programLoadAddress = address;
544 void w25n01g_pageProgramContinue(flashDevice_t *fdevice, const uint8_t *data, int length)
546 w25n01g_waitForReady(fdevice);
548 w25n01g_writeEnable(fdevice);
550 isProgramming = false;
552 if (!bufferDirty) {
553 w25n01g_programDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), data, length);
554 } else {
555 w25n01g_randomProgramDataLoad(fdevice, W25N01G_LINEAR_TO_COLUMN(programLoadAddress), data, length);
558 // XXX Test if write enable is reset after each data loading.
560 bufferDirty = true;
561 programLoadAddress += length;
564 static uint32_t currentPage = UINT32_MAX;
566 void w25n01g_pageProgramFinish(flashDevice_t *fdevice)
568 if (bufferDirty && W25N01G_LINEAR_TO_COLUMN(programLoadAddress) == 0) {
570 currentPage = W25N01G_LINEAR_TO_PAGE(programStartAddress); // reset page to the page being written
572 w25n01g_programExecute(fdevice, W25N01G_LINEAR_TO_PAGE(programStartAddress));
574 bufferDirty = false;
575 isProgramming = true;
577 programStartAddress = programLoadAddress;
582 * Write bytes to a flash page. Address must not cross a page boundary.
584 * 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.
586 * Length must be smaller than the page size.
588 * This will wait for the flash to become ready before writing begins.
590 * Datasheet indicates typical programming time is 0.8ms for 256 bytes, 0.2ms for 64 bytes, 0.05ms for 16 bytes.
591 * (Although the maximum possible write time is noted as 5ms).
593 * If you want to write multiple buffers (whose sum of sizes is still not more than the page size) then you can
594 * break this operation up into one beginProgram call, one or more continueProgram calls, and one finishProgram call.
597 void w25n01g_pageProgram(flashDevice_t *fdevice, uint32_t address, const uint8_t *data, int length)
599 w25n01g_pageProgramBegin(fdevice, address);
600 w25n01g_pageProgramContinue(fdevice, data, length);
601 w25n01g_pageProgramFinish(fdevice);
604 void w25n01g_flush(flashDevice_t *fdevice)
606 if (bufferDirty) {
607 currentPage = W25N01G_LINEAR_TO_PAGE(programStartAddress); // reset page to the page being written
609 w25n01g_programExecute(fdevice, W25N01G_LINEAR_TO_PAGE(programStartAddress));
611 bufferDirty = false;
612 isProgramming = true;
613 } else {
614 isProgramming = false;
618 void w25n01g_addError(uint32_t address, uint8_t code)
620 UNUSED(address);
621 UNUSED(code);
625 * Read `length` bytes into the provided `buffer` from the flash starting from the given `address` (which need not lie
626 * on a page boundary).
628 * Waits up to W25N01G_TIMEOUT_PAGE_READ_MS milliseconds for the flash to become ready before reading.
630 * The number of bytes actually read is returned, which can be zero if an error or timeout occurred.
633 // Continuous read mode (BUF = 0):
634 // (1) "Page Data Read" command is executed for the page pointed by address
635 // (2) "Read Data" command is executed for bytes not requested and data are discarded
636 // (3) "Read Data" command is executed and data are stored directly into caller's buffer
638 // Buffered read mode (BUF = 1), non-read ahead
639 // (1) If currentBufferPage != requested page, then issue PAGE_DATA_READ on requested page.
640 // (2) Compute transferLength as smaller of remaining length and requested length.
641 // (3) Issue READ_DATA on column address.
642 // (4) Return transferLength.
644 int w25n01g_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, int length)
646 uint32_t targetPage = W25N01G_LINEAR_TO_PAGE(address);
648 if (currentPage != targetPage) {
649 if (!w25n01g_waitForReady(fdevice)) {
650 return 0;
653 currentPage = UINT32_MAX;
655 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_PAGE_DATA_READ, targetPage);
657 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_READ_MS);
658 if (!w25n01g_waitForReady(fdevice)) {
659 return 0;
662 currentPage = targetPage;
665 int column = W25N01G_LINEAR_TO_COLUMN(address);
666 uint16_t transferLength;
668 if (length > W25N01G_PAGE_SIZE - column) {
669 transferLength = W25N01G_PAGE_SIZE - column;
670 } else {
671 transferLength = length;
674 if (fdevice->io.mode == FLASHIO_SPI) {
675 extDevice_t *dev = fdevice->io.handle.dev;
677 uint8_t cmd[4];
678 cmd[0] = W25N01G_INSTRUCTION_READ_DATA;
679 cmd[1] = (column >> 8) & 0xff;
680 cmd[2] = (column >> 0) & 0xff;
681 cmd[3] = 0;
683 busSegment_t segments[] = {
684 {cmd, NULL, sizeof (cmd), false, NULL},
685 {NULL, buffer, length, true, NULL},
686 {NULL, NULL, 0, true, NULL},
689 // Ensure any prior DMA has completed before continuing
690 spiWait(dev);
692 spiSequence(dev, &segments[0]);
694 // Block pending completion of SPI access
695 spiWait(dev);
697 #ifdef USE_QUADSPI
698 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
699 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
701 //quadSpiReceiveWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_READ_DATA, 8, column, W28N01G_STATUS_COLUMN_ADDRESS_SIZE, buffer, length);
702 quadSpiReceiveWithAddress4LINES(quadSpi, W25N01G_INSTRUCTION_FAST_READ_QUAD_OUTPUT, 8, column, W28N01G_STATUS_COLUMN_ADDRESS_SIZE, buffer, length);
704 #endif
706 // XXX Don't need this?
707 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_READ_MS);
708 if (!w25n01g_waitForReady(fdevice)) {
709 return 0;
712 // Check ECC
714 uint8_t statReg = w25n01g_readRegister(&fdevice->io, W25N01G_STAT_REG);
715 uint8_t eccCode = W25N01G_STATUS_FLAG_ECC(statReg);
717 switch (eccCode) {
718 case 0: // Successful read, no ECC correction
719 break;
720 case 1: // Successful read with ECC correction
721 case 2: // Uncorrectable ECC in a single page
722 case 3: // Uncorrectable ECC in multiple pages
723 w25n01g_addError(address, eccCode);
724 w25n01g_deviceReset(fdevice);
725 break;
728 return transferLength;
731 int w25n01g_readExtensionBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, int length)
734 if (!w25n01g_waitForReady(fdevice)) {
735 return 0;
738 w25n01g_performCommandWithPageAddress(&fdevice->io, W25N01G_INSTRUCTION_PAGE_DATA_READ, W25N01G_LINEAR_TO_PAGE(address));
740 uint32_t column = 2048;
742 if (fdevice->io.mode == FLASHIO_SPI) {
743 extDevice_t *dev = fdevice->io.handle.dev;
745 uint8_t cmd[4];
746 cmd[0] = W25N01G_INSTRUCTION_READ_DATA;
747 cmd[1] = (column >> 8) & 0xff;
748 cmd[2] = (column >> 0) & 0xff;
749 cmd[3] = 0;
751 busSegment_t segments[] = {
752 {cmd, NULL, sizeof (cmd), false, NULL},
753 {NULL, buffer, length, true, NULL},
754 {NULL, NULL, 0, true, NULL},
757 // Ensure any prior DMA has completed before continuing
758 spiWait(dev);
760 spiSequence(dev, &segments[0]);
762 // Block pending completion of SPI access
763 spiWait(dev);
766 #ifdef USE_QUADSPI
767 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
768 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
770 quadSpiReceiveWithAddress1LINE(quadSpi, W25N01G_INSTRUCTION_READ_DATA, 8, column, W28N01G_STATUS_COLUMN_ADDRESS_SIZE, buffer, length);
772 #endif
774 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_READ_MS);
776 return length;
780 * Fetch information about the detected flash chip layout.
782 * Can be called before calling w25n01g_init() (the result would have totalSize = 0).
784 const flashGeometry_t* w25n01g_getGeometry(flashDevice_t *fdevice)
786 return &fdevice->geometry;
789 const flashVTable_t w25n01g_vTable = {
790 .isReady = w25n01g_isReady,
791 .waitForReady = w25n01g_waitForReady,
792 .eraseSector = w25n01g_eraseSector,
793 .eraseCompletely = w25n01g_eraseCompletely,
794 .pageProgramBegin = w25n01g_pageProgramBegin,
795 .pageProgramContinue = w25n01g_pageProgramContinue,
796 .pageProgramFinish = w25n01g_pageProgramFinish,
797 .pageProgram = w25n01g_pageProgram,
798 .flush = w25n01g_flush,
799 .readBytes = w25n01g_readBytes,
800 .getGeometry = w25n01g_getGeometry,
803 void w25n01g_readBBLUT(flashDevice_t *fdevice, bblut_t *bblut, int lutsize)
805 uint8_t in[4];
807 if (fdevice->io.mode == FLASHIO_SPI) {
808 extDevice_t *dev = fdevice->io.handle.dev;
810 uint8_t cmd[4];
812 cmd[0] = W25N01G_INSTRUCTION_READ_BBM_LUT;
813 cmd[1] = 0;
815 busSegment_t segments[] = {
816 {cmd, NULL, sizeof (cmd), false, NULL},
817 {NULL, in, sizeof (in), true, NULL},
818 {NULL, NULL, 0, true, NULL},
821 // Ensure any prior DMA has completed before continuing
822 spiWait(dev);
824 spiSequence(dev, &segments[0]);
826 // Block pending completion of SPI access
827 spiWait(dev);
829 for (int i = 0 ; i < lutsize ; i++) {
830 spiReadWriteBuf(dev, NULL, in, 4);
831 bblut[i].pba = (in[0] << 16)|in[1];
832 bblut[i].lba = (in[2] << 16)|in[3];
835 #ifdef USE_QUADSPI
836 else if (fdevice->io.mode == FLASHIO_QUADSPI) {
837 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
839 // 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
840 // thus, we have to read the entire BBLUT in one go and process the result.
842 uint8_t bblutBuffer[W25N01G_BBLUT_TABLE_ENTRY_COUNT * W25N01G_BBLUT_TABLE_ENTRY_SIZE];
843 quadSpiReceive1LINE(quadSpi, W25N01G_INSTRUCTION_READ_BBM_LUT, 8, bblutBuffer, sizeof(bblutBuffer));
845 for (int i = 0, offset = 0 ; i < lutsize ; i++, offset += 4) {
846 if (i < W25N01G_BBLUT_TABLE_ENTRY_COUNT) {
847 bblut[i].pba = (in[offset + 0] << 16)|in[offset + 1];
848 bblut[i].lba = (in[offset + 2] << 16)|in[offset + 3];
852 #endif
855 void w25n01g_writeBBLUT(flashDevice_t *fdevice, uint16_t lba, uint16_t pba)
857 w25n01g_waitForReady(fdevice);
859 if (fdevice->io.mode == FLASHIO_SPI) {
860 extDevice_t *dev = fdevice->io.handle.dev;
862 uint8_t cmd[5] = { W25N01G_INSTRUCTION_BB_MANAGEMENT, lba >> 8, lba, pba >> 8, pba };
864 busSegment_t segments[] = {
865 {cmd, NULL, sizeof (cmd), true, NULL},
866 {NULL, NULL, 0, true, NULL},
869 // Ensure any prior DMA has completed before continuing
870 spiWait(dev);
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 uint8_t data[4] = { lba >> 8, lba, pba >> 8, pba };
882 quadSpiInstructionWithData1LINE(quadSpi, W25N01G_INSTRUCTION_BB_MANAGEMENT, 0, data, sizeof(data));
884 #endif
886 w25n01g_setTimeout(fdevice, W25N01G_TIMEOUT_PAGE_PROGRAM_MS);
889 static void w25n01g_deviceInit(flashDevice_t *flashdev)
891 UNUSED(flashdev);
893 #endif