Merge pull request #9742 from mikeller/fix_spi_transaction_support
[betaflight.git] / src / main / drivers / flash.c
blob6318bdb2b4b0046016dda1cd0ffce09cdd9999f7
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
25 #include "platform.h"
27 #include "build/debug.h"
29 #ifdef USE_FLASH_CHIP
31 #include "flash.h"
32 #include "flash_impl.h"
33 #include "flash_m25p16.h"
34 #include "flash_w25n01g.h"
35 #include "flash_w25m.h"
36 #include "drivers/bus_spi.h"
37 #include "drivers/bus_quadspi.h"
38 #include "drivers/io.h"
39 #include "drivers/time.h"
41 static busDevice_t busInstance;
42 static busDevice_t *busdev;
44 static flashDevice_t flashDevice;
45 static flashPartitionTable_t flashPartitionTable;
46 static int flashPartitions = 0;
48 #define FLASH_INSTRUCTION_RDID 0x9F
50 #ifdef USE_QUADSPI
51 static bool flashQuadSpiInit(const flashConfig_t *flashConfig)
53 QUADSPI_TypeDef *quadSpiInstance = quadSpiInstanceByDevice(QUADSPI_CFG_TO_DEV(flashConfig->quadSpiDevice));
54 quadSpiSetDivisor(quadSpiInstance, QUADSPI_CLOCK_INITIALISATION);
56 uint8_t readIdResponse[4];
57 bool status = quadSpiReceive1LINE(quadSpiInstance, FLASH_INSTRUCTION_RDID, 8, readIdResponse, sizeof(readIdResponse));
58 if (!status) {
59 return false;
62 flashDevice.io.mode = FLASHIO_QUADSPI;
63 flashDevice.io.handle.quadSpi = quadSpiInstance;
65 // Manufacturer, memory type, and capacity
66 uint32_t chipID = (readIdResponse[0] << 16) | (readIdResponse[1] << 8) | (readIdResponse[2]);
68 #ifdef USE_FLASH_W25N01G
69 quadSpiSetDivisor(quadSpiInstance, QUADSPI_CLOCK_ULTRAFAST);
71 if (w25n01g_detect(&flashDevice, chipID)) {
72 return true;
74 #endif
76 return false;
78 #endif // USE_QUADSPI
80 #ifdef USE_SPI
82 void flashPreInit(const flashConfig_t *flashConfig)
84 spiPreinitRegister(flashConfig->csTag, IOCFG_IPU, 1);
87 static bool flashSpiInit(const flashConfig_t *flashConfig)
89 // Read chip identification and send it to device detect
91 busdev = &busInstance;
93 if (flashConfig->csTag) {
94 busdev->busdev_u.spi.csnPin = IOGetByTag(flashConfig->csTag);
95 } else {
96 return false;
99 if (!IOIsFreeOrPreinit(busdev->busdev_u.spi.csnPin)) {
100 return false;
103 busdev->bustype = BUSTYPE_SPI;
105 SPI_TypeDef *instance = spiInstanceByDevice(SPI_CFG_TO_DEV(flashConfig->spiDevice));
106 if (!instance) {
107 return false;
110 spiBusSetInstance(busdev, instance);
112 IOInit(busdev->busdev_u.spi.csnPin, OWNER_FLASH_CS, 0);
113 IOConfigGPIO(busdev->busdev_u.spi.csnPin, SPI_IO_CS_CFG);
114 IOHi(busdev->busdev_u.spi.csnPin);
116 #ifdef USE_SPI_TRANSACTION
117 spiBusTransactionInit(busdev, SPI_MODE3_POL_HIGH_EDGE_2ND, SPI_CLOCK_FAST);
118 #else
119 #ifndef FLASH_SPI_SHARED
120 //Maximum speed for standard READ command is 20mHz, other commands tolerate 25mHz
121 //spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_FAST);
122 spiSetDivisor(busdev->busdev_u.spi.instance, SPI_CLOCK_STANDARD*2);
123 #endif
124 #endif
126 flashDevice.io.mode = FLASHIO_SPI;
127 flashDevice.io.handle.busdev = busdev;
129 const uint8_t out[] = { FLASH_INSTRUCTION_RDID, 0, 0, 0, 0 };
131 delay(50); // short delay required after initialisation of SPI device instance.
134 * Some newer chips require one dummy byte to be read; we can read
135 * 4 bytes for these chips while retaining backward compatibility.
137 uint8_t readIdResponse[5];
138 readIdResponse[1] = readIdResponse[2] = 0;
140 // Clearing the CS bit terminates the command early so we don't have to read the chip UID:
141 #ifdef USE_SPI_TRANSACTION
142 spiBusTransactionTransfer(busdev, out, readIdResponse, sizeof(out));
143 #else
144 spiBusTransfer(busdev, out, readIdResponse, sizeof(out));
145 #endif
147 // Manufacturer, memory type, and capacity
148 uint32_t chipID = (readIdResponse[1] << 16) | (readIdResponse[2] << 8) | (readIdResponse[3]);
150 #ifdef USE_FLASH_M25P16
151 if (m25p16_detect(&flashDevice, chipID)) {
152 return true;
154 #endif
156 #ifdef USE_FLASH_W25M512
157 if (w25m_detect(&flashDevice, chipID)) {
158 return true;
160 #endif
162 // Newer chips
163 chipID = (readIdResponse[2] << 16) | (readIdResponse[3] << 8) | (readIdResponse[4]);
165 #ifdef USE_FLASH_W25N01G
166 if (w25n01g_detect(&flashDevice, chipID)) {
167 return true;
169 #endif
171 #ifdef USE_FLASH_W25M02G
172 if (w25m_detect(&flashDevice, chipID)) {
173 return true;
175 #endif
177 spiPreinitByTag(flashConfig->csTag);
179 return false;
181 #endif // USE_SPI
183 bool flashDeviceInit(const flashConfig_t *flashConfig)
185 #ifdef USE_SPI
186 bool useSpi = (SPI_CFG_TO_DEV(flashConfig->spiDevice) != SPIINVALID);
188 if (useSpi) {
189 return flashSpiInit(flashConfig);
191 #endif
193 #ifdef USE_QUADSPI
194 bool useQuadSpi = (QUADSPI_CFG_TO_DEV(flashConfig->quadSpiDevice) != QUADSPIINVALID);
195 if (useQuadSpi) {
196 return flashQuadSpiInit(flashConfig);
198 #endif
200 return false;
203 bool flashIsReady(void)
205 return flashDevice.vTable->isReady(&flashDevice);
208 bool flashWaitForReady(void)
210 return flashDevice.vTable->waitForReady(&flashDevice);
213 void flashEraseSector(uint32_t address)
215 flashDevice.vTable->eraseSector(&flashDevice, address);
218 void flashEraseCompletely(void)
220 flashDevice.vTable->eraseCompletely(&flashDevice);
223 void flashPageProgramBegin(uint32_t address)
225 flashDevice.vTable->pageProgramBegin(&flashDevice, address);
228 void flashPageProgramContinue(const uint8_t *data, int length)
230 flashDevice.vTable->pageProgramContinue(&flashDevice, data, length);
233 void flashPageProgramFinish(void)
235 flashDevice.vTable->pageProgramFinish(&flashDevice);
238 void flashPageProgram(uint32_t address, const uint8_t *data, int length)
240 flashDevice.vTable->pageProgram(&flashDevice, address, data, length);
243 int flashReadBytes(uint32_t address, uint8_t *buffer, int length)
245 return flashDevice.vTable->readBytes(&flashDevice, address, buffer, length);
248 void flashFlush(void)
250 if (flashDevice.vTable->flush) {
251 flashDevice.vTable->flush(&flashDevice);
255 static const flashGeometry_t noFlashGeometry = {
256 .totalSize = 0,
259 const flashGeometry_t *flashGetGeometry(void)
261 if (flashDevice.vTable && flashDevice.vTable->getGeometry) {
262 return flashDevice.vTable->getGeometry(&flashDevice);
265 return &noFlashGeometry;
269 * Flash partitioning
271 * Partition table is not currently stored on the flash, in-memory only.
273 * Partitions are required so that Badblock management (inc spare blocks), FlashFS (Blackbox Logging), Configuration and Firmware can be kept separate and tracked.
275 * XXX FIXME
276 * XXX Note that Flash FS must start at sector 0.
277 * XXX There is existing blackbox/flash FS code the relies on this!!!
278 * XXX This restriction can and will be fixed by creating a set of flash operation functions that take partition as an additional parameter.
281 static void flashConfigurePartitions(void)
284 const flashGeometry_t *flashGeometry = flashGetGeometry();
285 if (flashGeometry->totalSize == 0) {
286 return;
289 flashSector_t startSector = 0;
290 flashSector_t endSector = flashGeometry->sectors - 1; // 0 based index
292 const flashPartition_t *badBlockPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_BADBLOCK_MANAGEMENT);
293 if (badBlockPartition) {
294 endSector = badBlockPartition->startSector - 1;
297 #if defined(FIRMWARE_SIZE)
298 const uint32_t firmwareSize = (FIRMWARE_SIZE * 1024);
299 flashSector_t firmwareSectors = (firmwareSize / flashGeometry->sectorSize);
301 if (firmwareSize % flashGeometry->sectorSize > 0) {
302 firmwareSectors++; // needs a portion of a sector.
305 startSector = (endSector + 1) - firmwareSectors; // + 1 for inclusive
307 flashPartitionSet(FLASH_PARTITION_TYPE_FIRMWARE, startSector, endSector);
309 endSector = startSector - 1;
310 startSector = 0;
311 #endif
313 #if defined(CONFIG_IN_EXTERNAL_FLASH)
314 const uint32_t configSize = EEPROM_SIZE;
315 flashSector_t configSectors = (configSize / flashGeometry->sectorSize);
317 if (configSize % flashGeometry->sectorSize > 0) {
318 configSectors++; // needs a portion of a sector.
321 startSector = (endSector + 1) - configSectors; // + 1 for inclusive
323 flashPartitionSet(FLASH_PARTITION_TYPE_CONFIG, startSector, endSector);
325 endSector = startSector - 1;
326 startSector = 0;
327 #endif
329 #ifdef USE_FLASHFS
330 flashPartitionSet(FLASH_PARTITION_TYPE_FLASHFS, startSector, endSector);
331 #endif
334 flashPartition_t *flashPartitionFindByType(uint8_t type)
336 for (int index = 0; index < FLASH_MAX_PARTITIONS; index++) {
337 flashPartition_t *candidate = &flashPartitionTable.partitions[index];
338 if (candidate->type == type) {
339 return candidate;
343 return NULL;
346 const flashPartition_t *flashPartitionFindByIndex(uint8_t index)
348 if (index >= flashPartitions) {
349 return NULL;
352 return &flashPartitionTable.partitions[index];
355 void flashPartitionSet(uint8_t type, uint32_t startSector, uint32_t endSector)
357 flashPartition_t *entry = flashPartitionFindByType(type);
359 if (!entry) {
360 if (flashPartitions == FLASH_MAX_PARTITIONS - 1) {
361 return;
363 entry = &flashPartitionTable.partitions[flashPartitions++];
366 entry->type = type;
367 entry->startSector = startSector;
368 entry->endSector = endSector;
371 // Must be in sync with FLASH_PARTITION_TYPE
372 static const char *flashPartitionNames[] = {
373 "UNKNOWN ",
374 "PARTITION",
375 "FLASHFS ",
376 "BBMGMT ",
377 "FIRMWARE ",
378 "CONFIG ",
381 const char *flashPartitionGetTypeName(flashPartitionType_e type)
383 if (type < ARRAYLEN(flashPartitionNames)) {
384 return flashPartitionNames[type];
387 return NULL;
390 bool flashInit(const flashConfig_t *flashConfig)
392 memset(&flashPartitionTable, 0x00, sizeof(flashPartitionTable));
394 bool haveFlash = flashDeviceInit(flashConfig);
396 flashConfigurePartitions();
398 return haveFlash;
401 int flashPartitionCount(void)
403 return flashPartitions;
405 #endif // USE_FLASH_CHIP