2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
23 #ifdef USE_FLASH_M25P16
25 #include "flash_m25p16.h"
26 #include "drivers/io.h"
27 #include "drivers/bus.h"
28 #include "drivers/time.h"
30 #if defined(USE_QUADSPI)
31 #include "drivers/bus_quadspi.h"
32 #include "drivers/bus_quadspi_impl.h"
35 #define M25P16_INSTRUCTION_RDID 0x9F
36 #define M25P16_INSTRUCTION_READ_BYTES 0x03
37 #define M25P16_INSTRUCTION_QUAD_READ 0x6B
38 #define M25P16_INSTRUCTION_READ_STATUS_REG 0x05
39 #define M25P16_INSTRUCTION_WRITE_STATUS_REG 0x01
40 #define M25P16_INSTRUCTION_WRITE_ENABLE 0x06
41 #define M25P16_INSTRUCTION_WRITE_DISABLE 0x04
42 #define M25P16_INSTRUCTION_PAGE_PROGRAM 0x02
43 #define M25P16_INSTRUCTION_QPAGE_PROGRAM 0x32
44 #define M25P16_INSTRUCTION_SECTOR_ERASE 0xD8
45 #define M25P16_INSTRUCTION_BULK_ERASE 0xC7
47 #define M25P16_STATUS_FLAG_WRITE_IN_PROGRESS 0x01
48 #define M25P16_STATUS_FLAG_WRITE_ENABLED 0x02
50 #define W25Q256_INSTRUCTION_ENTER_4BYTE_ADDRESS_MODE 0xB7
52 #define M25P16_FAST_READ_DUMMY_CYCLES 8
56 flashSector_t sectors
;
57 uint16_t pagesPerSector
;
58 } m25p16FlashConfig
[] = {
59 // Macronix MX25L3206E
60 // Datasheet: https://docs.rs-online.com/5c85/0900766b814ac6f9.pdf
62 // Macronix MX25L6406E
63 // Datasheet: https://www.macronix.com/Lists/Datasheet/Attachments/7370/MX25L6406E,%203V,%2064Mb,%20v1.9.pdf
65 // Macronix MX25L25635E
66 // Datasheet: https://www.macronix.com/Lists/Datasheet/Attachments/7331/MX25L25635E,%203V,%20256Mb,%20v1.3.pdf
69 // Datasheet: https://www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/m25p/m25p16.pdf
72 // Datasheet: https://www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_64a_3v_65nm.pdf
75 // Datasheet: https://www.micron.com/-/media/client/global/documents/products/data-sheet/nor-flash/serial-nor/n25q/n25q_128mb_1_8v_65nm.pdf
78 // Datasheet: https://www.winbond.com/resource-files/w25q80dv%20dl_revh_10022015.pdf
81 // Datasheet: https://www.winbond.com/resource-files/w25q16dv_revi_nov1714_web.pdf
84 // Datasheet: https://www.winbond.com/resource-files/w25x32a_revb_080709.pdf
87 // Datasheet: https://www.winbond.com/resource-files/w25q32jv%20dtr%20revf%2002242017.pdf?__locale=zh_TW
90 // Datasheet: https://www.winbond.com/resource-files/w25q64jv%20spi%20%20%20revc%2006032016%20kms.pdf
91 {0xEF4017, 128, 256}, // W25Q64JV-IQ/JQ
92 {0xEF7017, 128, 256}, // W25Q64JV-IM/JM*
94 // Datasheet: https://www.winbond.com/resource-files/w25q128fv%20rev.l%2008242015.pdf
97 // Datasheet: http://zbitsemi.com/upload/file/20201010/20201010174048_82182.pdf
99 // Winbond W25Q128_DTR
100 // Datasheet: https://www.winbond.com/resource-files/w25q128jv%20dtr%20revb%2011042016.pdf
101 {0xEF7018, 256, 256},
103 // Datasheet: https://www.winbond.com/resource-files/w25q256jv%20spi%20revb%2009202016.pdf
104 {0xEF4019, 512, 256},
106 // Datasheet: https://www.cypress.com/file/316661/download
107 {0x016017, 128, 256},
109 // Datasheet: https://www.cypress.com/file/316171/download
110 {0x016018, 256, 256},
112 // Datasheet: https://www.winbond.com/resource-files/w25q32jv%20dtr%20revf%2002242017.pdf?__locale=zh_TW
113 {0xE04016, 1024, 16},
114 // JEDEC_ID_EON_W25Q64
115 {0x1C3017, 128, 256},
116 // JEDEC_ID_SPANSION_S25FL116
117 {0x014015, 32, 256 },
121 // The timeout we expect between being able to issue page program instructions
122 #define DEFAULT_TIMEOUT_MILLIS 6
124 // These take sooooo long:
125 #define SECTOR_ERASE_TIMEOUT_MILLIS 5000
126 #define BULK_ERASE_TIMEOUT_MILLIS 21000
128 static flashGeometry_t geometry
= {.pageSize
= M25P16_PAGESIZE
};
130 #if !defined(M25P16_QUADSPI_DEVICE)
131 static busDevice_t
* busDev
= NULL
;
133 static QUADSPI_TypeDef
* qspi
= NULL
;
134 #endif /* !defined(M25P16_QUADSPI_DEVICE) */
136 static bool isLargeFlash
= false;
137 static uint32_t timeoutAt
= 0;
140 * Whether we've performed an action that could have made the device busy for writes.
142 * This allows us to avoid polling for writable status when it is definitely ready already.
144 static bool couldBeBusy
= false;
147 * Send the given command byte to the device.
149 static void m25p16_performOneByteCommand(uint8_t command
)
151 #if !defined(M25P16_QUADSPI_DEVICE)
152 busTransfer(busDev
, NULL
, &command
, 1);
154 quadSpiTransmit1LINE(qspi
, command
, 0, NULL
, 0);
155 #endif /* !defined(M25P16_QUADSPI_DEVICE) */
159 * The flash requires this write enable command to be sent before commands that would cause
160 * a write like program and erase.
162 static void m25p16_writeEnable(void)
164 m25p16_performOneByteCommand(M25P16_INSTRUCTION_WRITE_ENABLE
);
166 // Assume that we're about to do some writing, so the device is just about to become busy
170 static uint8_t m25p16_readStatus(void)
173 #if !defined(M25P16_QUADSPI_DEVICE)
174 uint8_t command
[2] = { M25P16_INSTRUCTION_READ_STATUS_REG
, 0 };
177 busTransfer(busDev
, in
, command
, sizeof(command
));
180 quadSpiReceive1LINE(qspi
, M25P16_INSTRUCTION_READ_STATUS_REG
, 0, &status
, 1);
181 #endif /* !defined(M25P16_QUADSPI_DEVICE) */
186 bool m25p16_isReady(void)
188 // If couldBeBusy is false, don't bother to poll the flash chip for its status
189 couldBeBusy
= couldBeBusy
&& ((m25p16_readStatus() & M25P16_STATUS_FLAG_WRITE_IN_PROGRESS
) != 0);
194 static void m25p16_setTimeout(uint32_t timeoutMillis
)
196 uint32_t now
= millis();
197 timeoutAt
= now
+ timeoutMillis
;
200 bool m25p16_waitForReady(uint32_t timeoutMillis
)
202 uint32_t timeoutAtUse
;
203 if (timeoutMillis
== 0) {
204 timeoutAtUse
= timeoutAt
;
207 timeoutAtUse
= millis() + timeoutMillis
;
210 while (!m25p16_isReady()) {
211 uint32_t now
= millis();
212 if (now
>= timeoutAtUse
) {
222 * Read chip identification and geometry information (into global `geometry`).
224 * Returns true if we get valid ident, false if something bad happened like there is no M25P16.
226 static bool m25p16_readIdentification(void)
231 delay(50); // short delay required after initialisation of SPI device instance.
233 /* Just in case transfer fails and writes nothing, so we don't try to verify the ID against random garbage
238 #if !defined(M25P16_QUADSPI_DEVICE)
239 uint8_t out
[] = { M25P16_INSTRUCTION_RDID
, 0, 0, 0 };
241 busTransfer(busDev
, in
, out
, sizeof(out
));
243 bool status
= quadSpiReceive1LINE(qspi
, M25P16_INSTRUCTION_RDID
, 0, &in
[1], sizeof(in
) - 1);
247 #endif /* !defined(M25P16_QUADSPI_DEVICE) */
249 // Manufacturer, memory type, and capacity
250 chipID
= (in
[1] << 16) | (in
[2] << 8) | (in
[3]);
252 geometry
.sectors
= 0;
253 geometry
.pagesPerSector
= 0;
254 geometry
.sectorSize
= 0;
255 geometry
.totalSize
= 0;
257 for(int i
= 0; m25p16FlashConfig
[i
].jedecID
!= 0; ++i
) {
258 if(m25p16FlashConfig
[i
].jedecID
== chipID
) {
259 geometry
.sectors
= m25p16FlashConfig
[i
].sectors
;
260 geometry
.pagesPerSector
= m25p16FlashConfig
[i
].pagesPerSector
;
264 if(geometry
.sectors
== 0) {
268 geometry
.flashType
= FLASH_TYPE_NOR
;
269 geometry
.pageSize
= M25P16_PAGESIZE
;
270 geometry
.sectorSize
= geometry
.pagesPerSector
* geometry
.pageSize
;
271 geometry
.totalSize
= geometry
.sectorSize
* geometry
.sectors
;
273 if (geometry
.totalSize
> 16 * 1024 * 1024) {
275 m25p16_performOneByteCommand(W25Q256_INSTRUCTION_ENTER_4BYTE_ADDRESS_MODE
);
278 couldBeBusy
= true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be
284 * Initialize the driver, must be called before any other routines.
286 * Attempts to detect a connected m25p16. If found, true is returned and device capacity can be fetched with
287 * m25p16_getGeometry().
289 bool m25p16_init(int flashNumToUse
)
292 #if !defined(M25P16_QUADSPI_DEVICE)
294 busDev
= busDeviceInit(BUSTYPE_SPI
, DEVHW_M25P16
, flashNumToUse
, OWNER_FLASH
);
295 if (busDev
== NULL
) {
299 #ifndef M25P16_SPI_SHARED
300 busSetSpeed(busDev
, BUS_SPEED_FAST
);
304 UNUSED(flashNumToUse
);
305 quadSpiPinConfigure(M25P16_QUADSPI_DEVICE
);
306 quadSpiInitDevice(M25P16_QUADSPI_DEVICE
);
308 qspi
= quadSpiInstanceByDevice(M25P16_QUADSPI_DEVICE
);
309 quadSpiSetDivisor(qspi
, QUADSPI_CLOCK_INITIALISATION
);
310 #endif /* M25P16_QUADSPI_DEVICE */
312 detected
= m25p16_readIdentification();
314 #if defined(M25P16_QUADSPI_DEVICE)
316 quadSpiSetDivisor(qspi
, QUADSPI_CLOCK_ULTRAFAST
);
323 void m25p16_setCommandAddress(uint8_t *buf
, uint32_t address
, bool useLongAddress
)
325 if (useLongAddress
) {
326 *buf
++ = (address
>> 24) & 0xff;
329 *buf
++ = (address
>> 16) & 0xff;
330 *buf
++ = (address
>> 8) & 0xff;
331 *buf
= address
& 0xff;
335 * Erase a sector full of bytes to all 1's at the given byte offset in the flash chip.
337 void m25p16_eraseSector(uint32_t address
)
339 if (!m25p16_waitForReady(0)) {
343 m25p16_writeEnable();
345 #if !defined(M25P16_QUADSPI_DEVICE)
346 uint8_t out
[5] = { M25P16_INSTRUCTION_SECTOR_ERASE
};
347 m25p16_setCommandAddress(&out
[1], address
, isLargeFlash
);
349 busTransfer(busDev
, NULL
, out
, isLargeFlash
? 5 : 4);
351 quadSpiInstructionWithAddress1LINE(qspi
, M25P16_INSTRUCTION_SECTOR_ERASE
, 0, address
, isLargeFlash
? 32 : 24);
352 #endif /* !defined(M25P16_QUADSPI_DEVICE) */
354 m25p16_setTimeout(SECTOR_ERASE_TIMEOUT_MILLIS
);
357 void m25p16_eraseCompletely(void)
359 if (!m25p16_waitForReady(0)) {
363 m25p16_writeEnable();
365 m25p16_performOneByteCommand(M25P16_INSTRUCTION_BULK_ERASE
);
367 m25p16_setTimeout(BULK_ERASE_TIMEOUT_MILLIS
);
371 * Write bytes to a flash page. Address must not cross a page boundary.
373 * 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.
375 * Length must be smaller than the page size.
377 * This will wait for the flash to become ready before writing begins.
379 * Datasheet indicates typical programming time is 0.8ms for 256 bytes, 0.2ms for 64 bytes, 0.05ms for 16 bytes.
380 * (Although the maximum possible write time is noted as 5ms).
382 * If you want to write multiple buffers (whose sum of sizes is still not more than the page size) then you can
383 * break this operation up into one beginProgram call, one or more continueProgram calls, and one finishProgram call.
385 uint32_t m25p16_pageProgram(uint32_t address
, const uint8_t *data
, int length
)
387 if (!m25p16_waitForReady(0)) {
388 // return same address to indicate timeout
392 m25p16_writeEnable();
394 #if !defined(M25P16_QUADSPI_DEVICE)
395 uint8_t command
[5] = { M25P16_INSTRUCTION_PAGE_PROGRAM
};
397 busTransferDescriptor_t txn
[2] = {
398 { NULL
, command
, isLargeFlash
? 5 : 4 },
399 { NULL
, data
, length
}
402 m25p16_setCommandAddress(&command
[1], address
, isLargeFlash
);
404 busTransferMultiple(busDev
, txn
, 2);
406 quadSpiTransmitWithAddress4LINES(qspi
, M25P16_INSTRUCTION_QPAGE_PROGRAM
, 0, address
, isLargeFlash
? 32 : 24, data
, length
);
407 #endif /* !defined(M25P16_QUADSPI_DEVICE) */
409 m25p16_setTimeout(DEFAULT_TIMEOUT_MILLIS
);
411 return address
+ length
;
415 * Read `length` bytes into the provided `buffer` from the flash starting from the given `address` (which need not lie
416 * on a page boundary).
418 * Waits up to DEFAULT_TIMEOUT_MILLIS milliseconds for the flash to become ready before reading.
420 * The number of bytes actually read is returned, which can be zero if an error or timeout occurred.
422 int m25p16_readBytes(uint32_t address
, uint8_t *buffer
, int length
)
424 if (!m25p16_waitForReady(0)) {
428 #if !defined(M25P16_QUADSPI_DEVICE)
429 uint8_t command
[5] = { M25P16_INSTRUCTION_READ_BYTES
};
431 busTransferDescriptor_t txn
[2] = {
432 { NULL
, command
, isLargeFlash
? 5 : 4 },
433 { buffer
, NULL
, length
}
436 m25p16_setCommandAddress(&command
[1], address
, isLargeFlash
);
438 busTransferMultiple(busDev
, txn
, 2);
440 quadSpiReceiveWithAddress4LINES(qspi
, M25P16_INSTRUCTION_QUAD_READ
, M25P16_FAST_READ_DUMMY_CYCLES
,
441 address
, isLargeFlash
? 32 : 24, buffer
, length
);
442 #endif /* !defined(M25P16_QUADSPI_DEVICE) */
448 * Fetch information about the detected flash chip layout.
450 * Can be called before calling m25p16_init() (the result would have totalSize = 0).
452 const flashGeometry_t
* m25p16_getGeometry(void)