diff --git a/lib/flash_internal.c b/lib/flash_internal.c index f1cc685..f6234ce 100644 --- a/lib/flash_internal.c +++ b/lib/flash_internal.c @@ -12,7 +12,7 @@ * along with this program. If not, see . * */ -/** library to read/write internal flash (code) +/** library to read/write internal flash * @file * @author King Kévin * @date 2016-2020 @@ -319,3 +319,91 @@ int32_t flash_internal_eeprom_write(const uint8_t *eeprom, uint16_t size) } return rc; } + +uint16_t flash_internal_probe_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 + 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; + flash_erase_page(address); // erase current page + if (flash_get_status_flags() != FLASH_SR_EOP) { // operation went wrong + break; + } + flash_program_half_word(address, test_data); // writes test data + if (flash_get_status_flags() != FLASH_SR_EOP) { // operation went wrong + break; + } + if (test_data != *((uint16_t*)address)) { // verify data is written correctly + break; + } + flash_erase_page(address); // erase test data + if (flash_get_status_flags() != FLASH_SR_EOP) { // operation went wrong + break; + } + } + flash_lock(); + + if (flash_size < DESIG_FLASH_SIZE * 1024) { // less than advertised size + return 0; + } else { + return flash_size / 1024; + } +} diff --git a/lib/flash_internal.h b/lib/flash_internal.h index f1e891f..e9d47d2 100644 --- a/lib/flash_internal.h +++ b/lib/flash_internal.h @@ -12,7 +12,7 @@ * along with this program. If not, see . * */ -/** library to read/write internal flash (API) +/** library to read/write internal flash * @file * @author King Kévin * @date 2016-2020 @@ -57,3 +57,8 @@ bool flash_internal_eeprom_read(uint8_t *eeprom, uint16_t size); * @return number of bytes written (including preserved data), or negative in case of error */ 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 + */ +uint16_t flash_internal_probe_size(void);