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)
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/>.
28 #ifdef USE_FLASH_W25N01G
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)
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
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
{
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
163 else if (io
->mode
== FLASHIO_QUADSPI
) {
164 QUADSPI_TypeDef
*quadSpi
= io
->handle
.quadSpi
;
165 quadSpiTransmit1LINE(quadSpi
, command
, 0, NULL
, 0);
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
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);
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 };
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
212 spiSequence(dev
, &segments
[0]);
214 // Block pending completion of SPI access
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
));
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
247 spiSequence(dev
, &segments
[0]);
249 // Block pending completion of SPI access
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);
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 uint8_t status
= w25n01g_readRegister(&fdevice
->io
, W25N01G_STAT_REG
);
286 return ((status
& W25N01G_STATUS_FLAG_BUSY
) == 0);
289 static bool w25n01g_waitForReady(flashDevice_t
*fdevice
)
291 while (!w25n01g_isReady(fdevice
)) {
292 uint32_t now
= millis();
293 if (cmp32(now
, fdevice
->timeoutAt
) >= 0) {
297 fdevice
->timeoutAt
= 0;
303 * The flash requires this write enable command to be sent before commands that would cause
304 * a write like program and erase.
306 static void w25n01g_writeEnable(flashDevice_t
*fdevice
)
308 w25n01g_performOneByteCommand(&fdevice
->io
, W25N01G_INSTRUCTION_WRITE_ENABLE
);
310 // Assume that we're about to do some writing, so the device is just about to become busy
311 fdevice
->couldBeBusy
= true;
314 const flashVTable_t w25n01g_vTable
;
316 bool w25n01g_identify(flashDevice_t
*fdevice
, uint32_t jedecID
)
319 case JEDEC_ID_WINBOND_W25N01GV
:
320 fdevice
->geometry
.sectors
= 1024; // Blocks
321 fdevice
->geometry
.pagesPerSector
= 64; // Pages/Blocks
322 fdevice
->geometry
.pageSize
= 2048;
327 fdevice
->geometry
.sectors
= 0;
328 fdevice
->geometry
.pagesPerSector
= 0;
330 fdevice
->geometry
.sectorSize
= 0;
331 fdevice
->geometry
.totalSize
= 0;
335 fdevice
->geometry
.flashType
= FLASH_TYPE_NAND
;
336 fdevice
->geometry
.sectorSize
= fdevice
->geometry
.pagesPerSector
* fdevice
->geometry
.pageSize
;
337 fdevice
->geometry
.totalSize
= fdevice
->geometry
.sectorSize
* fdevice
->geometry
.sectors
;
339 flashPartitionSet(FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT
,
340 W25N01G_BB_MANAGEMENT_START_BLOCK
,
341 W25N01G_BB_MANAGEMENT_START_BLOCK
+ W25N01G_BB_MANAGEMENT_BLOCKS
- 1);
343 fdevice
->couldBeBusy
= true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be
344 fdevice
->vTable
= &w25n01g_vTable
;
349 static void w25n01g_deviceInit(flashDevice_t
*flashdev
);
352 void w25n01g_configure(flashDevice_t
*fdevice
, uint32_t configurationFlags
)
354 if (configurationFlags
& FLASH_CF_SYSTEM_IS_MEMORY_MAPPED
) {
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
);
378 * Erase a sector full of bytes to all 1's at the given byte offset in the flash chip.
380 void w25n01g_eraseSector(flashDevice_t
*fdevice
, uint32_t address
)
383 w25n01g_waitForReady(fdevice
);
385 w25n01g_writeEnable(fdevice
);
387 w25n01g_performCommandWithPageAddress(&fdevice
->io
, W25N01G_INSTRUCTION_BLOCK_ERASE
, W25N01G_LINEAR_TO_PAGE(address
));
389 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_BLOCK_ERASE_MS
);
393 // W25N01G does not support full chip erase.
394 // Call eraseSector repeatedly.
396 void w25n01g_eraseCompletely(flashDevice_t
*fdevice
)
398 for (uint32_t block
= 0; block
< fdevice
->geometry
.sectors
; block
++) {
399 w25n01g_eraseSector(fdevice
, W25N01G_BLOCK_TO_LINEAR(block
));
403 static void w25n01g_programDataLoad(flashDevice_t
*fdevice
, uint16_t columnAddress
, const uint8_t *data
, int length
)
406 w25n01g_waitForReady(fdevice
);
408 if (fdevice
->io
.mode
== FLASHIO_SPI
) {
409 extDevice_t
*dev
= fdevice
->io
.handle
.dev
;
410 uint8_t cmd
[] = { W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD
, columnAddress
>> 8, columnAddress
& 0xff };
412 busSegment_t segments
[] = {
413 {.u
.buffers
= {cmd
, NULL
}, sizeof(cmd
), false, NULL
},
414 {.u
.buffers
= {(uint8_t *)data
, NULL
}, length
, true, NULL
},
415 {.u
.link
= {NULL
, NULL
}, 0, true, NULL
},
418 spiSequence(dev
, &segments
[0]);
420 // Block pending completion of SPI access
424 else if (fdevice
->io
.mode
== FLASHIO_QUADSPI
) {
425 QUADSPI_TypeDef
*quadSpi
= fdevice
->io
.handle
.quadSpi
;
427 quadSpiTransmitWithAddress1LINE(quadSpi
, W25N01G_INSTRUCTION_PROGRAM_DATA_LOAD
, 0, columnAddress
, W25N01G_STATUS_COLUMN_ADDRESS_SIZE
, data
, length
);
431 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_PAGE_PROGRAM_MS
);
434 static void w25n01g_randomProgramDataLoad(flashDevice_t
*fdevice
, uint16_t columnAddress
, const uint8_t *data
, int length
)
436 uint8_t cmd
[] = { W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD
, columnAddress
>> 8, columnAddress
& 0xff };
438 w25n01g_waitForReady(fdevice
);
440 if (fdevice
->io
.mode
== FLASHIO_SPI
) {
441 extDevice_t
*dev
= fdevice
->io
.handle
.dev
;
443 busSegment_t segments
[] = {
444 {.u
.buffers
= {cmd
, NULL
}, sizeof(cmd
), false, NULL
},
445 {.u
.buffers
= {(uint8_t *)data
, NULL
}, length
, true, NULL
},
446 {.u
.link
= {NULL
, NULL
}, 0, true, NULL
},
449 spiSequence(dev
, &segments
[0]);
451 // Block pending completion of SPI access
455 else if (fdevice
->io
.mode
== FLASHIO_QUADSPI
) {
456 QUADSPI_TypeDef
*quadSpi
= fdevice
->io
.handle
.quadSpi
;
458 quadSpiTransmitWithAddress1LINE(quadSpi
, W25N01G_INSTRUCTION_RANDOM_PROGRAM_DATA_LOAD
, 0, columnAddress
, W25N01G_STATUS_COLUMN_ADDRESS_SIZE
, data
, length
);
462 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_PAGE_PROGRAM_MS
);
466 static void w25n01g_programExecute(flashDevice_t
*fdevice
, uint32_t pageAddress
)
468 w25n01g_waitForReady(fdevice
);
470 w25n01g_performCommandWithPageAddress(&fdevice
->io
, W25N01G_INSTRUCTION_PROGRAM_EXECUTE
, pageAddress
);
472 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_PAGE_PROGRAM_MS
);
476 // Writes are done in three steps:
477 // (1) Load internal data buffer with data to write
478 // - We use "Random Load Program Data", as "Load Program Data" resets unused data bytes in the buffer to 0xff.
479 // - Each "Random Load Program Data" instruction must be accompanied by at least a single data.
480 // - Each "Random Load Program Data" instruction terminates at the rising of CS.
482 // (3) Issue "Execute Program"
486 flashfs page program behavior
487 - Single program never crosses page boundary.
488 - Except for this characteristic, it program arbitral size.
489 - Write address is, naturally, not a page boundary.
491 To cope with this behavior.
494 If buffer is dirty and programLoadAddress != address, then the last page is a partial write;
495 issue PAGE_PROGRAM_EXECUTE to flash buffer contents, clear dirty and record the address as programLoadAddress and programStartAddress.
499 Mark buffer as dirty.
500 If programLoadAddress is on page boundary, then issue PROGRAM_LOAD_DATA, else issue RANDOM_PROGRAM_LOAD_DATA.
501 Update programLoadAddress.
502 Optionally observe the programLoadAddress, and if it's on page boundary, issue PAGE_PROGRAM_EXECUTE.
505 Observe programLoadAddress. If it's on page boundary, issue PAGE_PROGRAM_EXECUTE and clear dirty, else just return.
506 If pageProgramContinue observes the page boundary, then do nothing(?).
509 static uint32_t programStartAddress
;
510 static uint32_t programLoadAddress
;
511 bool bufferDirty
= false;
512 bool isProgramming
= false;
514 void w25n01g_pageProgramBegin(flashDevice_t
*fdevice
, uint32_t address
, void (*callback
)(uint32_t length
))
516 fdevice
->callback
= callback
;
519 if (address
!= programLoadAddress
) {
520 w25n01g_waitForReady(fdevice
);
522 isProgramming
= false;
524 w25n01g_writeEnable(fdevice
);
526 w25n01g_programExecute(fdevice
, W25N01G_LINEAR_TO_PAGE(programStartAddress
));
529 isProgramming
= true;
532 programStartAddress
= programLoadAddress
= address
;
536 uint32_t w25n01g_pageProgramContinue(flashDevice_t
*fdevice
, uint8_t const **buffers
, uint32_t *bufferSizes
, uint32_t bufferCount
)
538 if (bufferCount
< 1) {
539 fdevice
->callback(0);
543 w25n01g_waitForReady(fdevice
);
545 w25n01g_writeEnable(fdevice
);
547 isProgramming
= false;
550 w25n01g_programDataLoad(fdevice
, W25N01G_LINEAR_TO_COLUMN(programLoadAddress
), buffers
[0], bufferSizes
[0]);
552 w25n01g_randomProgramDataLoad(fdevice
, W25N01G_LINEAR_TO_COLUMN(programLoadAddress
), buffers
[0], bufferSizes
[0]);
555 // XXX Test if write enable is reset after each data loading.
558 programLoadAddress
+= bufferSizes
[0];
560 if (fdevice
->callback
) {
561 fdevice
->callback(bufferSizes
[0]);
564 return bufferSizes
[0];
567 static uint32_t currentPage
= UINT32_MAX
;
569 void w25n01g_pageProgramFinish(flashDevice_t
*fdevice
)
571 if (bufferDirty
&& W25N01G_LINEAR_TO_COLUMN(programLoadAddress
) == 0) {
573 currentPage
= W25N01G_LINEAR_TO_PAGE(programStartAddress
); // reset page to the page being written
575 w25n01g_programExecute(fdevice
, W25N01G_LINEAR_TO_PAGE(programStartAddress
));
578 isProgramming
= true;
580 programStartAddress
= programLoadAddress
;
585 * Write bytes to a flash page. Address must not cross a page boundary.
587 * 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.
589 * Length must be smaller than the page size.
591 * This will wait for the flash to become ready before writing begins.
593 * Datasheet indicates typical programming time is 0.8ms for 256 bytes, 0.2ms for 64 bytes, 0.05ms for 16 bytes.
594 * (Although the maximum possible write time is noted as 5ms).
596 * If you want to write multiple buffers (whose sum of sizes is still not more than the page size) then you can
597 * break this operation up into one beginProgram call, one or more continueProgram calls, and one finishProgram call.
600 void w25n01g_pageProgram(flashDevice_t
*fdevice
, uint32_t address
, const uint8_t *data
, uint32_t length
, void (*callback
)(uint32_t length
))
602 w25n01g_pageProgramBegin(fdevice
, address
, callback
);
603 w25n01g_pageProgramContinue(fdevice
, &data
, &length
, 1);
604 w25n01g_pageProgramFinish(fdevice
);
607 void w25n01g_flush(flashDevice_t
*fdevice
)
610 currentPage
= W25N01G_LINEAR_TO_PAGE(programStartAddress
); // reset page to the page being written
612 w25n01g_programExecute(fdevice
, W25N01G_LINEAR_TO_PAGE(programStartAddress
));
615 isProgramming
= true;
617 isProgramming
= false;
621 void w25n01g_addError(uint32_t address
, uint8_t code
)
628 * Read `length` bytes into the provided `buffer` from the flash starting from the given `address` (which need not lie
629 * on a page boundary).
631 * Waits up to W25N01G_TIMEOUT_PAGE_READ_MS milliseconds for the flash to become ready before reading.
633 * The number of bytes actually read is returned, which can be zero if an error or timeout occurred.
636 // Continuous read mode (BUF = 0):
637 // (1) "Page Data Read" command is executed for the page pointed by address
638 // (2) "Read Data" command is executed for bytes not requested and data are discarded
639 // (3) "Read Data" command is executed and data are stored directly into caller's buffer
641 // Buffered read mode (BUF = 1), non-read ahead
642 // (1) If currentBufferPage != requested page, then issue PAGE_DATA_READ on requested page.
643 // (2) Compute transferLength as smaller of remaining length and requested length.
644 // (3) Issue READ_DATA on column address.
645 // (4) Return transferLength.
647 int w25n01g_readBytes(flashDevice_t
*fdevice
, uint32_t address
, uint8_t *buffer
, uint32_t length
)
649 uint32_t targetPage
= W25N01G_LINEAR_TO_PAGE(address
);
651 if (currentPage
!= targetPage
) {
652 if (!w25n01g_waitForReady(fdevice
)) {
656 currentPage
= UINT32_MAX
;
658 w25n01g_performCommandWithPageAddress(&fdevice
->io
, W25N01G_INSTRUCTION_PAGE_DATA_READ
, targetPage
);
660 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_PAGE_READ_MS
);
661 if (!w25n01g_waitForReady(fdevice
)) {
665 currentPage
= targetPage
;
668 uint32_t column
= W25N01G_LINEAR_TO_COLUMN(address
);
669 uint16_t transferLength
;
671 if (length
> W25N01G_PAGE_SIZE
- column
) {
672 transferLength
= W25N01G_PAGE_SIZE
- column
;
674 transferLength
= length
;
677 if (fdevice
->io
.mode
== FLASHIO_SPI
) {
678 extDevice_t
*dev
= fdevice
->io
.handle
.dev
;
681 cmd
[0] = W25N01G_INSTRUCTION_READ_DATA
;
682 cmd
[1] = (column
>> 8) & 0xff;
683 cmd
[2] = (column
>> 0) & 0xff;
686 busSegment_t segments
[] = {
687 {.u
.buffers
= {cmd
, NULL
}, sizeof(cmd
), false, NULL
},
688 {.u
.buffers
= {NULL
, buffer
}, length
, true, NULL
},
689 {.u
.link
= {NULL
, NULL
}, 0, true, NULL
},
692 spiSequence(dev
, &segments
[0]);
694 // Block pending completion of SPI access
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, W25N01G_STATUS_COLUMN_ADDRESS_SIZE, buffer, length);
702 quadSpiReceiveWithAddress4LINES(quadSpi
, W25N01G_INSTRUCTION_FAST_READ_QUAD_OUTPUT
, 8, column
, W25N01G_STATUS_COLUMN_ADDRESS_SIZE
, buffer
, length
);
706 // XXX Don't need this?
707 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_PAGE_READ_MS
);
708 if (!w25n01g_waitForReady(fdevice
)) {
714 uint8_t statReg
= w25n01g_readRegister(&fdevice
->io
, W25N01G_STAT_REG
);
715 uint8_t eccCode
= W25N01G_STATUS_FLAG_ECC(statReg
);
718 case 0: // Successful read, no ECC correction
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
);
728 return transferLength
;
731 int w25n01g_readExtensionBytes(flashDevice_t
*fdevice
, uint32_t address
, uint8_t *buffer
, int length
)
734 if (!w25n01g_waitForReady(fdevice
)) {
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
;
746 cmd
[0] = W25N01G_INSTRUCTION_READ_DATA
;
747 cmd
[1] = (column
>> 8) & 0xff;
748 cmd
[2] = (column
>> 0) & 0xff;
751 busSegment_t segments
[] = {
752 {.u
.buffers
= {cmd
, NULL
}, sizeof(cmd
), false, NULL
},
753 {.u
.buffers
= {NULL
, buffer
}, length
, true, NULL
},
754 {.u
.link
= {NULL
, NULL
}, 0, true, NULL
},
757 // Ensure any prior DMA has completed before continuing
760 spiSequence(dev
, &segments
[0]);
762 // Block pending completion of SPI access
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
, W25N01G_STATUS_COLUMN_ADDRESS_SIZE
, buffer
, length
);
774 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_PAGE_READ_MS
);
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 .configure
= w25n01g_configure
,
791 .isReady
= w25n01g_isReady
,
792 .waitForReady
= w25n01g_waitForReady
,
793 .eraseSector
= w25n01g_eraseSector
,
794 .eraseCompletely
= w25n01g_eraseCompletely
,
795 .pageProgramBegin
= w25n01g_pageProgramBegin
,
796 .pageProgramContinue
= w25n01g_pageProgramContinue
,
797 .pageProgramFinish
= w25n01g_pageProgramFinish
,
798 .pageProgram
= w25n01g_pageProgram
,
799 .flush
= w25n01g_flush
,
800 .readBytes
= w25n01g_readBytes
,
801 .getGeometry
= w25n01g_getGeometry
,
804 typedef volatile struct cb_context_s
{
805 flashDevice_t
*fdevice
;
811 // Called in ISR context
812 // Read of BBLUT entry has just completed
813 busStatus_e
w25n01g_readBBLUTCallback(uint32_t arg
)
815 cb_context_t
*cb_context
= (cb_context_t
*)arg
;
816 flashDevice_t
*fdevice
= cb_context
->fdevice
;
817 uint8_t *rxData
= fdevice
->io
.handle
.dev
->bus
->curSegment
->u
.buffers
.rxData
;
820 cb_context
->bblut
->pba
= (rxData
[0] << 16)|rxData
[1];
821 cb_context
->bblut
->lba
= (rxData
[2] << 16)|rxData
[3];
823 if (++cb_context
->lutindex
< cb_context
->lutsize
) {
825 return BUS_BUSY
; // Repeat the operation
828 return BUS_READY
; // All done
832 void w25n01g_readBBLUT(flashDevice_t
*fdevice
, bblut_t
*bblut
, int lutsize
)
834 cb_context_t cb_context
;
837 cb_context
.fdevice
= fdevice
;
838 fdevice
->callbackArg
= (uint32_t)&cb_context
;
840 if (fdevice
->io
.mode
== FLASHIO_SPI
) {
841 extDevice_t
*dev
= fdevice
->io
.handle
.dev
;
845 cmd
[0] = W25N01G_INSTRUCTION_READ_BBM_LUT
;
848 cb_context
.bblut
= &bblut
[0];
849 cb_context
.lutsize
= lutsize
;
850 cb_context
.lutindex
= 0;
852 busSegment_t segments
[] = {
853 {.u
.buffers
= {cmd
, NULL
}, sizeof(cmd
), false, NULL
},
854 {.u
.buffers
= {NULL
, in
}, sizeof(in
), true, w25n01g_readBBLUTCallback
},
855 {.u
.link
= {NULL
, NULL
}, 0, true, NULL
},
858 spiSequence(dev
, &segments
[0]);
860 // Block pending completion of SPI access
864 else if (fdevice
->io
.mode
== FLASHIO_QUADSPI
) {
865 QUADSPI_TypeDef
*quadSpi
= fdevice
->io
.handle
.quadSpi
;
867 // 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
868 // thus, we have to read the entire BBLUT in one go and process the result.
870 uint8_t bblutBuffer
[W25N01G_BBLUT_TABLE_ENTRY_COUNT
* W25N01G_BBLUT_TABLE_ENTRY_SIZE
];
871 quadSpiReceive1LINE(quadSpi
, W25N01G_INSTRUCTION_READ_BBM_LUT
, 8, bblutBuffer
, sizeof(bblutBuffer
));
873 for (int i
= 0, offset
= 0 ; i
< lutsize
; i
++, offset
+= 4) {
874 if (i
< W25N01G_BBLUT_TABLE_ENTRY_COUNT
) {
875 bblut
[i
].pba
= (in
[offset
+ 0] << 16)|in
[offset
+ 1];
876 bblut
[i
].lba
= (in
[offset
+ 2] << 16)|in
[offset
+ 3];
883 void w25n01g_writeBBLUT(flashDevice_t
*fdevice
, uint16_t lba
, uint16_t pba
)
885 w25n01g_waitForReady(fdevice
);
887 if (fdevice
->io
.mode
== FLASHIO_SPI
) {
888 extDevice_t
*dev
= fdevice
->io
.handle
.dev
;
890 uint8_t cmd
[5] = { W25N01G_INSTRUCTION_BB_MANAGEMENT
, lba
>> 8, lba
, pba
>> 8, pba
};
892 busSegment_t segments
[] = {
893 {.u
.buffers
= {cmd
, NULL
}, sizeof(cmd
), true, NULL
},
894 {.u
.link
= {NULL
, NULL
}, 0, true, NULL
},
897 // Ensure any prior DMA has completed before continuing
900 spiSequence(dev
, &segments
[0]);
902 // Block pending completion of SPI access
906 else if (fdevice
->io
.mode
== FLASHIO_QUADSPI
) {
907 QUADSPI_TypeDef
*quadSpi
= fdevice
->io
.handle
.quadSpi
;
909 uint8_t data
[4] = { lba
>> 8, lba
, pba
>> 8, pba
};
910 quadSpiInstructionWithData1LINE(quadSpi
, W25N01G_INSTRUCTION_BB_MANAGEMENT
, 0, data
, sizeof(data
));
914 w25n01g_setTimeout(fdevice
, W25N01G_TIMEOUT_PAGE_PROGRAM_MS
);
917 static void w25n01g_deviceInit(flashDevice_t
*flashdev
)