mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-14 20:10:18 +03:00
Add flash partitioning system
This commit is contained in:
parent
ba047e0559
commit
92999681e3
9 changed files with 215 additions and 56 deletions
|
@ -2209,16 +2209,24 @@ static void cliSdInfo(char *cmdline)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_FLASHFS
|
#ifdef USE_FLASH_CHIP
|
||||||
|
|
||||||
static void cliFlashInfo(char *cmdline)
|
static void cliFlashInfo(char *cmdline)
|
||||||
{
|
{
|
||||||
const flashGeometry_t *layout = flashfsGetGeometry();
|
const flashGeometry_t *layout = flashGetGeometry();
|
||||||
|
|
||||||
UNUSED(cmdline);
|
UNUSED(cmdline);
|
||||||
|
|
||||||
cliPrintLinef("Flash sectors=%u, sectorSize=%u, pagesPerSector=%u, pageSize=%u, totalSize=%u, usedSize=%u",
|
cliPrintLinef("Flash sectors=%u, sectorSize=%u, pagesPerSector=%u, pageSize=%u, totalSize=%u",
|
||||||
layout->sectors, layout->sectorSize, layout->pagesPerSector, layout->pageSize, layout->totalSize, flashfsGetOffset());
|
layout->sectors, layout->sectorSize, layout->pagesPerSector, layout->pageSize, layout->totalSize);
|
||||||
|
#ifdef USE_FLASHFS
|
||||||
|
const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS);
|
||||||
|
|
||||||
|
cliPrintLinef("FlashFS size=%u, usedSize=%u",
|
||||||
|
FLASH_PARTITION_SECTOR_COUNT(flashPartition) * layout->sectorSize,
|
||||||
|
flashfsGetOffset()
|
||||||
|
);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -126,9 +126,11 @@ static void cmsx_Blackbox_GetDeviceStatus(void)
|
||||||
if (storageDeviceIsWorking) {
|
if (storageDeviceIsWorking) {
|
||||||
tfp_sprintf(cmsx_BlackboxStatus, "READY");
|
tfp_sprintf(cmsx_BlackboxStatus, "READY");
|
||||||
|
|
||||||
const flashGeometry_t *geometry = flashfsGetGeometry();
|
const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS);
|
||||||
|
const flashGeometry_t *flashGeometry = flashGetGeometry();
|
||||||
|
|
||||||
storageUsed = flashfsGetOffset() / 1024;
|
storageUsed = flashfsGetOffset() / 1024;
|
||||||
storageFree = (geometry->totalSize / 1024) - storageUsed;
|
storageFree = ((FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize) / 1024) - storageUsed;
|
||||||
} else {
|
} else {
|
||||||
tfp_sprintf(cmsx_BlackboxStatus, "FAULT");
|
tfp_sprintf(cmsx_BlackboxStatus, "FAULT");
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
|
|
||||||
|
@ -41,6 +42,9 @@ static busDevice_t busInstance;
|
||||||
static busDevice_t *busdev;
|
static busDevice_t *busdev;
|
||||||
|
|
||||||
static flashDevice_t flashDevice;
|
static flashDevice_t flashDevice;
|
||||||
|
static flashPartitionTable_t flashPartitionTable;
|
||||||
|
|
||||||
|
static void flashConfigurePartitions(void);
|
||||||
|
|
||||||
#define FLASH_INSTRUCTION_RDID 0x9F
|
#define FLASH_INSTRUCTION_RDID 0x9F
|
||||||
|
|
||||||
|
@ -177,7 +181,7 @@ static bool flashSpiInit(const flashConfig_t *flashConfig)
|
||||||
}
|
}
|
||||||
#endif // USE_SPI
|
#endif // USE_SPI
|
||||||
|
|
||||||
bool flashInit(const flashConfig_t *flashConfig)
|
bool flashDeviceInit(const flashConfig_t *flashConfig)
|
||||||
{
|
{
|
||||||
#ifdef USE_SPI
|
#ifdef USE_SPI
|
||||||
bool useSpi = (SPI_CFG_TO_DEV(flashConfig->spiDevice) != SPIINVALID);
|
bool useSpi = (SPI_CFG_TO_DEV(flashConfig->spiDevice) != SPIINVALID);
|
||||||
|
@ -197,6 +201,17 @@ bool flashInit(const flashConfig_t *flashConfig)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool flashInit(const flashConfig_t *flashConfig)
|
||||||
|
{
|
||||||
|
memset(&flashPartitionTable, 0x00, sizeof(flashPartitionTable));
|
||||||
|
|
||||||
|
bool haveFlash = flashDeviceInit(flashConfig);
|
||||||
|
|
||||||
|
flashConfigurePartitions();
|
||||||
|
|
||||||
|
return haveFlash;
|
||||||
|
}
|
||||||
|
|
||||||
bool flashIsReady(void)
|
bool flashIsReady(void)
|
||||||
{
|
{
|
||||||
return flashDevice.vTable->isReady(&flashDevice);
|
return flashDevice.vTable->isReady(&flashDevice);
|
||||||
|
@ -259,4 +274,90 @@ const flashGeometry_t *flashGetGeometry(void)
|
||||||
|
|
||||||
return &noFlashGeometry;
|
return &noFlashGeometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flash partitioning
|
||||||
|
*
|
||||||
|
* Partition table is not currently stored on the flash, in-memory only.
|
||||||
|
*
|
||||||
|
* Partitions are required so that Badblock management (inc spare blocks), FlashFS (Blackbox Logging), Configuration and Firmware can be kept separate and tracked.
|
||||||
|
*
|
||||||
|
* Currently, to keep things simple (and working), the following rules apply:
|
||||||
|
*
|
||||||
|
* 1) order of partitions in the paritions table strictly defined as follows
|
||||||
|
*
|
||||||
|
* BAD BLOCK MANAGEMENT
|
||||||
|
* FIRMWARE
|
||||||
|
* FLASH FS
|
||||||
|
*
|
||||||
|
* 2) If firmware or bootloader doesn't use or care about a particular type partition the corresponding entry should be empty, i.e. partition table entry memset to 0x00.
|
||||||
|
*
|
||||||
|
* 3) flash FS must start at sector 0. IMPORTANT: There is existing blackbox/flash FS code the relies on this!!!
|
||||||
|
*/
|
||||||
|
static void flashConfigurePartitions(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
const flashGeometry_t *flashGeometry = flashGetGeometry();
|
||||||
|
if (flashGeometry->totalSize == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flashSector_t startSector = 0;
|
||||||
|
flashSector_t endSector = flashGeometry->sectors - 1; // 0 based index
|
||||||
|
|
||||||
|
const flashPartition_t *badBlockPartition = flashFindPartitionByUsage(FLASH_PARTITION_BADBLOCK_MANAGEMENT);
|
||||||
|
if (badBlockPartition) {
|
||||||
|
endSector = badBlockPartition->startSector - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(FIRMWARE_SIZE)
|
||||||
|
const uint32_t firmwareSize = (FIRMWARE_SIZE * 1024);
|
||||||
|
flashSector_t firmwareSectors = (firmwareSize / flashGeometry->sectorSize);
|
||||||
|
|
||||||
|
if (firmwareSize % flashGeometry->sectorSize > 0) {
|
||||||
|
firmwareSectors++; // needs a portion of a sector.
|
||||||
|
}
|
||||||
|
|
||||||
|
startSector = (endSector + 1) - firmwareSectors; // + 1 for inclusive
|
||||||
|
|
||||||
|
const flashPartition_t firmwarePartition = {
|
||||||
|
.usage = FLASH_PARTITION_FIRMWARE,
|
||||||
|
.startSector = startSector,
|
||||||
|
.endSector = endSector
|
||||||
|
};
|
||||||
|
|
||||||
|
endSector = startSector - 1;
|
||||||
|
startSector = 0;
|
||||||
|
|
||||||
|
flashSetPartition(1, &firmwarePartition);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USE_FLASHFS
|
||||||
|
const flashPartition_t flashFsPartition = {
|
||||||
|
.usage = FLASH_PARTITION_FLASHFS,
|
||||||
|
.startSector = startSector,
|
||||||
|
.endSector = endSector
|
||||||
|
};
|
||||||
|
|
||||||
|
flashSetPartition(2, &flashFsPartition);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void flashSetPartition(uint8_t index, const flashPartition_t *partition)
|
||||||
|
{
|
||||||
|
memcpy(&flashPartitionTable.partitions[index], partition, sizeof(*partition));
|
||||||
|
}
|
||||||
|
|
||||||
|
const flashPartition_t *flashFindPartitionByUsage(uint8_t usage)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < FLASH_MAX_PARTITIONS; index++) {
|
||||||
|
flashPartition_t *candidate = &flashPartitionTable.partitions[index];
|
||||||
|
if (candidate->usage == usage) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // USE_FLASH_CHIP
|
#endif // USE_FLASH_CHIP
|
||||||
|
|
|
@ -36,8 +36,10 @@ typedef enum {
|
||||||
FLASH_TYPE_NAND
|
FLASH_TYPE_NAND
|
||||||
} flashType_e;
|
} flashType_e;
|
||||||
|
|
||||||
|
typedef uint16_t flashSector_t;
|
||||||
|
|
||||||
typedef struct flashGeometry_s {
|
typedef struct flashGeometry_s {
|
||||||
uint16_t sectors; // Count of the number of erasable blocks on the device
|
flashSector_t sectors; // Count of the number of erasable blocks on the device
|
||||||
uint16_t pageSize; // In bytes
|
uint16_t pageSize; // In bytes
|
||||||
uint32_t sectorSize; // This is just pagesPerSector * pageSize
|
uint32_t sectorSize; // This is just pagesPerSector * pageSize
|
||||||
uint32_t totalSize; // This is just sectorSize * sectors
|
uint32_t totalSize; // This is just sectorSize * sectors
|
||||||
|
@ -59,3 +61,29 @@ void flashPageProgram(uint32_t address, const uint8_t *data, int length);
|
||||||
int flashReadBytes(uint32_t address, uint8_t *buffer, int length);
|
int flashReadBytes(uint32_t address, uint8_t *buffer, int length);
|
||||||
void flashFlush(void);
|
void flashFlush(void);
|
||||||
const flashGeometry_t *flashGetGeometry(void);
|
const flashGeometry_t *flashGetGeometry(void);
|
||||||
|
|
||||||
|
//
|
||||||
|
// flash partitioning api
|
||||||
|
//
|
||||||
|
|
||||||
|
typedef struct flashPartition_s {
|
||||||
|
uint8_t usage;
|
||||||
|
flashSector_t startSector;
|
||||||
|
flashSector_t endSector;
|
||||||
|
} flashPartition_t;
|
||||||
|
|
||||||
|
#define FLASH_PARTITION_SECTOR_COUNT(partition) (partition->endSector + 1 - partition->startSector) // + 1 for inclusive, start and end sector can be the same sector.
|
||||||
|
|
||||||
|
#define FLASH_PARTITION_UNKNOWN 0
|
||||||
|
#define FLASH_PARTITION_FLASHFS 1
|
||||||
|
#define FLASH_PARTITION_BADBLOCK_MANAGEMENT 2
|
||||||
|
#define FLASH_PARTITION_FIRMWARE 3
|
||||||
|
|
||||||
|
#define FLASH_MAX_PARTITIONS 3
|
||||||
|
|
||||||
|
typedef struct flashPartitionTable_s {
|
||||||
|
flashPartition_t partitions[FLASH_MAX_PARTITIONS];
|
||||||
|
} flashPartitionTable_t;
|
||||||
|
|
||||||
|
void flashSetPartition(uint8_t index, const flashPartition_t *partition);
|
||||||
|
const flashPartition_t *flashFindPartitionByUsage(uint8_t usage);
|
||||||
|
|
|
@ -58,6 +58,15 @@ serialPort_t *debugSerialPort = NULL;
|
||||||
#define W25N01G_PAGES_PER_BLOCK 64
|
#define W25N01G_PAGES_PER_BLOCK 64
|
||||||
#define W25N01G_BLOCKS_PER_DIE 1024
|
#define W25N01G_BLOCKS_PER_DIE 1024
|
||||||
|
|
||||||
|
// BB replacement area
|
||||||
|
#define W25N01G_BB_MARKER_BLOCKS 1
|
||||||
|
#define W25N01G_BB_REPLACEMENT_BLOCKS 20
|
||||||
|
#define W25N01G_BB_MANAGEMENT_BLOCKS (W25N01G_BB_REPLACEMENT_BLOCKS + W25N01G_BB_MARKER_BLOCKS)
|
||||||
|
// blocks are zero-based index
|
||||||
|
#define W25N01G_BB_REPLACEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_REPLACEMENT_BLOCKS)
|
||||||
|
#define W25N01G_BB_MANAGEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_MANAGEMENT_BLOCKS)
|
||||||
|
#define W25N01G_BB_MARKER_BLOCK (W25N01G_BB_REPLACEMENT_START_BLOCK - W25N01G_BB_MARKER_BLOCKS)
|
||||||
|
|
||||||
// Instructions
|
// Instructions
|
||||||
|
|
||||||
#define W25N01G_INSTRUCTION_RDID 0x9F
|
#define W25N01G_INSTRUCTION_RDID 0x9F
|
||||||
|
@ -113,12 +122,6 @@ serialPort_t *debugSerialPort = NULL;
|
||||||
#define W25N01G_BLOCK_TO_PAGE(block) ((block) * W25N01G_PAGES_PER_BLOCK)
|
#define W25N01G_BLOCK_TO_PAGE(block) ((block) * W25N01G_PAGES_PER_BLOCK)
|
||||||
#define W25N01G_BLOCK_TO_LINEAR(block) (W25N01G_BLOCK_TO_PAGE(block) * W25N01G_PAGE_SIZE)
|
#define W25N01G_BLOCK_TO_LINEAR(block) (W25N01G_BLOCK_TO_PAGE(block) * W25N01G_PAGE_SIZE)
|
||||||
|
|
||||||
// BB replacement area
|
|
||||||
#define W25N01G_BB_MARKER_BLOCKS 1
|
|
||||||
#define W25N01G_BB_REPLACEMENT_BLOCKS 21
|
|
||||||
#define W25N01G_BB_REPLACEMENT_START_BLOCK (W25N01G_BLOCKS_PER_DIE - W25N01G_BB_REPLACEMENT_BLOCKS)
|
|
||||||
#define W25N01G_BB_MARKER_BLOCK (W25N01G_BB_REPLACEMENT_START_BLOCK - W25N01G_BB_MARKER_BLOCKS)
|
|
||||||
|
|
||||||
// The timeout values (2ms minimum to avoid 1 tick advance in consecutive calls to millis).
|
// The timeout values (2ms minimum to avoid 1 tick advance in consecutive calls to millis).
|
||||||
#define W25N01G_TIMEOUT_PAGE_READ_MS 2 // tREmax = 60us (ECC enabled)
|
#define W25N01G_TIMEOUT_PAGE_READ_MS 2 // tREmax = 60us (ECC enabled)
|
||||||
#define W25N01G_TIMEOUT_PAGE_PROGRAM_MS 2 // tPPmax = 700us
|
#define W25N01G_TIMEOUT_PAGE_PROGRAM_MS 2 // tPPmax = 700us
|
||||||
|
@ -322,6 +325,12 @@ static void w25n01g_writeEnable(flashDevice_t *fdevice)
|
||||||
*/
|
*/
|
||||||
const flashVTable_t w25n01g_vTable;
|
const flashVTable_t w25n01g_vTable;
|
||||||
|
|
||||||
|
static const flashPartition_t badBlockPartition = {
|
||||||
|
.usage = FLASH_PARTITION_BADBLOCK_MANAGEMENT,
|
||||||
|
.startSector = W25N01G_BB_MANAGEMENT_START_BLOCK,
|
||||||
|
.endSector = W25N01G_BB_MANAGEMENT_START_BLOCK + W25N01G_BB_MANAGEMENT_BLOCKS - 1 // -1 for inclusive, 0 based.
|
||||||
|
};
|
||||||
|
|
||||||
static void w25n01g_deviceInit(flashDevice_t *flashdev);
|
static void w25n01g_deviceInit(flashDevice_t *flashdev);
|
||||||
|
|
||||||
bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID)
|
bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID)
|
||||||
|
@ -354,10 +363,11 @@ bool w25n01g_detect(flashDevice_t *fdevice, uint32_t chipID)
|
||||||
}
|
}
|
||||||
|
|
||||||
fdevice->geometry.flashType = FLASH_TYPE_NAND;
|
fdevice->geometry.flashType = FLASH_TYPE_NAND;
|
||||||
fdevice->geometry.sectors -= W25N01G_BB_REPLACEMENT_BLOCKS;
|
|
||||||
fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize;
|
fdevice->geometry.sectorSize = fdevice->geometry.pagesPerSector * fdevice->geometry.pageSize;
|
||||||
fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors;
|
fdevice->geometry.totalSize = fdevice->geometry.sectorSize * fdevice->geometry.sectors;
|
||||||
|
|
||||||
|
flashSetPartition(0, &badBlockPartition);
|
||||||
|
|
||||||
fdevice->couldBeBusy = true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be
|
fdevice->couldBeBusy = true; // Just for luck we'll assume the chip could be busy even though it isn't specced to be
|
||||||
|
|
||||||
w25n01g_deviceReset(fdevice);
|
w25n01g_deviceReset(fdevice);
|
||||||
|
|
|
@ -716,11 +716,9 @@ void init(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_FLASH_CHIP
|
#ifdef USE_FLASH_CHIP
|
||||||
bool haveFlash = flashInit(flashConfig());
|
flashInit(flashConfig());
|
||||||
#ifdef USE_FLASHFS
|
#ifdef USE_FLASHFS
|
||||||
if (haveFlash) {
|
flashfsInit();
|
||||||
flashfsInit();
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,10 @@
|
||||||
|
|
||||||
#include "io/flashfs.h"
|
#include "io/flashfs.h"
|
||||||
|
|
||||||
|
static const flashPartition_t *flashPartition = NULL;
|
||||||
|
static const flashGeometry_t *flashGeometry = NULL;
|
||||||
|
static uint32_t flashfsSize = 0;
|
||||||
|
|
||||||
static uint8_t flashWriteBuffer[FLASHFS_WRITE_BUFFER_SIZE];
|
static uint8_t flashWriteBuffer[FLASHFS_WRITE_BUFFER_SIZE];
|
||||||
|
|
||||||
/* The position of our head and tail in the circular flash write buffer.
|
/* The position of our head and tail in the circular flash write buffer.
|
||||||
|
@ -74,7 +78,10 @@ static void flashfsSetTailAddress(uint32_t address)
|
||||||
|
|
||||||
void flashfsEraseCompletely(void)
|
void flashfsEraseCompletely(void)
|
||||||
{
|
{
|
||||||
flashEraseCompletely();
|
for (flashSector_t sectorIndex = flashPartition->startSector; sectorIndex <= flashPartition->endSector; sectorIndex++) {
|
||||||
|
uint32_t sectorAddress = sectorIndex * flashGeometry->sectorSize;
|
||||||
|
flashEraseSector(sectorAddress);
|
||||||
|
}
|
||||||
|
|
||||||
flashfsClearBuffer();
|
flashfsClearBuffer();
|
||||||
|
|
||||||
|
@ -87,24 +94,23 @@ void flashfsEraseCompletely(void)
|
||||||
*/
|
*/
|
||||||
void flashfsEraseRange(uint32_t start, uint32_t end)
|
void flashfsEraseRange(uint32_t start, uint32_t end)
|
||||||
{
|
{
|
||||||
const flashGeometry_t *geometry = flashGetGeometry();
|
if (flashGeometry->sectorSize <= 0)
|
||||||
|
|
||||||
if (geometry->sectorSize <= 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Round the start down to a sector boundary
|
// Round the start down to a sector boundary
|
||||||
int startSector = start / geometry->sectorSize;
|
int startSector = start / flashGeometry->sectorSize;
|
||||||
|
|
||||||
// And the end upward
|
// And the end upward
|
||||||
int endSector = end / geometry->sectorSize;
|
int endSector = end / flashGeometry->sectorSize;
|
||||||
int endRemainder = end % geometry->sectorSize;
|
int endRemainder = end % flashGeometry->sectorSize;
|
||||||
|
|
||||||
if (endRemainder > 0) {
|
if (endRemainder > 0) {
|
||||||
endSector++;
|
endSector++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = startSector; i < endSector; i++) {
|
for (int sectorIndex = startSector; sectorIndex < endSector; sectorIndex++) {
|
||||||
flashEraseSector(i * geometry->sectorSize);
|
uint32_t sectorAddress = sectorIndex * flashGeometry->sectorSize;
|
||||||
|
flashEraseSector(sectorAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,12 +126,12 @@ bool flashfsIsReady(void)
|
||||||
|
|
||||||
bool flashfsIsSupported(void)
|
bool flashfsIsSupported(void)
|
||||||
{
|
{
|
||||||
return flashfsGetSize() > 0;
|
return flashfsSize > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t flashfsGetSize(void)
|
uint32_t flashfsGetSize(void)
|
||||||
{
|
{
|
||||||
return flashGetGeometry()->totalSize;
|
return flashfsSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t flashfsTransmitBufferUsed(void)
|
static uint32_t flashfsTransmitBufferUsed(void)
|
||||||
|
@ -152,11 +158,6 @@ uint32_t flashfsGetWriteBufferFreeSpace(void)
|
||||||
return flashfsGetWriteBufferSize() - flashfsTransmitBufferUsed();
|
return flashfsGetWriteBufferSize() - flashfsTransmitBufferUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
const flashGeometry_t* flashfsGetGeometry(void)
|
|
||||||
{
|
|
||||||
return flashGetGeometry();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write the given buffers to flash sequentially at the current tail address, advancing the tail address after
|
* Write the given buffers to flash sequentially at the current tail address, advancing the tail address after
|
||||||
* each write.
|
* each write.
|
||||||
|
@ -192,7 +193,7 @@ static uint32_t flashfsWriteBuffers(uint8_t const **buffers, uint32_t *bufferSiz
|
||||||
|
|
||||||
uint32_t bytesTotalRemaining = bytesTotal;
|
uint32_t bytesTotalRemaining = bytesTotal;
|
||||||
|
|
||||||
uint16_t pageSize = flashfsGetGeometry()->pageSize;
|
uint16_t pageSize = flashGeometry->pageSize;
|
||||||
|
|
||||||
while (bytesTotalRemaining > 0) {
|
while (bytesTotalRemaining > 0) {
|
||||||
uint32_t bytesTotalThisIteration;
|
uint32_t bytesTotalThisIteration;
|
||||||
|
@ -482,9 +483,9 @@ int flashfsReadAbs(uint32_t address, uint8_t *buffer, unsigned int len)
|
||||||
int bytesRead;
|
int bytesRead;
|
||||||
|
|
||||||
// Did caller try to read past the end of the volume?
|
// Did caller try to read past the end of the volume?
|
||||||
if (address + len > flashfsGetSize()) {
|
if (address + len > flashfsSize) {
|
||||||
// Truncate their request
|
// Truncate their request
|
||||||
len = flashfsGetSize() - address;
|
len = flashfsSize - address;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Since the read could overlap data in our dirty buffers, force a sync to clear those first
|
// Since the read could overlap data in our dirty buffers, force a sync to clear those first
|
||||||
|
@ -528,7 +529,7 @@ int flashfsIdentifyStartOfFreeSpace(void)
|
||||||
} testBuffer;
|
} testBuffer;
|
||||||
|
|
||||||
int left = 0; // Smallest block index in the search region
|
int left = 0; // Smallest block index in the search region
|
||||||
int right = flashfsGetSize() / FREE_BLOCK_SIZE; // One past the largest block index in the search region
|
int right = flashfsSize / FREE_BLOCK_SIZE; // One past the largest block index in the search region
|
||||||
int mid;
|
int mid;
|
||||||
int result = right;
|
int result = right;
|
||||||
int i;
|
int i;
|
||||||
|
@ -571,12 +572,12 @@ int flashfsIdentifyStartOfFreeSpace(void)
|
||||||
*/
|
*/
|
||||||
bool flashfsIsEOF(void)
|
bool flashfsIsEOF(void)
|
||||||
{
|
{
|
||||||
return tailAddress >= flashfsGetSize();
|
return tailAddress >= flashfsSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
void flashfsClose(void)
|
void flashfsClose(void)
|
||||||
{
|
{
|
||||||
switch(flashfsGetGeometry()->flashType) {
|
switch(flashGeometry->flashType) {
|
||||||
case FLASH_TYPE_NOR:
|
case FLASH_TYPE_NOR:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -584,7 +585,7 @@ void flashfsClose(void)
|
||||||
flashFlush();
|
flashFlush();
|
||||||
|
|
||||||
// Advance tailAddress to next page boundary.
|
// Advance tailAddress to next page boundary.
|
||||||
uint32_t pageSize = flashfsGetGeometry()->pageSize;
|
uint32_t pageSize = flashGeometry->pageSize;
|
||||||
flashfsSetTailAddress((tailAddress + pageSize - 1) & ~(pageSize - 1));
|
flashfsSetTailAddress((tailAddress + pageSize - 1) & ~(pageSize - 1));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -594,30 +595,36 @@ void flashfsClose(void)
|
||||||
/**
|
/**
|
||||||
* Call after initializing the flash chip in order to set up the filesystem.
|
* Call after initializing the flash chip in order to set up the filesystem.
|
||||||
*/
|
*/
|
||||||
void flashfsInit(void)
|
void flashfsInit()
|
||||||
{
|
{
|
||||||
// If we have a flash chip present at all
|
flashfsSize = 0;
|
||||||
if (flashfsGetSize() > 0) {
|
|
||||||
// Start the file pointer off at the beginning of free space so caller can start writing immediately
|
flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS);
|
||||||
flashfsSeekAbs(flashfsIdentifyStartOfFreeSpace());
|
flashGeometry = flashGetGeometry();
|
||||||
|
|
||||||
|
if (!flashPartition) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flashfsSize = FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize;
|
||||||
|
|
||||||
|
// Start the file pointer off at the beginning of free space so caller can start writing immediately
|
||||||
|
flashfsSeekAbs(flashfsIdentifyStartOfFreeSpace());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_FLASH_TOOLS
|
#ifdef USE_FLASH_TOOLS
|
||||||
bool flashfsVerifyEntireFlash(void)
|
bool flashfsVerifyEntireFlash(void)
|
||||||
{
|
{
|
||||||
flashEraseCompletely();
|
flashfsEraseCompletely();
|
||||||
flashfsInit();
|
flashfsInit();
|
||||||
|
|
||||||
const flashGeometry_t *flashGeometry = flashfsGetGeometry();
|
|
||||||
|
|
||||||
uint32_t address = 0;
|
uint32_t address = 0;
|
||||||
flashfsSeekAbs(address);
|
flashfsSeekAbs(address);
|
||||||
|
|
||||||
const int bufferSize = 32;
|
const int bufferSize = 32;
|
||||||
char buffer[bufferSize + 1];
|
char buffer[bufferSize + 1];
|
||||||
|
|
||||||
const uint32_t testLimit = flashGeometry->totalSize;
|
const uint32_t testLimit = flashfsGetSize();
|
||||||
|
|
||||||
for (address = 0; address < testLimit; address += bufferSize) {
|
for (address = 0; address < testLimit; address += bufferSize) {
|
||||||
tfp_sprintf(buffer, "%08x >> **0123456789ABCDEF**", address);
|
tfp_sprintf(buffer, "%08x >> **0123456789ABCDEF**", address);
|
||||||
|
|
|
@ -337,10 +337,12 @@ static void serializeDataflashSummaryReply(sbuf_t *dst)
|
||||||
if (flashfsIsSupported()) {
|
if (flashfsIsSupported()) {
|
||||||
uint8_t flags = MSP_FLASHFS_FLAG_SUPPORTED;
|
uint8_t flags = MSP_FLASHFS_FLAG_SUPPORTED;
|
||||||
flags |= (flashfsIsReady() ? MSP_FLASHFS_FLAG_READY : 0);
|
flags |= (flashfsIsReady() ? MSP_FLASHFS_FLAG_READY : 0);
|
||||||
const flashGeometry_t *geometry = flashfsGetGeometry();
|
|
||||||
|
const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS);
|
||||||
|
|
||||||
sbufWriteU8(dst, flags);
|
sbufWriteU8(dst, flags);
|
||||||
sbufWriteU32(dst, geometry->sectors);
|
sbufWriteU32(dst, FLASH_PARTITION_SECTOR_COUNT(flashPartition));
|
||||||
sbufWriteU32(dst, geometry->totalSize);
|
sbufWriteU32(dst, flashfsGetSize());
|
||||||
sbufWriteU32(dst, flashfsGetOffset()); // Effectively the current number of bytes stored on the volume
|
sbufWriteU32(dst, flashfsGetOffset()); // Effectively the current number of bytes stored on the volume
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -432,8 +432,11 @@ static void osdGetBlackboxStatusString(char * buff)
|
||||||
#ifdef USE_FLASHFS
|
#ifdef USE_FLASHFS
|
||||||
case BLACKBOX_DEVICE_FLASH:
|
case BLACKBOX_DEVICE_FLASH:
|
||||||
if (storageDeviceIsWorking) {
|
if (storageDeviceIsWorking) {
|
||||||
const flashGeometry_t *geometry = flashfsGetGeometry();
|
|
||||||
storageTotal = geometry->totalSize / 1024;
|
const flashPartition_t *flashPartition = flashFindPartitionByUsage(FLASH_PARTITION_FLASHFS);
|
||||||
|
const flashGeometry_t *flashGeometry = flashGetGeometry();
|
||||||
|
|
||||||
|
storageTotal = ((FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize) / 1024);
|
||||||
storageUsed = flashfsGetOffset() / 1024;
|
storageUsed = flashfsGetOffset() / 1024;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue