From 155bfd9aebd1142623de57a0bba28d6ceb705d8b Mon Sep 17 00:00:00 2001 From: Matthew Kennedy Date: Sun, 9 May 2021 06:19:20 -0700 Subject: [PATCH] Support STM32F7 1MB devices (#2659) * modify linker script for 1MB devices * handle null flash address * actually support 1MB F7 * comment --- firmware/controllers/flash_main.cpp | 14 ++- .../stm32f7/{STM32F76xxI.ld => STM32F7.ld} | 4 +- .../hw_layer/ports/stm32/stm32f7/hw_ports.mk | 2 +- .../hw_layer/ports/stm32/stm32f7/mpu_util.cpp | 101 ++++++++++++++++-- 4 files changed, 107 insertions(+), 14 deletions(-) rename firmware/hw_layer/ports/stm32/stm32f7/{STM32F76xxI.ld => STM32F7.ld} (97%) diff --git a/firmware/controllers/flash_main.cpp b/firmware/controllers/flash_main.cpp index 124c196a66..d1674d67a5 100644 --- a/firmware/controllers/flash_main.cpp +++ b/firmware/controllers/flash_main.cpp @@ -86,8 +86,12 @@ void writeToFlashIfPending() { // Erase and write a copy of the configuration at the specified address template -int eraseAndFlashCopy(flashaddr_t storageAddress, const TStorage& data) -{ +int eraseAndFlashCopy(flashaddr_t storageAddress, const TStorage& data) { + // error already reported, return + if (!storageAddress) { + return FLASH_RETURN_SUCCESS; + } + auto err = intFlashErase(storageAddress, sizeof(TStorage)); if (FLASH_RETURN_SUCCESS != err) { firmwareError(OBD_PCM_Processor_Fault, "Failed to erase flash at %#010x", storageAddress); @@ -145,6 +149,12 @@ typedef enum { static persisted_configuration_state_e doReadConfiguration(flashaddr_t address) { efiPrintf("readFromFlash %x", address); + + // error already reported, return + if (!address) { + return CRC_FAILED; + } + intFlashRead(address, (char *) &persistentState, sizeof(persistentState)); if (!isValidCrc(&persistentState)) { diff --git a/firmware/hw_layer/ports/stm32/stm32f7/STM32F76xxI.ld b/firmware/hw_layer/ports/stm32/stm32f7/STM32F7.ld similarity index 97% rename from firmware/hw_layer/ports/stm32/stm32f7/STM32F76xxI.ld rename to firmware/hw_layer/ports/stm32/stm32f7/STM32F7.ld index c404b00922..130ad3bbeb 100644 --- a/firmware/hw_layer/ports/stm32/stm32f7/STM32F76xxI.ld +++ b/firmware/hw_layer/ports/stm32/stm32f7/STM32F7.ld @@ -15,7 +15,7 @@ */ /* - * STM32F76xxI generic setup. + * STM32F7 memory setup. * * RAM0 - Data, Heap. * RAM3 - Main Stack, Process Stack, BSS, NOCACHE, ETH. @@ -27,7 +27,7 @@ MEMORY { bl : org = 0x08000000, len = 16k /* bootloader section */ - flash0 (rx) : org = DEFINED(BOOTLOADER) ? 0x08008000 : 0x08000000, len = DEFINED(BOOTLOADER) ? 1992k : 2048k + flash0 (rx) : org = DEFINED(BOOTLOADER) ? 0x08008000 : 0x08000000, len = DEFINED(BOOTLOADER) ? 736k : 768k /* change address & length if bootloader */ flash1 (rx) : org = 0x00200000, len = 2M /* Flash as ITCM */ /* TODO: do we need BOOTLOADER logic here? */ flash2 (rx) : org = 0x00000000, len = 0 flash3 (rx) : org = 0x00000000, len = 0 diff --git a/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk b/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk index ee0b793150..faea4b4669 100644 --- a/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk +++ b/firmware/hw_layer/ports/stm32/stm32f7/hw_ports.mk @@ -8,7 +8,7 @@ HW_LAYER_EMS_CPP += $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/mpu_util.cpp \ DDEFS += -DSTM32F767xx MCU = cortex-m7 -LDSCRIPT = $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/STM32F76xxI.ld +LDSCRIPT = $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/STM32F7.ld ALLCSRC += $(CHIBIOS)/os/hal/boards/ST_NUCLEO144_F767ZI/board.c CONFDIR = $(PROJECT_DIR)/hw_layer/ports/stm32/stm32f7/cfg diff --git a/firmware/hw_layer/ports/stm32/stm32f7/mpu_util.cpp b/firmware/hw_layer/ports/stm32/stm32f7/mpu_util.cpp index 465b4f01a3..7f1f99f117 100644 --- a/firmware/hw_layer/ports/stm32/stm32f7/mpu_util.cpp +++ b/firmware/hw_layer/ports/stm32/stm32f7/mpu_util.cpp @@ -5,23 +5,106 @@ * @author Andrey Belomutskiy, (c) 2012-2020 */ +#include "hal.h" #include "flash_int.h" +static bool isDualBank() { + // cleared bit indicates dual bank + return (FLASH->OPTCR & FLASH_OPTCR_nDBANK) == 0; +} + +static uint16_t flashSize() { + return *reinterpret_cast(FLASHSIZE_BASE); +} + +enum class DeviceType { + DualBank1MB, + DualBank2MB, + SingleBank1MB, + SingleBank2MB, + Unknown +}; + +static DeviceType determineDevice() { + bool db = isDualBank(); + uint16_t fs = flashSize(); + + if (db) { + if (fs == 1024) { + return DeviceType::DualBank1MB; + } else if (fs == 2048) { + return DeviceType::DualBank2MB; + } + } else { + if (fs == 1024) { + // Unsupported scenario! Not enough space for program plus two config copies + firmwareError(OBD_PCM_Processor_Fault, "1MB single bank MCU detected: please clear nDBANK option bit and reinstall FW."); + return DeviceType::SingleBank1MB; + } else if (fs == 2048) { + return DeviceType::SingleBank2MB; + } + } + + firmwareError(OBD_PCM_Processor_Fault, "Unrecognized flash memory layout db=%d, size=%d", db, fs); + return DeviceType::Unknown; +} + +// See ST AN4826 size_t flashSectorSize(flashsector_t sector) { - // sectors 0..11 are the 1st memory bank (1Mb), and 12..23 are the 2nd (the same structure). - if (sector <= 3 || (sector >= 12 && sector <= 15)) - return 32 * 1024; - else if (sector == 4 || sector == 16) - return 128 * 1024; - else if ((sector >= 5 && sector <= 11) || (sector >= 17 && sector <= 23)) - return 256 * 1024; + // 1MB devices have 8 sectors per bank + // 2MB devices have 12 sectors per bank + // However, the second bank always starts at index 12 (1MB devices have a 4 sector discontinuity between banks) + + if (sector >= 12) { + // The second bank has the same structure as the first + return flashSectorSize(sector - 12); + } + + // Pages are twice the size when in single bank mode + size_t dbMul = isDualBank() ? 1 : 2; + + if (sector <= 3) + return 16 * 1024 * dbMul; + else if (sector == 4) + return 64 * 1024 * dbMul; + else if (sector >= 5) + return 128 * 1024 * dbMul; return 0; } uintptr_t getFlashAddrFirstCopy() { - return 0x08100000; + switch (determineDevice()) { + case DeviceType::DualBank1MB: + // Sector 18, second to last 128K sector + return 0x080C0000; + case DeviceType::SingleBank1MB: + // Sector 7, last 256K sector + return 0x080C0000; + case DeviceType::DualBank2MB: /* falls thru */ + case DeviceType::SingleBank2MB: + // Start of the second megabyte + // Sector 12 for dual bank + // Sector 8 for single bank + return 0x08100000; + default: + return 0; + } } uintptr_t getFlashAddrSecondCopy() { - return 0x08140000; + switch (determineDevice()) { + case DeviceType::DualBank1MB: + // Sector 19, last 128K sector, 128K after the first copy + return 0x080E0000; + case DeviceType::DualBank2MB: + // Sector 14, 32K after the first copy + return 0x08108000; + case DeviceType::SingleBank2MB: + // Sector 9, 256K after the first copy + return 0x08140000; + case DeviceType::SingleBank1MB: + // We can't fit a second copy in this config, fall thru to failure case + default: + return 0; + } }