Use the cached value of useDshotTelemetry to ensure consistent runtime use if dshot_b...
[betaflight.git] / src / main / drivers / flash_w25q128fv.c
blobe8fb03bf1349a462368915dfe25478040a2d1f69
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: Dominic Clifton - Initial implementation and testing.
23 #include <stdbool.h>
24 #include <stdint.h>
26 #include "platform.h"
28 #if defined(USE_FLASH_W25Q128FV) && (defined(USE_QUADSPI) || defined(USE_OCTOSPI))
30 #define USE_FLASH_WRITES_USING_4LINES
31 #define USE_FLASH_READS_USING_4LINES
33 #include "build/debug.h"
34 #include "common/utils.h"
36 #include "drivers/time.h"
37 #include "drivers/flash.h"
38 #include "drivers/flash_impl.h"
39 #include "drivers/flash_w25q128fv.h"
40 #include "drivers/bus_quadspi.h"
41 #include "drivers/bus_octospi.h"
43 // JEDEC ID
44 #define JEDEC_ID_WINBOND_W25Q128FV_SPI 0xEF4018
45 #define JEDEC_ID_WINBOND_W25Q128FV_QUADSPI 0xEF6018
46 #define JEDEC_ID_WINBOND_W25Q128JV_QUADSPI 0xEF7018
47 #define JEDEC_ID_WINBOND_W25Q16JV_SPI 0xEF4015
48 #define JEDEC_ID_WINBOND_W25Q16JV_DTR_SPI 0xEF7015
50 // Device size parameters
51 #define W25Q128FV_PAGE_SIZE 2048
52 #define W25Q128FV_PAGES_PER_BLOCK 64
53 #define W25Q128FV_BLOCKS_PER_DIE 1024
54 #define W25Q128FV_BLOCK_SIZE (W25Q128FV_PAGES_PER_BLOCK * W25Q128FV_PAGE_SIZE)
56 // Sizes
57 #define W25Q128FV_STATUS_REGISTER_BITS 8
58 #define W25Q128FV_ADDRESS_BITS 24
61 // Instructions
62 #define W25Q128FV_INSTRUCTION_RDID 0x9F
64 #define W25Q128FV_INSTRUCTION_ENABLE_RESET 0x66
65 #define W25Q128FV_INSTRUCTION_RESET_DEVICE 0x99
67 #define W25Q128FV_INSTRUCTION_READ_STATUS1_REG 0x05
68 #define W25Q128FV_INSTRUCTION_READ_STATUS2_REG 0x35
69 #define W25Q128FV_INSTRUCTION_READ_STATUS3_REG 0x15
71 #define W25Q128FV_INSTRUCTION_WRITE_STATUS1_REG 0x01
72 #define W25Q128FV_INSTRUCTION_WRITE_STATUS2_REG 0x31
73 #define W25Q128FV_INSTRUCTION_WRITE_STATUS3_REG 0x11
75 #define W25Q128FV_INSTRUCTION_WRITE_ENABLE 0x06
76 #define W25Q128FV_INSTRUCTION_VOLATILE_WRITE_ENABLE 0x50
77 #define W25Q128FV_INSTRUCTION_BLOCK_ERASE_64KB 0xD8
78 #define W25Q128FV_INSTRUCTION_CHIP_ERASE 0xC7
80 #define W25Q128FV_INSTRUCTION_ENTER_QPI_MODE 0x38
82 #define W25Q128FV_INSTRUCTION_FAST_READ 0x0B
83 #define W25Q128FV_INSTRUCTION_FAST_READ_QUAD_OUTPUT 0x6B
85 #define W25Q128FV_INSTRUCTION_PAGE_PROGRAM 0x02
86 #define W25Q128FV_INSTRUCTION_QUAD_PAGE_PROGRAM 0x32
88 #define W25Q128FV_SR1_BIT_WRITE_IN_PROGRESS (1 << 0)
89 #define W25Q128FV_SR1_BIT_WRITE_ENABLED (1 << 1)
91 #define W25Q128FV_SR2_BIT_QUAD_ENABLE (1 << 1)
94 //#define W25Q128FV_INSTRUCTION_WRITE_DISABLE 0x04
95 //#define W25Q128FV_INSTRUCTION_PAGE_PROGRAM 0x02
97 // Values from W25Q128FV Datasheet Rev L.
98 #define W25Q128FV_TIMEOUT_PAGE_READ_MS 1 // No minimum specified in datasheet
99 #define W25Q128FV_TIMEOUT_RESET_MS 1 // tRST = 30us
100 #define W25Q128FV_TIMEOUT_BLOCK_ERASE_64KB_MS 2000 // tBE2max = 2000ms, tBE2typ = 150ms
101 #define W25Q128FV_TIMEOUT_CHIP_ERASE_MS (200 * 1000) // tCEmax 200s, tCEtyp = 40s
103 #define W25Q128FV_TIMEOUT_PAGE_PROGRAM_MS 3 // tPPmax = 3ms, tPPtyp = 0.7ms
104 #define W25Q128FV_TIMEOUT_WRITE_ENABLE_MS 1
107 typedef enum {
108 INITIAL_MODE_SPI = 0,
109 INITIAL_MODE_QUADSPI,
110 } w25q128fv_initialMode_e;
112 typedef struct w25q128fvState_s {
113 w25q128fv_initialMode_e initialMode;
114 uint32_t currentWriteAddress;
115 } w25q128fvState_t;
117 w25q128fvState_t w25q128fvState = { 0 };
119 static bool w25q128fv_waitForReady(flashDevice_t *fdevice);
120 static void w25q128fv_waitForTimeout(flashDevice_t *fdevice);
122 MMFLASH_CODE static void w25q128fv_setTimeout(flashDevice_t *fdevice, timeMs_t timeoutMillis)
124 timeMs_t nowMs = microsISR() / 1000;
125 fdevice->timeoutAt = nowMs + timeoutMillis;
128 MMFLASH_CODE static void w25q128fv_performOneByteCommand(flashDeviceIO_t *io, uint8_t command)
130 #if defined(USE_QUADSPI)
131 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
132 quadSpiTransmit1LINE(quadSpi, command, 0, NULL, 0);
133 #elif defined(USE_OCTOSPI)
134 OCTOSPI_TypeDef *octoSpi = io->handle.octoSpi;
135 octoSpiTransmit1LINE(octoSpi, command, 0, NULL, 0);
136 #endif
140 MMFLASH_CODE static void w25q128fv_performCommandWithAddress(flashDeviceIO_t *io, uint8_t command, uint32_t address)
142 #if defined(USE_QUADSPI)
143 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
145 quadSpiInstructionWithAddress1LINE(quadSpi, command, 0, address & 0xffffff, W25Q128FV_ADDRESS_BITS);
146 #elif defined(USE_OCTOSPI)
147 OCTOSPI_TypeDef *octoSpi = io->handle.octoSpi;
149 octoSpiInstructionWithAddress1LINE(octoSpi, command, 0, address & 0xffffff, W25Q128FV_ADDRESS_BITS);
150 #endif
153 MMFLASH_CODE static void w25q128fv_writeEnable(flashDevice_t *fdevice)
155 w25q128fv_performOneByteCommand(&fdevice->io, W25Q128FV_INSTRUCTION_WRITE_ENABLE);
158 MMFLASH_CODE static uint8_t w25q128fv_readRegister(flashDeviceIO_t *io, uint8_t command)
160 uint8_t in[W25Q128FV_STATUS_REGISTER_BITS / 8] = { 0 };
161 #if defined(USE_QUADSPI)
162 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
164 quadSpiReceive1LINE(quadSpi, command, 0, in, W25Q128FV_STATUS_REGISTER_BITS / 8);
165 #elif defined(USE_OCTOSPI)
166 OCTOSPI_TypeDef *octoSpi = io->handle.octoSpi;
168 octoSpiReceive1LINE(octoSpi, command, 0, in, W25Q128FV_STATUS_REGISTER_BITS / 8);
169 #endif
172 return in[0];
175 static void w25q128fv_writeRegister(flashDeviceIO_t *io, uint8_t command, uint8_t data)
177 #if defined(USE_QUADSPI)
178 QUADSPI_TypeDef *quadSpi = io->handle.quadSpi;
180 quadSpiTransmit1LINE(quadSpi, command, 0, &data, W25Q128FV_STATUS_REGISTER_BITS / 8);
181 #elif defined(USE_OCTOSPI)
182 OCTOSPI_TypeDef *octoSpi = io->handle.octoSpi;
184 octoSpiTransmit1LINE(octoSpi, command, 0, &data, W25Q128FV_STATUS_REGISTER_BITS / 8);
185 #endif
189 static void w25q128fv_deviceReset(flashDevice_t *fdevice)
191 flashDeviceIO_t *io = &fdevice->io;
193 w25q128fv_waitForReady(fdevice);
194 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_ENABLE_RESET);
195 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_RESET_DEVICE);
197 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_RESET_MS);
198 w25q128fv_waitForTimeout(fdevice);
200 w25q128fv_waitForReady(fdevice);
202 #ifdef DISABLE_NONVOLATILE_QE_MODE // Use this if you encounter a chip with it's QE bit enabled when it shouldn't be.
203 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_WRITE_ENABLE);
204 w25q128fv_writeRegister(io, W25Q128FV_INSTRUCTION_WRITE_STATUS2_REG, 0x00);
205 #endif
208 #if defined(USE_FLASH_WRITES_USING_4LINES) || defined(USE_FLASH_READS_USING_4LINES)
209 uint8_t registerValue = w25q128fv_readRegister(io, W25Q128FV_INSTRUCTION_READ_STATUS2_REG);
212 // WARNING: DO NOT ENABLE QE bit if IO2/IO3 are connected to GND or VCC.
214 // See datasheet https://www.winbond.com/resource-files/w25q128fv%20rev.m%2005132016%20kms.pdf
215 // W25Q128FV - Revision M - 7.1.10 Quad Enable
217 // There is no such warning for the W25Q128JV in the same documentation section
218 // See datasheet https://www.winbond.com/resource-files/w25q128jv%20revg%2004082019%20plus.pdf
219 // W25Q128JV - Revision G - 7.1.4 Quad Enable
222 if ((registerValue & W25Q128FV_SR2_BIT_QUAD_ENABLE) == 0) {
223 // Enable QUADSPI mode.
224 registerValue = w25q128fv_readRegister(io, W25Q128FV_INSTRUCTION_READ_STATUS2_REG);
226 uint8_t newValue = registerValue;
227 newValue |= W25Q128FV_SR2_BIT_QUAD_ENABLE;
229 //w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_WRITE_ENABLE);
230 w25q128fv_performOneByteCommand(io, W25Q128FV_INSTRUCTION_VOLATILE_WRITE_ENABLE);
231 w25q128fv_writeRegister(io, W25Q128FV_INSTRUCTION_WRITE_STATUS2_REG, newValue);
233 #endif
236 MMFLASH_CODE bool w25q128fv_isReady(flashDevice_t *fdevice)
238 uint8_t status = w25q128fv_readRegister(&fdevice->io, W25Q128FV_INSTRUCTION_READ_STATUS1_REG);
240 bool busy = (status & W25Q128FV_SR1_BIT_WRITE_IN_PROGRESS);
242 return !busy;
245 MMFLASH_CODE static bool w25q128fv_isWritable(flashDevice_t *fdevice)
247 uint8_t status = w25q128fv_readRegister(&fdevice->io, W25Q128FV_INSTRUCTION_READ_STATUS1_REG);
249 bool writable = (status & W25Q128FV_SR1_BIT_WRITE_ENABLED);
251 return writable;
254 MMFLASH_CODE bool w25q128fv_hasTimedOut(flashDevice_t *fdevice)
256 uint32_t nowMs = microsISR() / 1000;
257 if (cmp32(nowMs, fdevice->timeoutAt) >= 0) {
258 return true;
260 return false;
263 MMFLASH_CODE void w25q128fv_waitForTimeout(flashDevice_t *fdevice)
265 while (!w25q128fv_hasTimedOut(fdevice)) { }
267 fdevice->timeoutAt = 0;
270 MMFLASH_CODE bool w25q128fv_waitForReady(flashDevice_t *fdevice)
272 bool ready = true;
273 while (!w25q128fv_isReady(fdevice)) {
274 if (w25q128fv_hasTimedOut(fdevice)) {
275 ready = false;
276 break;
279 fdevice->timeoutAt = 0;
281 return ready;
284 const flashVTable_t w25q128fv_vTable;
286 static void w25q128fv_deviceInit(flashDevice_t *flashdev);
288 MMFLASH_CODE_NOINLINE bool w25q128fv_identify(flashDevice_t *fdevice, uint32_t jedecID)
290 switch (jedecID) {
291 case JEDEC_ID_WINBOND_W25Q128FV_SPI:
292 case JEDEC_ID_WINBOND_W25Q128FV_QUADSPI:
293 case JEDEC_ID_WINBOND_W25Q128JV_QUADSPI:
294 fdevice->geometry.sectors = 256;
295 fdevice->geometry.pagesPerSector = 256;
296 fdevice->geometry.pageSize = 256;
297 // = 16777216 128MBit 16MB
298 break;
300 case JEDEC_ID_WINBOND_W25Q16JV_DTR_SPI:
301 case JEDEC_ID_WINBOND_W25Q16JV_SPI:
302 fdevice->geometry.sectors = 32;
303 fdevice->geometry.pagesPerSector = 256;
304 fdevice->geometry.pageSize = 256;
305 // = 2097152 16MBit 2MB
306 break;
308 default:
309 // Unsupported chip
310 fdevice->geometry.sectors = 0;
311 fdevice->geometry.pagesPerSector = 0;
312 fdevice->geometry.sectorSize = 0;
313 fdevice->geometry.totalSize = 0;
314 return false;
317 // use the chip id to determine the initial interface mode on cold-boot.
318 switch (jedecID) {
319 case JEDEC_ID_WINBOND_W25Q16JV_SPI:
320 case JEDEC_ID_WINBOND_W25Q16JV_DTR_SPI:
321 case JEDEC_ID_WINBOND_W25Q128FV_SPI:
322 w25q128fvState.initialMode = INITIAL_MODE_SPI;
323 break;
325 case JEDEC_ID_WINBOND_W25Q128JV_QUADSPI:
326 case JEDEC_ID_WINBOND_W25Q128FV_QUADSPI:
327 w25q128fvState.initialMode = INITIAL_MODE_QUADSPI;
328 break;
330 default:
331 break;
334 fdevice->geometry.flashType = FLASH_TYPE_NOR;
335 fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize;
336 fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors;
338 fdevice->vTable = &w25q128fv_vTable;
340 return true;
343 void w25q128fv_configure(flashDevice_t *fdevice, uint32_t configurationFlags)
345 if (configurationFlags & FLASH_CF_SYSTEM_IS_MEMORY_MAPPED) {
346 return;
349 w25q128fv_deviceReset(fdevice);
351 w25q128fv_deviceInit(fdevice);
354 MMFLASH_CODE static void w25q128fv_eraseSector(flashDevice_t *fdevice, uint32_t address)
356 w25q128fv_waitForReady(fdevice);
358 w25q128fv_writeEnable(fdevice);
360 w25q128fv_performCommandWithAddress(&fdevice->io, W25Q128FV_INSTRUCTION_BLOCK_ERASE_64KB, address);
362 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_BLOCK_ERASE_64KB_MS);
365 static void w25q128fv_eraseCompletely(flashDevice_t *fdevice)
367 w25q128fv_waitForReady(fdevice);
369 w25q128fv_writeEnable(fdevice);
371 w25q128fv_performOneByteCommand(&fdevice->io, W25Q128FV_INSTRUCTION_CHIP_ERASE);
373 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_CHIP_ERASE_MS);
376 MMFLASH_CODE static void w25q128fv_loadProgramData(flashDevice_t *fdevice, const uint8_t *data, int length)
378 w25q128fv_waitForReady(fdevice);
380 #if defined(USE_QUADSPI)
381 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
383 #ifdef USE_FLASH_WRITES_USING_4LINES
384 quadSpiTransmitWithAddress4LINES(quadSpi, W25Q128FV_INSTRUCTION_QUAD_PAGE_PROGRAM, 0, w25q128fvState.currentWriteAddress, W25Q128FV_ADDRESS_BITS, data, length);
385 #else
386 quadSpiTransmitWithAddress1LINE(quadSpi, W25Q128FV_INSTRUCTION_PAGE_PROGRAM, 0, w25q128fvState.currentWriteAddress, W25Q128FV_ADDRESS_BITS, data, length);
387 #endif
388 #elif defined(USE_OCTOSPI)
389 OCTOSPI_TypeDef *octoSpi = fdevice->io.handle.octoSpi;
391 #ifdef USE_FLASH_WRITES_USING_4LINES
392 octoSpiTransmitWithAddress4LINES(octoSpi, W25Q128FV_INSTRUCTION_QUAD_PAGE_PROGRAM, 0, w25q128fvState.currentWriteAddress, W25Q128FV_ADDRESS_BITS, data, length);
393 #else
394 octoSpiTransmitWithAddress1LINE(octoSpi, W25Q128FV_INSTRUCTION_PAGE_PROGRAM, 0, w25q128fvState.currentWriteAddress, W25Q128FV_ADDRESS_BITS, data, length);
395 #endif
396 #endif
398 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_PAGE_PROGRAM_MS);
400 w25q128fvState.currentWriteAddress += length;
403 MMFLASH_CODE static void w25q128fv_pageProgramBegin(flashDevice_t *fdevice, uint32_t address, void (*callback)(uint32_t length))
405 fdevice->callback = callback;
406 w25q128fvState.currentWriteAddress = address;
409 MMFLASH_CODE static uint32_t w25q128fv_pageProgramContinue(flashDevice_t *fdevice, uint8_t const **buffers, uint32_t *bufferSizes, uint32_t bufferCount)
411 for (uint32_t i = 0; i < bufferCount; i++) {
412 w25q128fv_waitForReady(fdevice);
414 w25q128fv_writeEnable(fdevice);
416 // verify write enable is set.
417 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_WRITE_ENABLE_MS);
418 bool writable = false;
419 do {
420 writable = w25q128fv_isWritable(fdevice);
421 } while (!writable && w25q128fv_hasTimedOut(fdevice));
423 if (!writable) {
424 return 0; // TODO report failure somehow.
427 w25q128fv_loadProgramData(fdevice, buffers[i], bufferSizes[i]);
430 return fdevice->callbackArg;
433 MMFLASH_CODE static void w25q128fv_pageProgramFinish(flashDevice_t *fdevice)
435 UNUSED(fdevice);
438 MMFLASH_CODE static void w25q128fv_pageProgram(flashDevice_t *fdevice, uint32_t address, const uint8_t *data, uint32_t length, void (*callback)(uint32_t length))
440 w25q128fv_pageProgramBegin(fdevice, address, callback);
441 w25q128fv_pageProgramContinue(fdevice, &data, &length, 1);
442 w25q128fv_pageProgramFinish(fdevice);
445 MMFLASH_CODE void w25q128fv_flush(flashDevice_t *fdevice)
447 UNUSED(fdevice);
450 MMFLASH_CODE static int w25q128fv_readBytes(flashDevice_t *fdevice, uint32_t address, uint8_t *buffer, uint32_t length)
452 if (!w25q128fv_waitForReady(fdevice)) {
453 return 0;
456 #if defined(USE_QUADSPI)
457 QUADSPI_TypeDef *quadSpi = fdevice->io.handle.quadSpi;
458 #ifdef USE_FLASH_READS_USING_4LINES
459 bool status = quadSpiReceiveWithAddress4LINES(quadSpi, W25Q128FV_INSTRUCTION_FAST_READ_QUAD_OUTPUT, 8, address, W25Q128FV_ADDRESS_BITS, buffer, length);
460 #else
461 bool status = quadSpiReceiveWithAddress1LINE(quadSpi, W25Q128FV_INSTRUCTION_FAST_READ, 8, address, W25Q128FV_ADDRESS_BITS, buffer, length);
462 #endif
463 #elif defined(USE_OCTOSPI)
464 OCTOSPI_TypeDef *octoSpi = fdevice->io.handle.octoSpi;
465 #ifdef USE_FLASH_READS_USING_4LINES
466 bool status = octoSpiReceiveWithAddress4LINES(octoSpi, W25Q128FV_INSTRUCTION_FAST_READ_QUAD_OUTPUT, 8, address, W25Q128FV_ADDRESS_BITS, buffer, length);
467 #else
468 bool status = octoSpiReceiveWithAddress1LINE(octoSpi, W25Q128FV_INSTRUCTION_FAST_READ, 8, address, W25Q128FV_ADDRESS_BITS, buffer, length);
469 #endif
470 #endif
472 w25q128fv_setTimeout(fdevice, W25Q128FV_TIMEOUT_PAGE_READ_MS);
474 if (!status) {
475 return 0;
478 return length;
481 const flashGeometry_t* w25q128fv_getGeometry(flashDevice_t *fdevice)
483 return &fdevice->geometry;
486 MMFLASH_DATA const flashVTable_t w25q128fv_vTable = {
487 .configure = w25q128fv_configure,
488 .isReady = w25q128fv_isReady,
489 .waitForReady = w25q128fv_waitForReady,
490 .eraseSector = w25q128fv_eraseSector,
491 .eraseCompletely = w25q128fv_eraseCompletely,
492 .pageProgramBegin = w25q128fv_pageProgramBegin,
493 .pageProgramContinue = w25q128fv_pageProgramContinue,
494 .pageProgramFinish = w25q128fv_pageProgramFinish,
495 .pageProgram = w25q128fv_pageProgram,
496 .flush = w25q128fv_flush,
497 .readBytes = w25q128fv_readBytes,
498 .getGeometry = w25q128fv_getGeometry,
501 static void w25q128fv_deviceInit(flashDevice_t *flashdev)
503 UNUSED(flashdev);
506 #endif