From 8142854522db20e1f176115c5ef95a7d13996c49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Sun, 14 Jun 2020 19:06:54 +0200 Subject: [PATCH] flash_internal: replace probe size with more accurate probe_read and probe_write --- lib/flash_internal.c | 108 ++++++++++++++++++------------------------- lib/flash_internal.h | 11 +++-- 2 files changed, 53 insertions(+), 66 deletions(-) diff --git a/lib/flash_internal.c b/lib/flash_internal.c index ddb34f2..90d0498 100644 --- a/lib/flash_internal.c +++ b/lib/flash_internal.c @@ -10,6 +10,7 @@ #include // general utilities /* STM32 (including CM3) libraries */ +#include // Cortex M3 utilities #include // flash utilities #include // device signature definitions #include // debug definitions @@ -307,69 +308,49 @@ int32_t flash_internal_eeprom_write(const uint8_t *eeprom, uint16_t size) return rc; } -uint16_t flash_internal_probe_size(void) +uint32_t flash_internal_probe_read_size(void) +{ + // we will check is a flash address is readable until a bus fault occurs + cm_disable_faults(); // disable all faults, particularly BusFault + SCB_CFSR |= SCB_CFSR_BFARVALID; // clear bus fault flag + SCB_CCR |= SCB_CCR_BFHFNMIGN; // ignore bus faults (but still flag them) + uint32_t address = FLASH_BASE; // start with the start of flash + while (0 == (SCB_CFSR & SCB_CFSR_BFARVALID)) { // until a bus fault occurs + (void)*(volatile uint8_t*)address; // access address + address++; // got to next address + } + SCB_CFSR |= SCB_CFSR_BFARVALID; // clear bus fault flag + SCB_CCR &= ~SCB_CCR_BFHFNMIGN; // re-enable bus fault + cm_enable_faults(); // re-enable faults + + return address - 1 - FLASH_BASE; +} + +uint32_t flash_internal_probe_write_size(void) { if (0 == DESIG_FLASH_SIZE) { // no flash size advertised return 0; } - // get max flash size based on device identifier (DEV_ID) - uint32_t flash_size_max = 0; // max flash size (in bytes) - switch (DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK) { // get page size based on family code - case 0x412: // low-density, 16-32 kB flash - flash_size_max = 32; - break; - case 0x410: // medium-density, 64-128 kB flash - flash_size_max = 128; - break; - case 0x414: // high-density, 256-512 kB flash - flash_size_max = 512; - break; - case 0x430: // XL-density, 768-1024 kB flash - flash_size_max = 1024; - break; - case 0x418: // connectivity, 64-256 kB flash - flash_size_max = 256; - break; - case 0: // DBGMCU_IDCODE is only accessible in debug mode (this is a known issue documented in STM32F10xxC/D/E Errata sheet, without workaround) - default: // unknown - if ((*(uint32_t*)0x1FFFF000 & 0xFFFE0000) == 0x20000000) { // non-connectivity system memory start detected (MSP address pointing to SRAM - switch (DESIG_FLASH_SIZE) { - case 16: - case 32: - flash_size_max = 32; // low-density, 16-32 kB flash - break; - case 64: - case 128: - flash_size_max = 128; // medium-density, 64-128 kB flash - break; - case 256: - case 512: - flash_size_max = 512; // high-density, 256-512 kB flash - break; - case 768: - case 1024: - flash_size_max = 1024; // XL-density, 768-1024 kB flash - break; - default: - break; - } - } else { // connectivity system memory start is at 0x1FFFB000 - flash_size_max = 256; // connectivity, 64-256 kB flash - } - break; - } - if (0 == flash_size_max) { // could not determine max flash size - return 0; - } - flash_size_max *= 1024; // get in bytes - - // test if page is writable, starting with last one - uint32_t flash_size; // tested flash size (in bytes) - const uint16_t test_data = 0x2342; // the data we will write and read to test page + // prepare for reading the flash + cm_disable_faults(); // disable all faults, particularly BusFault + SCB_CFSR |= SCB_CFSR_BFARVALID; // clear bus fault flag + SCB_CCR |= SCB_CCR_BFHFNMIGN; // ignore bus faults (but still flag them) + // prepare for writing the flash flash_unlock(); // unlock flash to be able to write it - for (flash_size = DESIG_FLASH_SIZE * 1024 - flash_internal_page_size(); flash_size < flash_size_max; flash_size += flash_internal_page_size()) { // don't exceed max size else it will erase the first page (weird behaviour) - uint32_t address = FLASH_BASE + flash_size; + // try reading and writing the flash, page per page + uint32_t address = FLASH_BASE + DESIG_FLASH_SIZE * 1024; // start with the end of the advertised flash + if ((uint32_t)&__flash_end >= FLASH_BASE) { + address = (uint32_t)&__flash_end; + } + const uint16_t test_data = 0x2342; // the data we will write and read to test page + while (address < 0x1FFFEFFF) { // this is where the system memory starts + // try reading the flash + (void)*(volatile uint32_t*)address; // access address + if (0 != (SCB_CFSR & SCB_CFSR_BFARVALID)) { // until a bus fault occurs + break; // page not readable + } + // try writing the flash flash_erase_page(address); // erase current page if (flash_get_status_flags() != FLASH_SR_EOP) { // operation went wrong break; @@ -385,12 +366,13 @@ uint16_t flash_internal_probe_size(void) if (flash_get_status_flags() != FLASH_SR_EOP) { // operation went wrong break; } + address += flash_internal_page_size(); // go to next page } - flash_lock(); + flash_clear_status_flags(); // clear all flag + flash_lock(); // protect again from writing + SCB_CFSR |= SCB_CFSR_BFARVALID; // clear bus fault flag + SCB_CCR &= ~SCB_CCR_BFHFNMIGN; // re-enable bus fault + cm_enable_faults(); // re-enable faults - if (flash_size < DESIG_FLASH_SIZE * 1024) { // less than advertised size - return 0; - } else { - return flash_size / 1024; - } + return address - FLASH_BASE; } diff --git a/lib/flash_internal.h b/lib/flash_internal.h index 14596a5..e7d4f8b 100644 --- a/lib/flash_internal.h +++ b/lib/flash_internal.h @@ -45,7 +45,12 @@ bool flash_internal_eeprom_read(uint8_t *eeprom, uint16_t size); */ int32_t flash_internal_eeprom_write(const uint8_t *eeprom, uint16_t size); /** probe the real size of the internal flash - * @return tested size (in KiB), or 0 if less than advertised - * @warning it will write the last page of the advertised size + * @return tested size (in bytes) + * @note it only test if the flash is readable (not writable) */ -uint16_t flash_internal_probe_size(void); +uint32_t flash_internal_probe_read_size(void); +/** probe the real size of the internal flash + * @return tested size (in bytes) + * @warning it will write to the pages over the advertised size (it will not test the MCU advertised or linker provided size and assumes this is writable) + */ +uint32_t flash_internal_probe_write_size(void);