Support 'EEPROM' in file on SD card. (#8379)

Support 'EEPROM' in file on SD card.
This commit is contained in:
Michael Keller 2019-06-14 09:28:57 +12:00 committed by GitHub
commit b5a6b543a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 268 additions and 36 deletions

View File

@ -3315,6 +3315,7 @@ static void cliRebootEx(bool bootLoader)
bufWriterFlush(cliWriter);
waitForSerialPortToFinishTransmitting(cliPort);
stopPwmAllMotors();
if (bootLoader) {
systemResetToBootloader();
return;

View File

@ -34,6 +34,10 @@
#include "pg/pg.h"
#include "fc/config.h"
#ifdef EEPROM_IN_SDCARD
#include "io/asyncfatfs/asyncfatfs.h"
#endif
#include "drivers/flash.h"
#include "drivers/system.h"
@ -79,7 +83,7 @@ typedef struct {
uint32_t word;
} PG_PACKED packingTest_t;
#ifdef EEPROM_IN_EXTERNAL_FLASH
#if defined(EEPROM_IN_EXTERNAL_FLASH)
bool loadEEPROMFromExternalFlash(void)
{
const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_CONFIG);
@ -102,6 +106,134 @@ bool loadEEPROMFromExternalFlash(void)
return success;
}
#elif defined(EEPROM_IN_SDCARD)
enum {
FILE_STATE_NONE = 0,
FILE_STATE_BUSY = 1,
FILE_STATE_FAILED,
FILE_STATE_COMPLETE,
};
uint8_t fileState = FILE_STATE_NONE;
const char *defaultSDCardConfigFilename = "CONFIG.BIN";
void saveEEPROMToSDCardCloseContinue(void)
{
if (fileState != FILE_STATE_FAILED) {
fileState = FILE_STATE_COMPLETE;
}
}
void saveEEPROMToSDCardWriteContinue(afatfsFilePtr_t file)
{
if (!file) {
fileState = FILE_STATE_FAILED;
return;
}
uint32_t totalBytesWritten = 0;
uint32_t bytesWritten = 0;
bool success;
do {
bytesWritten = afatfs_fwrite(file, &eepromData[totalBytesWritten], EEPROM_SIZE - totalBytesWritten);
totalBytesWritten += bytesWritten;
success = (totalBytesWritten == EEPROM_SIZE);
afatfs_poll();
} while (!success && afatfs_getLastError() == AFATFS_ERROR_NONE);
if (!success) {
fileState = FILE_STATE_FAILED;
}
while (!afatfs_fclose(file, saveEEPROMToSDCardCloseContinue)) {
afatfs_poll();
}
}
bool saveEEPROMToSDCard(void)
{
fileState = FILE_STATE_BUSY;
bool result = afatfs_fopen(defaultSDCardConfigFilename, "w+", saveEEPROMToSDCardWriteContinue);
if (!result) {
return false;
}
while (fileState == FILE_STATE_BUSY) {
afatfs_poll();
}
while (!afatfs_flush()) {
afatfs_poll();
};
return (fileState == FILE_STATE_COMPLETE);
}
void loadEEPROMFromSDCardCloseContinue(void)
{
if (fileState != FILE_STATE_FAILED) {
fileState = FILE_STATE_COMPLETE;
}
}
void loadEEPROMFromSDCardReadContinue(afatfsFilePtr_t file)
{
if (!file) {
fileState = FILE_STATE_FAILED;
return;
}
fileState = FILE_STATE_BUSY;
uint32_t totalBytesRead = 0;
uint32_t bytesRead = 0;
bool success;
if (afatfs_feof(file)) {
// empty file, nothing to load.
memset(eepromData, 0x00, EEPROM_SIZE);
success = true;
} else {
do {
bytesRead = afatfs_fread(file, &eepromData[totalBytesRead], EEPROM_SIZE - totalBytesRead);
totalBytesRead += bytesRead;
success = (totalBytesRead == EEPROM_SIZE);
afatfs_poll();
} while (!success && afatfs_getLastError() == AFATFS_ERROR_NONE);
}
if (!success) {
fileState = FILE_STATE_FAILED;
}
while (!afatfs_fclose(file, loadEEPROMFromSDCardCloseContinue)) {
afatfs_poll();
}
return;
}
bool loadEEPROMFromSDCard(void)
{
fileState = FILE_STATE_BUSY;
// use "w+" mode here to ensure the file is created now - in w+ mode we can read and write and the seek position is 0 on existing files, ready for reading.
bool result = afatfs_fopen(defaultSDCardConfigFilename, "w+", loadEEPROMFromSDCardReadContinue);
if (!result) {
return false;
}
while (fileState == FILE_STATE_BUSY) {
afatfs_poll();
}
return (fileState == FILE_STATE_COMPLETE);
}
#endif
#ifdef EEPROM_IN_FILE
@ -120,16 +252,20 @@ void initEEPROM(void)
STATIC_ASSERT(sizeof(configFooter_t) == 2, footer_size_failed);
STATIC_ASSERT(sizeof(configRecord_t) == 6, record_size_failed);
#ifdef EEPROM_IN_FILE
#if defined(EEPROM_IN_FILE)
loadEEPROMFromFile();
#endif
#ifdef EEPROM_IN_EXTERNAL_FLASH
#elif defined(EEPROM_IN_EXTERNAL_FLASH)
bool eepromLoaded = loadEEPROMFromExternalFlash();
if (!eepromLoaded) {
// Flash read failed - just die now
failureMode(FAILURE_FLASH_READ_FAILED);
}
#elif defined(EEPROM_IN_SDCARD)
bool eepromLoaded = loadEEPROMFromSDCard();
if (!eepromLoaded) {
// SDCard read failed - just die now
failureMode(FAILURE_SDCARD_READ_FAILED);
}
#endif
}
@ -317,6 +453,10 @@ void writeConfigToEEPROM(void)
#ifdef EEPROM_IN_EXTERNAL_FLASH
// copy it back from flash to the in-memory buffer.
success = loadEEPROMFromExternalFlash();
#endif
#ifdef EEPROM_IN_SDCARD
// copy it back from flash to the in-memory buffer.
success = loadEEPROMFromSDCard();
#endif
}
}
@ -327,5 +467,5 @@ void writeConfigToEEPROM(void)
}
// Flash write failed - just die now
failureMode(FAILURE_FLASH_WRITE_FAILED);
failureMode(FAILURE_CONFIG_STORE_FAILURE);
}

View File

@ -27,7 +27,16 @@
#include "config/config_streamer.h"
#if defined(STM32H750xx) && !(defined(EEPROM_IN_EXTERNAL_FLASH) || defined(EEPROM_IN_RAM))
#if !defined(EEPROM_IN_FLASH)
#if defined(EEPROM_IN_RAM) && defined(PERSISTENT)
PERSISTENT uint8_t eepromData[EEPROM_SIZE];
#else
uint8_t eepromData[EEPROM_SIZE];
#endif
#endif
#if defined(STM32H750xx) && !(defined(EEPROM_IN_EXTERNAL_FLASH) || defined(EEPROM_IN_RAM) || defined(EEPROM_IN_SDCARD))
#error "STM32750xx only has one flash page which contains the bootloader, no spare flash pages available, use external storage for persistent config or ram for target testing"
#endif
// @todo this is not strictly correct for F4/F7, where sector sizes are variable
@ -82,7 +91,7 @@ void config_streamer_start(config_streamer_t *c, uintptr_t base, int size)
c->address = base;
c->size = size;
if (!c->unlocked) {
#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_EXTERNAL_FLASH)
#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_EXTERNAL_FLASH) || defined(EEPROM_IN_SDCARD)
// NOP
#elif defined(EEPROM_IN_FLASH) || defined(EEPROM_IN_FILE)
#if defined(STM32F7) || defined(STM32H7)
@ -116,7 +125,7 @@ void config_streamer_start(config_streamer_t *c, uintptr_t base, int size)
c->err = 0;
}
#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_EXTERNAL_FLASH)
#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_EXTERNAL_FLASH) || defined(EEPROM_IN_SDCARD)
// No flash sector method required.
#elif defined(EEPROM_IN_FLASH)
#if defined(STM32F745xx) || defined(STM32F746xx) || defined(STM32F765xx)
@ -168,7 +177,7 @@ static uint32_t getFLASHSectorForEEPROM(void)
// Not good
while (1) {
failureMode(FAILURE_FLASH_WRITE_FAILED);
failureMode(FAILURE_CONFIG_STORE_FAILURE);
}
}
@ -205,7 +214,7 @@ static uint32_t getFLASHSectorForEEPROM(void)
// Not good
while (1) {
failureMode(FAILURE_FLASH_WRITE_FAILED);
failureMode(FAILURE_CONFIG_STORE_FAILURE);
}
}
@ -254,7 +263,7 @@ static uint32_t getFLASHSectorForEEPROM(void)
// Not good
while (1) {
failureMode(FAILURE_FLASH_WRITE_FAILED);
failureMode(FAILURE_CONFIG_STORE_FAILURE);
}
}
@ -296,7 +305,7 @@ static void getFLASHSectorForEEPROM(uint32_t *bank, uint32_t *sector)
} else {
// Not good
while (1) {
failureMode(FAILURE_FLASH_WRITE_FAILED);
failureMode(FAILURE_CONFIG_STORE_FAILURE);
}
}
@ -338,7 +347,7 @@ static void getFLASHSectorForEEPROM(uint32_t *bank, uint32_t *sector)
} else {
// Not good
while (1) {
failureMode(FAILURE_FLASH_WRITE_FAILED);
failureMode(FAILURE_CONFIG_STORE_FAILURE);
}
}
}
@ -386,7 +395,7 @@ static int write_word(config_streamer_t *c, config_streamer_buffer_align_type_t
flashPageProgramContinue((uint8_t *)buffer, CONFIG_STREAMER_BUFFER_SIZE);
#elif defined(EEPROM_IN_RAM)
#elif defined(EEPROM_IN_RAM) || defined(EEPROM_IN_SDCARD)
if (c->address == (uintptr_t)&eepromData[0]) {
memset(eepromData, 0, sizeof(eepromData));
}
@ -394,7 +403,7 @@ static int write_word(config_streamer_t *c, config_streamer_buffer_align_type_t
uint64_t *dest_addr = (uint64_t *)c->address;
uint64_t *src_addr = (uint64_t*)buffer;
uint8_t row_index = 4;
/* Program the 256 bits flash word */
/* copy the 256 bits flash word */
do
{
*dest_addr++ = *src_addr++;
@ -509,7 +518,11 @@ int config_streamer_flush(config_streamer_t *c)
int config_streamer_finish(config_streamer_t *c)
{
if (c->unlocked) {
#if defined(EEPROM_IN_EXTERNAL_FLASH)
#if defined(EEPROM_IN_SDCARD)
bool saveEEPROMToSDCard(void); // XXX forward declaration to avoid circular dependency between config_streamer / config_eeprom
saveEEPROMToSDCard();
// TODO overwrite the data in the file on the SD card.
#elif defined(EEPROM_IN_EXTERNAL_FLASH)
flashFlush();
#elif defined(EEPROM_IN_RAM)
// NOP

View File

@ -31,10 +31,17 @@ typedef enum {
FAILURE_ACC_INIT,
FAILURE_ACC_INCOMPATIBLE,
FAILURE_INVALID_EEPROM_CONTENTS,
FAILURE_FLASH_WRITE_FAILED,
FAILURE_CONFIG_STORE_FAILURE,
FAILURE_GYRO_INIT_FAILED,
FAILURE_FLASH_READ_FAILED,
FAILURE_EXTERNAL_FLASH_INIT_FAILED
FAILURE_FLASH_WRITE_FAILED,
FAILURE_FLASH_INIT_FAILED, // RESERVED
FAILURE_EXTERNAL_FLASH_READ_FAILED, // RESERVED
FAILURE_EXTERNAL_FLASH_WRITE_FAILED, // RESERVED
FAILURE_EXTERNAL_FLASH_INIT_FAILED,
FAILURE_SDCARD_READ_FAILED,
FAILURE_SDCARD_WRITE_FAILED,
FAILURE_SDCARD_INITIALISATION_FAILED,
} failureMode_e;
#define WARNING_FLASH_DURATION_MS 50

View File

@ -179,6 +179,8 @@ serialPort_t *loopbackPort;
uint8_t systemState = SYSTEM_STATE_INITIALISING;
void SDIO_GPIO_Init(void);
void processLoopback(void)
{
#ifdef SOFTSERIAL_LOOPBACK
@ -246,6 +248,13 @@ static void configureSPIAndQuadSPI(void)
#endif // USE_QUAD_SPI
}
void sdCardAndFSInit()
{
sdcardInsertionDetectInit();
sdcard_init(sdcardConfig());
afatfs_init();
}
void init(void)
{
@ -292,14 +301,69 @@ void init(void)
}
#endif
#ifdef EEPROM_IN_EXTERNAL_FLASH
enum {
FLASH_INIT_ATTEMPTED = (1 << 0),
SD_INIT_ATTEMPTED = (1 << 1),
SPI_AND_QSPI_INIT_ATTEMPTED = (1 << 2),
};
uint8_t initFlags = 0;
#ifdef EEPROM_IN_SDCARD
//
// Config in sdcard presents an issue with pin configuration since the pin and sdcard configs for the
// sdcard are in the config which is on the sdcard which we can't read yet!
//
// FIXME We need to add configuration somewhere, e.g. bootloader image or reserved flash area, that can be read by the firmware.
// it's currently possible for the firmware resource allocation to be wrong after the config is loaded if the user changes the settings.
// This would cause undefined behaviour once the config is loaded. so for now, users must NOT change sdio/spi configs needed for
// the system to boot and/or to save the config.
//
// note that target specific SDCARD/SDIO/SPI/QUADSPI configs are
// also not supported in USE_TARGET_CONFIG/targetConfigure() when using EEPROM_IN_SDCARD.
//
//
// IMPORTANT: all default flash and pin configurations must be valid for the target after pgResetAll() is called.
// Target designers must ensure other devices connected the same SPI/QUADSPI interface as the flash chip do not
// cause communication issues with the flash chip. e.g. use external pullups on SPI/QUADSPI CS lines.
//
#ifdef TARGET_BUS_INIT
#error "EEPROM_IN_SDCARD and TARGET_BUS_INIT are mutually exclusive"
#endif
pgResetAll();
#if defined(STM32H7) && defined(USE_SDCARD_SDIO) // H7 only for now, likely should be applied to F4/F7 too
SDIO_GPIO_Init();
#endif
#ifdef USE_SDCARD_SPI
configureSPIAndQuadSPI();
initFlags |= SPI_AND_QSPI_INIT_ATTEMPTED;
#endif
sdCardAndFSInit();
initFlags |= SD_INIT_ATTEMPTED;
while (afatfs_getFilesystemState() != AFATFS_FILESYSTEM_STATE_READY) {
afatfs_poll();
if (afatfs_getFilesystemState() == AFATFS_FILESYSTEM_STATE_FATAL) {
failureMode(FAILURE_SDCARD_INITIALISATION_FAILED);
}
}
#endif // EEPROM_IN_SDCARD
#ifdef EEPROM_IN_EXTERNAL_FLASH
//
// Config on external flash presents an issue with pin configuration since the pin and flash configs for the
// external flash are in the config which is on a chip which we can't read yet!
//
// FIXME We need to add configuration into the bootloader image that can be read by the firmware.
// it's currently possible firmware and bootloader to become mismatched if the user changes them.
// FIXME We need to add configuration somewhere, e.g. bootloader image or reserved flash area, that can be read by the firmware.
// it's currently possible for the firmware resource allocation to be wrong after the config is loaded if the user changes the settings.
// This would cause undefined behaviour once the config is loaded. so for now, users must NOT change flash/pin configs needed for
// the system to boot and/or to save the config.
//
@ -319,6 +383,8 @@ void init(void)
#endif
configureSPIAndQuadSPI();
initFlags |= SPI_AND_QSPI_INIT_ATTEMPTED;
#ifndef USE_FLASH_CHIP
#error "EEPROM_IN_EXTERNAL_FLASH requires USE_FLASH_CHIP to be defined."
@ -329,10 +395,10 @@ void init(void)
if (!haveFlash) {
failureMode(FAILURE_EXTERNAL_FLASH_INIT_FAILED);
}
initFlags |= FLASH_INIT_ATTEMPTED;
#endif // EEPROM_IN_EXTERNAL_FLASH
initEEPROM();
ensureEEPROMStructureIsValid();
@ -517,9 +583,11 @@ void init(void)
#else
#ifndef EEPROM_IN_EXTERNAL_FLASH
configureSPIAndQuadSPI();
#endif // EEPROM_IN_EXTERNAL_FLASH
// Depending on compilation options SPI/QSPI initialisation may already be done.
if (!(initFlags & SPI_AND_QSPI_INIT_ATTEMPTED)) {
configureSPIAndQuadSPI();
initFlags |= SPI_AND_QSPI_INIT_ATTEMPTED;
}
#ifdef USE_USB_MSC
/* MSC mode will start after init, but will not allow scheduler to run,
@ -567,10 +635,12 @@ void init(void)
#endif
#if defined(STM32H7) && defined(USE_SDCARD_SDIO) // H7 only for now, likely should be applied to F4/F7 too
void SDIO_GPIO_Init(void);
SDIO_GPIO_Init();
if (!(initFlags & SD_INIT_ATTEMPTED)) {
SDIO_GPIO_Init();
}
#endif
#ifdef USE_VTX_RTC6705
bool useRTC6705 = rtc6705IOInit(vtxIOConfig());
#endif
@ -763,10 +833,11 @@ void init(void)
}
#endif
#ifndef EEPROM_IN_EXTERNAL_FLASH
#ifdef USE_FLASH_CHIP
flashInit(flashConfig());
#endif
if (!(initFlags & FLASH_INIT_ATTEMPTED)) {
flashInit(flashConfig());
initFlags |= FLASH_INIT_ATTEMPTED;
}
#endif
#ifdef USE_FLASHFS
flashfsInit();
@ -776,9 +847,10 @@ void init(void)
#ifdef USE_SDCARD
if (blackboxConfig()->device == BLACKBOX_DEVICE_SDCARD) {
if (sdcardConfig()->mode) {
sdcardInsertionDetectInit();
sdcard_init(sdcardConfig());
afatfs_init();
if (!(initFlags & SD_INIT_ATTEMPTED)) {
initFlags |= SD_INIT_ATTEMPTED;
sdCardAndFSInit();
}
} else {
blackboxConfigMutable()->device = BLACKBOX_DEVICE_NONE;
}

View File

@ -468,7 +468,6 @@ char _Min_Stack_Size;
// fake EEPROM
static FILE *eepromFd = NULL;
uint8_t eepromData[EEPROM_SIZE];
void FLASH_Unlock(void) {
if (eepromFd != NULL) {

View File

@ -338,7 +338,7 @@
#undef USE_ESCSERIAL
#endif
#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_FILE) || defined(EEPROM_IN_EXTERNAL_FLASH)
#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_FILE) || defined(EEPROM_IN_EXTERNAL_FLASH) || defined(EEPROM_IN_SDCARD)
#ifndef EEPROM_SIZE
#define EEPROM_SIZE 4096
#endif