Support load/save configuration to external flash

Fixes to 6a3e7d8e6 as the flash partition code had changed during
the merge to master.
This commit is contained in:
Dominic Clifton 2019-05-13 00:10:46 +09:00
parent a6c07b046b
commit cf1ce1a67b
7 changed files with 189 additions and 50 deletions

View File

@ -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)

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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