From cf1ce1a67b49a0a111e6cce4d082b0bb4d084b92 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 13 May 2019 00:10:46 +0900 Subject: [PATCH] Support load/save configuration to external flash Fixes to 6a3e7d8e6 as the flash partition code had changed during the merge to master. --- Makefile | 1 - src/main/config/config_eeprom.c | 51 ++++++++++++- src/main/config/config_streamer.c | 55 ++++++++++++-- src/main/config/config_streamer.h | 5 +- src/main/drivers/system.h | 3 +- src/main/fc/init.c | 122 ++++++++++++++++++++---------- src/main/target/common_post.h | 2 +- 7 files changed, 189 insertions(+), 50 deletions(-) diff --git a/Makefile b/Makefile index 6c37848f6b..4ca97c3008 100644 --- a/Makefile +++ b/Makefile @@ -677,6 +677,5 @@ check-platform-included: # rebuild everything when makefile changes $(TARGET_OBJS): Makefile $(TARGET_DIR)/target.mk $(wildcard make/*) - # include auto-generated dependencies -include $(TARGET_DEPS) diff --git a/src/main/config/config_eeprom.c b/src/main/config/config_eeprom.c index 234a482ab0..64463b11bf 100644 --- a/src/main/config/config_eeprom.c +++ b/src/main/config/config_eeprom.c @@ -34,6 +34,7 @@ #include "pg/pg.h" #include "fc/config.h" +#include "drivers/flash.h" #include "drivers/system.h" static uint16_t eepromConfigSize; @@ -78,6 +79,35 @@ typedef struct { uint32_t word; } PG_PACKED packingTest_t; +#ifdef EEPROM_IN_EXTERNAL_FLASH +bool loadEEPROMFromExternalFlash(void) +{ + const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_CONFIG); + const flashGeometry_t *flashGeometry = flashGetGeometry(); + + uint32_t flashStartAddress = flashPartition->startSector * flashGeometry->sectorSize; + + uint32_t totalBytesRead = 0; + uint32_t bytesRead = 0; + + bool success; + + do { + bytesRead = flashReadBytes(flashStartAddress + totalBytesRead, &eepromData[totalBytesRead], EEPROM_SIZE - totalBytesRead); + totalBytesRead += bytesRead; + success = (totalBytesRead == EEPROM_SIZE); + } while (!success && bytesRead); + + return success; +} +#endif + +#ifdef EEPROM_IN_FILE +void loadEEPROMFromFile(void) { + FLASH_Unlock(); // load existing config file into eepromData +} +#endif + void initEEPROM(void) { // Verify that this architecture packs as expected. @@ -89,7 +119,15 @@ void initEEPROM(void) STATIC_ASSERT(sizeof(configRecord_t) == 6, record_size_failed); #ifdef EEPROM_IN_FILE - FLASH_Unlock(); // load existing config file into eepromData + loadEEPROMFromFile(); +#endif + +#ifdef EEPROM_IN_EXTERNAL_FLASH + bool eepromLoaded = loadEEPROMFromExternalFlash(); + if (!eepromLoaded) { + // Flash read failed - just die now + failureMode(FAILURE_FLASH_READ_FAILED); + } #endif } @@ -159,6 +197,11 @@ uint16_t getEEPROMConfigSize(void) size_t getEEPROMStorageSize(void) { +#if defined(EEPROM_IN_EXTERNAL_FLASH) + + const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_CONFIG); + return FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGetGeometry()->sectorSize; +#endif #ifdef EEPROM_IN_RAM return EEPROM_SIZE; #else @@ -268,9 +311,15 @@ void writeConfigToEEPROM(void) for (int attempt = 0; attempt < 3 && !success; attempt++) { if (writeSettingsToEEPROM()) { success = true; + +#ifdef EEPROM_IN_EXTERNAL_FLASH + // copy it back from flash to the in-memory buffer. + success = loadEEPROMFromExternalFlash(); +#endif } } + if (success && isEEPROMVersionValid() && isEEPROMStructureValid()) { return; } diff --git a/src/main/config/config_streamer.c b/src/main/config/config_streamer.c index 5cad10df9c..341cab0d6a 100644 --- a/src/main/config/config_streamer.c +++ b/src/main/config/config_streamer.c @@ -23,9 +23,13 @@ #include "platform.h" #include "drivers/system.h" +#include "drivers/flash.h" #include "config/config_streamer.h" +#if defined(STM32H750xx) && !(defined(EEPROM_IN_EXTERNAL_FLASH) || defined(EEPROM_IN_RAM)) +#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 #if !defined(FLASH_PAGE_SIZE) // F1 @@ -74,12 +78,11 @@ void config_streamer_init(config_streamer_t *c) void config_streamer_start(config_streamer_t *c, uintptr_t base, int size) { - // base must start at FLASH_PAGE_SIZE boundary + // base must start at FLASH_PAGE_SIZE boundary when using embedded flash. c->address = base; c->size = size; if (!c->unlocked) { - -#if defined(EEPROM_IN_RAM) +#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_EXTERNAL_FLASH) // NOP #elif defined(EEPROM_IN_FLASH) || defined(EEPROM_IN_FILE) #if defined(STM32F7) || defined(STM32H7) @@ -91,7 +94,7 @@ void config_streamer_start(config_streamer_t *c, uintptr_t base, int size) c->unlocked = true; } -#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_FILE) +#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_FILE) || defined(EEPROM_IN_EXTERNAL_FLASH) // NOP #elif defined(EEPROM_IN_FLASH) #if defined(STM32F10X) @@ -113,7 +116,7 @@ void config_streamer_start(config_streamer_t *c, uintptr_t base, int size) c->err = 0; } -#if defined(EEPROM_IN_RAM) +#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_EXTERNAL_FLASH) // No flash sector method required. #elif defined(EEPROM_IN_FLASH) #if defined(STM32F745xx) || defined(STM32F746xx) || defined(STM32F765xx) @@ -342,12 +345,48 @@ static void getFLASHSectorForEEPROM(uint32_t *bank, uint32_t *sector) #endif #endif +// FIXME the return values are currently magic numbers static int write_word(config_streamer_t *c, config_streamer_buffer_align_type_t *buffer) { if (c->err != 0) { return c->err; } -#if defined(EEPROM_IN_RAM) +#if defined(EEPROM_IN_EXTERNAL_FLASH) + + uint32_t dataOffset = (uint32_t)(c->address - (uintptr_t)&eepromData[0]); + + const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_CONFIG); + const flashGeometry_t *flashGeometry = flashGetGeometry(); + + uint32_t flashStartAddress = flashPartition->startSector * flashGeometry->sectorSize; + uint32_t flashOverflowAddress = ((flashPartition->endSector + 1) * flashGeometry->sectorSize); // +1 to sector for inclusive + + uint32_t flashAddress = flashStartAddress + dataOffset; + if (flashAddress + CONFIG_STREAMER_BUFFER_SIZE > flashOverflowAddress) { + return -3; // address is past end of partition + } + + uint32_t flashSectorSize = flashGeometry->sectorSize; + uint32_t flashPageSize = flashGeometry->pageSize; + + bool onPageBoundary = (flashAddress % flashPageSize == 0); + if (onPageBoundary) { + + bool firstPage = (flashAddress == flashStartAddress); + if (!firstPage) { + flashPageProgramFinish(); + } + + if (flashAddress % flashSectorSize == 0) { + flashEraseSector(flashAddress); + } + + flashPageProgramBegin(flashAddress); + } + + flashPageProgramContinue((uint8_t *)buffer, CONFIG_STREAMER_BUFFER_SIZE); + +#elif defined(EEPROM_IN_RAM) if (c->address == (uintptr_t)&eepromData[0]) { memset(eepromData, 0, sizeof(eepromData)); } @@ -470,7 +509,9 @@ int config_streamer_flush(config_streamer_t *c) int config_streamer_finish(config_streamer_t *c) { if (c->unlocked) { -#if defined(EEPROM_IN_RAM) +#if defined(EEPROM_IN_EXTERNAL_FLASH) + flashFlush(); +#elif defined(EEPROM_IN_RAM) // NOP #elif defined(EEPROM_IN_FILE) FLASH_Lock(); diff --git a/src/main/config/config_streamer.h b/src/main/config/config_streamer.h index 0cbd884ea8..c26551ddbe 100644 --- a/src/main/config/config_streamer.h +++ b/src/main/config/config_streamer.h @@ -26,7 +26,10 @@ // Streams data out to the EEPROM, padding to the write size as // needed, and updating the checksum as it goes. -#ifdef STM32H7 +#ifdef EEPROM_IN_EXTERNAL_FLASH +#define CONFIG_STREAMER_BUFFER_SIZE 8 // Must not be greater than the smallest flash page size of all compiled-in flash devices. +typedef uint32_t config_streamer_buffer_align_type_t; +#elif defined(STM32H7) #define CONFIG_STREAMER_BUFFER_SIZE 32 // Flash word = 256-bits typedef uint64_t config_streamer_buffer_align_type_t; #else diff --git a/src/main/drivers/system.h b/src/main/drivers/system.h index 01c9eca595..724dbad810 100644 --- a/src/main/drivers/system.h +++ b/src/main/drivers/system.h @@ -32,7 +32,8 @@ typedef enum { FAILURE_ACC_INCOMPATIBLE, FAILURE_INVALID_EEPROM_CONTENTS, FAILURE_FLASH_WRITE_FAILED, - FAILURE_GYRO_INIT_FAILED + FAILURE_GYRO_INIT_FAILED, + FAILURE_FLASH_READ_FAILED } failureMode_e; #define WARNING_FLASH_DURATION_MS 50 diff --git a/src/main/fc/init.c b/src/main/fc/init.c index 969034892c..cea50361c7 100644 --- a/src/main/fc/init.c +++ b/src/main/fc/init.c @@ -206,6 +206,46 @@ static IO_t busSwitchResetPin = IO_NONE; } #endif +static void configureSPIAndQuadSPI(void) +{ +#ifdef USE_SPI + spiPinConfigure(spiPinConfig(0)); +#endif + + sensorsPreInit(); + +#ifdef USE_SPI + spiPreinit(); + +#ifdef USE_SPI_DEVICE_1 + spiInit(SPIDEV_1); +#endif +#ifdef USE_SPI_DEVICE_2 + spiInit(SPIDEV_2); +#endif +#ifdef USE_SPI_DEVICE_3 + spiInit(SPIDEV_3); +#endif +#ifdef USE_SPI_DEVICE_4 + spiInit(SPIDEV_4); +#endif +#ifdef USE_SPI_DEVICE_5 + spiInit(SPIDEV_5); +#endif +#ifdef USE_SPI_DEVICE_6 + spiInit(SPIDEV_6); +#endif +#endif // USE_SPI + +#ifdef USE_QUADSPI + quadSpiPinConfigure(quadSpiConfig(0)); + +#ifdef USE_QUADSPI_DEVICE_1 + quadSpiInit(QUADSPIDEV_1); +#endif +#endif // USE_QUAD_SPI +} + void init(void) { @@ -252,6 +292,43 @@ void init(void) } #endif +#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. + // 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. + // + // note that target specific FLASH/SPI/QUADSPI configs are + // also not supported in USE_TARGET_CONFIG/targetConfigure() when using EEPROM_IN_EXTERNAL_FLASH. + // + + // + // 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. + // + pgResetAll(); + +#ifdef TARGET_BUS_INIT +#error "EEPROM_IN_EXTERNAL_FLASH and TARGET_BUS_INIT are mutually exclusive" +#endif + + configureSPIAndQuadSPI(); + +#ifndef USE_FLASH_CHIP +#error "EEPROM_IN_EXTERNAL_FLASH requires USE_FLASH_CHIP to be defined." +#endif + + flashInit(flashConfig()); + +#endif // EEPROM_IN_EXTERNAL_FLASH + + initEEPROM(); ensureEEPROMStructureIsValid(); @@ -430,48 +507,15 @@ void init(void) initInverters(serialPinConfig()); #endif + #ifdef TARGET_BUS_INIT targetBusInit(); #else -#ifdef USE_SPI - spiPinConfigure(spiPinConfig(0)); -#endif - - sensorsPreInit(); - -#ifdef USE_SPI - spiPreinit(); - -#ifdef USE_SPI_DEVICE_1 - spiInit(SPIDEV_1); -#endif -#ifdef USE_SPI_DEVICE_2 - spiInit(SPIDEV_2); -#endif -#ifdef USE_SPI_DEVICE_3 - spiInit(SPIDEV_3); -#endif -#ifdef USE_SPI_DEVICE_4 - spiInit(SPIDEV_4); -#endif -#ifdef USE_SPI_DEVICE_5 - spiInit(SPIDEV_5); -#endif -#ifdef USE_SPI_DEVICE_6 - spiInit(SPIDEV_6); -#endif -#endif // USE_SPI - -#ifdef USE_QUADSPI - quadSpiPinConfigure(quadSpiConfig(0)); - -#ifdef USE_QUADSPI_DEVICE_1 - quadSpiInit(QUADSPIDEV_1); -#endif -#endif // USE_QUAD_SPI - +#ifndef EEPROM_IN_EXTERNAL_FLASH + configureSPIAndQuadSPI(); +#endif // EEPROM_IN_EXTERNAL_FLASH #ifdef USE_USB_MSC /* MSC mode will start after init, but will not allow scheduler to run, @@ -715,12 +759,14 @@ void init(void) } #endif +#ifndef EEPROM_IN_EXTERNAL_FLASH #ifdef USE_FLASH_CHIP flashInit(flashConfig()); +#endif +#endif #ifdef USE_FLASHFS flashfsInit(); #endif -#endif #ifdef USE_BLACKBOX #ifdef USE_SDCARD diff --git a/src/main/target/common_post.h b/src/main/target/common_post.h index 34e759ed25..933443d49a 100644 --- a/src/main/target/common_post.h +++ b/src/main/target/common_post.h @@ -338,7 +338,7 @@ #undef USE_ESCSERIAL #endif -#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_FILE) +#if defined(EEPROM_IN_RAM) || defined(EEPROM_IN_FILE) || defined(EEPROM_IN_EXTERNAL_FLASH) #ifndef EEPROM_SIZE #define EEPROM_SIZE 4096 #endif