Skip to content

Commit

Permalink
Erase all of flash if needed, make flash writing more robust
Browse files Browse the repository at this point in the history
  • Loading branch information
gloomyandy committed Mar 22, 2022
1 parent 1f3b660 commit 5f38286
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 37 deletions.
131 changes: 103 additions & 28 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "iapparams.h"
// Define replacement standard library functions
#include <syscalls.h>
#define USB_DEBUG 1
//#define USB_DEBUG 1
// This is the string that identifies the board type and firmware version, that the vector at 0x20 points to.
// The characters after the last space must be the firmware version in standard format, e.g. "3.3.0" or "3.4.0beta4". The firmware build date/time is not included.
extern const char VersionText[] = FIRMWARE_NAME " version " VERSION;
Expand Down Expand Up @@ -165,7 +165,7 @@ void Init(bool watchdog) noexcept
IrqEnable();
#if USB_DEBUG
SERIAL_MAIN_DEVICE.begin(9600);
delay(2000);
delay(5000);
#else
delay(500);
#endif
Expand All @@ -184,29 +184,74 @@ void Init(bool watchdog) noexcept
#define IS_FLASH_ALIGNED(addr) (((uint32_t)(addr) & (sizeof(uint32_t)-1)) == 0)
#endif
#define IS_ALIGNED(addr) (((uint32_t)(addr) & (sizeof(uint32_t)-1)) == 0)
constexpr uint32_t IAP_BAD_SECTOR = 0xffffffff;

bool isErased(const uint32_t addr, const size_t len) noexcept
static void FlashClearError()
{
// Clear pending flags (if any)
#if STM32H7
__HAL_FLASH_CLEAR_FLAG_BANK1(FLASH_FLAG_WRPERR_BANK1 | FLASH_FLAG_PGSERR_BANK1 | FLASH_FLAG_STRBERR_BANK1 | \
FLASH_FLAG_INCERR_BANK1 | FLASH_FLAG_OPERR_BANK1 | FLASH_FLAG_SNECCERR_BANK1 | \
FLASH_IT_DBECCERR_BANK1);
__HAL_FLASH_CLEAR_FLAG_BANK2((FLASH_FLAG_WRPERR_BANK2 | FLASH_FLAG_PGSERR_BANK2 | FLASH_FLAG_STRBERR_BANK2 | \
FLASH_FLAG_INCERR_BANK2 | FLASH_FLAG_SNECCERR_BANK2 | FLASH_IT_DBECCERR_BANK2) & 0x7FFFFFFFU);
#else
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |\
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR| FLASH_FLAG_PGSERR);
#endif
}


static bool isErased(const uint32_t addr, const size_t len) noexcept
{
#if STM32H7
// On the STM32H7 if the flash has not been correctly erased then simply reading
// it can cause a bus fault (due to multiple ECC errors). We avoid this by disaabling
// the fault mechanism while checking the flash memory.
const irqflags_t flags = IrqSave();

__set_FAULTMASK(1);
SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk;
__DSB();
__ISB();
#endif
HAL_FLASH_Unlock();
FlashClearError();

bool blank = true;
// Check that the sector really is erased
for (uint32_t p = addr; p < addr + len; p += sizeof(uint32_t))
for (uint32_t p = addr; p < addr + len && blank; p += sizeof(uint32_t))
{
if (*reinterpret_cast<const uint32_t*>(p) != 0xFFFFFFFF)
{
return false;
blank = false;
}
}
return true;

FlashClearError();
HAL_FLASH_Lock();

#if STM32H7
// restore bus fault logic
__set_FAULTMASK(0);
SCB->CCR &= ~SCB_CCR_BFHFNMIGN_Msk;
__DSB();
__ISB();
IrqRestore(flags);
#endif
return blank;
}

uint32_t FlashGetSector(const uint32_t addr) noexcept
static uint32_t FlashGetSector(const uint32_t addr) noexcept
{
if (!IS_FLASH_PROGRAM_ADDRESS(addr))
{
debugPrintf("Bad flash address %x\n", (unsigned)addr);
return IAP_BAD_SECTOR;
}
// Flash memory on STM32F4 is 4 sectors of 16K + 1 sector of 64K + 8 sectors of 128K
uint32_t offset = addr - FLASH_ADDR;
// on the H7 all sectors are 128Kb
uint32_t offset = addr - FLASH_BASE;
#if STM32H7
return offset/0x20000;
#else
Expand All @@ -219,7 +264,7 @@ uint32_t FlashGetSector(const uint32_t addr) noexcept
#endif
}

size_t FlashGetSectorLength(const uint32_t addr) noexcept
static size_t FlashGetSectorLength(const uint32_t addr) noexcept
{
uint32_t sector = FlashGetSector(addr);
if (sector == IAP_BAD_SECTOR)
Expand All @@ -236,31 +281,28 @@ size_t FlashGetSectorLength(const uint32_t addr) noexcept
#endif
}

void FlashClearError()
{
// Clear pending flags (if any)
#if STM32H7
__HAL_FLASH_CLEAR_FLAG_BANK1(FLASH_FLAG_WRPERR_BANK1 | FLASH_FLAG_PGSERR_BANK1 | FLASH_FLAG_STRBERR_BANK1 | \
FLASH_FLAG_INCERR_BANK1 | FLASH_FLAG_OPERR_BANK1);
__HAL_FLASH_CLEAR_FLAG_BANK2((FLASH_FLAG_WRPERR_BANK2 | FLASH_FLAG_PGSERR_BANK2 | FLASH_FLAG_STRBERR_BANK2 | \
FLASH_FLAG_INCERR_BANK2) & 0x7FFFFFFFU);
#else
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |\
FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR| FLASH_FLAG_PGSERR);
#endif
}

bool FlashEraseSector(const uint32_t sector) noexcept
static bool FlashEraseSector(const uint32_t sector) noexcept
{
WatchdogReset();
FLASH_EraseInitTypeDef eraseInfo;
uint32_t SectorError;
bool ret = true;
eraseInfo.TypeErase = FLASH_TYPEERASE_SECTORS;
#if STM32H7
eraseInfo.Banks = FLASH_BANK_1;
#endif
if (sector < FLASH_SECTOR_TOTAL)
{
eraseInfo.Banks = FLASH_BANK_1;
eraseInfo.Sector = sector;
}
else
{
eraseInfo.Banks = FLASH_BANK_2;
eraseInfo.Sector = sector - FLASH_SECTOR_TOTAL;
}
debugPrintf("Erase %d bank %d sector %d\n", sector, eraseInfo.Banks, eraseInfo.Sector);
#else
eraseInfo.Sector = sector;
#endif
eraseInfo.NbSectors = 1;
eraseInfo.VoltageRange = FLASH_VOLTAGE_RANGE_3;
HAL_FLASH_Unlock();
Expand All @@ -275,7 +317,7 @@ bool FlashEraseSector(const uint32_t sector) noexcept
return ret;
}

bool FlashWrite(const uint32_t addr, const uint8_t *data, const size_t len) noexcept
static bool FlashWrite(const uint32_t addr, const uint8_t *data, const size_t len) noexcept
{
uint32_t *dst = (uint32_t *)addr;
uint32_t *src = (uint32_t *)data;
Expand All @@ -287,6 +329,7 @@ bool FlashWrite(const uint32_t addr, const uint8_t *data, const size_t len) noex
bool ret = true;
debugPrintf("Write flash addr %x len %d\n", (unsigned)addr, (int)len);
WatchdogReset();
bool cacheEnabled = Cache::Disable();
HAL_FLASH_Unlock();
FlashClearError();
uint32_t cnt = 0;
Expand Down Expand Up @@ -315,12 +358,44 @@ bool FlashWrite(const uint32_t addr, const uint8_t *data, const size_t len) noex
#endif
}
HAL_FLASH_Lock();
if (cacheEnabled) Cache::Enable();
if (!ret)
debugPrintf("Flash write failed cnt %d\n", (int)dst - addr);
debugPrintf("Flash write failed cnt %d\n", (int)((int)dst - addr));

return ret;
}

static bool FlashRead(const uint32_t addr, uint8_t *data, const size_t len) noexcept
{
#if STM32H7
// On the STM32H7 if the flash has not been correctly erased then simply reading
// it can cause a bus fault (due to multiple ECC errors). We avoid this by disaabling
// the fault mechanism while checking the flash memory.
const irqflags_t flags = IrqSave();

__set_FAULTMASK(1);
SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk;
__DSB();
__ISB();
#endif
HAL_FLASH_Unlock();
FlashClearError();
// Do the actual read from flash
memcpy((void *)data, (void *)addr, len);
// Clear any errors
FlashClearError();
HAL_FLASH_Lock();
#if STM32H7
// restore bus fault logic
__set_FAULTMASK(0);
SCB->CCR &= ~SCB_CCR_BFHFNMIGN_Msk;
__DSB();
__ISB();
IrqRestore(flags);
#endif
return true;
}

bool FlashVerify(const uint32_t addr, const uint8_t *data, const size_t len)
{
uint32_t *dst = (uint32_t *)addr;
Expand Down
10 changes: 1 addition & 9 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,12 @@
const NvicPriority NvicPrioritySpi = 8;
const NvicPriority NvicPrioritySDIO = 8;

#ifdef FLASH_SIZE
#undef FLASH_SIZE
#endif

#define STRINGIFY2(X) #X
#define STRINGIFY(X) STRINGIFY2(X)

#if STM32H7
constexpr size_t FirmwareFlashStart = 0x8020000;
constexpr size_t FLASH_ADDR = FLASH_BASE;
// For now we only use one bank of flash
#undef FLASH_SIZE
constexpr size_t FLASH_SIZE = 0x0100000;
#if IAP_SPI_LOADER
#define FIRMWARE_NAME "STM32H7 SPI loader"
#else
Expand All @@ -34,9 +27,8 @@ constexpr size_t FLASH_SIZE = (FLASH_END + 1 - FLASH_BASE);
#error "unknown mcu"
#endif

#define VERSION "1.0.0"
#define VERSION "1.0.1"

constexpr uint32_t IAP_BAD_SECTOR = 0xffffffff;
constexpr size_t IAP_BUFFER_SIZE = 2048;
constexpr char firmwarePath[] = "0:/firmware.bin";
constexpr char goodFirmwarePath[] = "0:/firmware.cur";
Expand Down

0 comments on commit 5f38286

Please sign in to comment.