/** internal flash utilities * @file * @author King Kévin * @copyright SPDX-License-Identifier: GPL-3.0-or-later * @date 2016-2020 * @note peripherals used: none */ /* standard libraries */ #include // standard integer types #include // general utilities /* STM32 (including CM3) libraries */ #include // Cortex M3 utilities #include // device signature definitions #include // MCU definitions /* own libraries */ #include "global.h" // global definitions #include "flash_internal.h" // own definitions /** information about the MCU's flash sections */ struct flash_sections_info_s { const uint16_t device_id; /**< the MCU DEV ID */ const uint8_t number; /**< number of sections */ const struct flash_internal_section_info_s* sections; /**< size of the sections, in KiB */ }; /** information about the STM42F401xB/C flash sections */ static const struct flash_internal_section_info_s sections_f401xbc[] = { { .number = 0, .size = 16, .start = FLASH_BASE + (0) * 1024, .end = FLASH_BASE + (16) * 1024 - 1, }, { .number = 1, .size = 16, .start = FLASH_BASE + (0 + 16) * 1024, .end = FLASH_BASE + (16 + 16) * 1024 - 1, }, { .number = 2, .size = 16, .start = FLASH_BASE + (0 + 16 + 16) * 1024, .end = FLASH_BASE + (16 + 16 + 16) * 1024 - 1, }, { .number = 3, .size = 16, .start = FLASH_BASE + (0 + 16 + 16 + 16) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16) * 1024 - 1, }, { .number = 4, .size = 64, .start = FLASH_BASE + (0 + 16 + 16 + 16 + 16) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16 + 64) * 1024 - 1, }, { .number = 5, .size = 128, .start = FLASH_BASE + (0 + 16 + 16 + 16 + 16 + 64) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16 + 64 + 128) * 1024 - 1, }, }; /** information about the STM42F401xD/E flash sections */ static const struct flash_internal_section_info_s sections_f401xde[] = { { .number = 0, .size = 16, .start = FLASH_BASE + (0) * 1024, .end = FLASH_BASE + (16) * 1024 - 1, }, { .number = 1, .size = 16, .start = FLASH_BASE + (0 + 16) * 1024, .end = FLASH_BASE + (16 + 16) * 1024 - 1, }, { .number = 2, .size = 16, .start = FLASH_BASE + (0 + 16 + 16) * 1024, .end = FLASH_BASE + (16 + 16 + 16) * 1024 - 1, }, { .number = 3, .size = 16, .start = FLASH_BASE + (0 + 16 + 16 + 16) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16) * 1024 - 1, }, { .number = 4, .size = 64, .start = FLASH_BASE + (0 + 16 + 16 + 16 + 16) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16 + 64) * 1024 - 1, }, { .number = 5, .size = 128, .start = FLASH_BASE + (0 + 16 + 16 + 16 + 16 + 64) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16 + 64 + 128) * 1024 - 1, }, { .number = 6, .size = 128, .start = FLASH_BASE + (0 + 16 + 16 + 16 + 16 + 64 + 128) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16 + 64 + 128 + 128) * 1024 - 1, }, { .number = 7, .size = 128, .start = FLASH_BASE + (0 + 16 + 16 + 16 + 16 + 64 + 128 + 128) * 1024, .end = FLASH_BASE + (16 + 16 + 16 + 16 + 64 + 128 + 128 + 128) * 1024 - 1, }, }; static const struct flash_sections_info_s flash_sections_info[] = { { .device_id = 0x423, .number = LENGTH(sections_f401xbc), .sections = sections_f401xbc, }, { .device_id = 0x433, .number = LENGTH(sections_f401xde), .sections = sections_f401xde, }, }; bool flash_internal_range(uint32_t address, size_t size) { if (address < FLASH_BASE) { // start address is before the start of the internal flash return false; } if (address > (UINT32_MAX - size)) { // an integer overflow will occur return false; } if ((address + size) > FLASH_BASE + desig_get_flash_size() * 1024) { // end address is after the end of the internal flash return false; } return true; } /** find out in which section is this address * @param[in] address address to find the section for * @return section in which this address is (NULL if not in flash, section has not been found, or the sections of this device are unknown) */ const struct flash_internal_section_info_s* flash_internal_section(uint32_t address) { if (!flash_internal_range(address, 0)) { // verify if this address is in flash return NULL; } // find sections information for this device uint8_t flash_sections_info_i; for (flash_sections_info_i = 0; flash_sections_info_i < LENGTH(flash_sections_info); flash_sections_info_i++) { if ((DBGMCU_IDCODE & DBGMCU_IDCODE_DEV_ID_MASK) == flash_sections_info[flash_sections_info_i].device_id) { break; // we found the device's section information } } if (flash_sections_info_i >= LENGTH(flash_sections_info)) { // we did not find the device's section information return NULL; } // find in which section this address is for (uint8_t i = 0; i < flash_sections_info[flash_sections_info_i].number; i++) { if (address >= flash_sections_info[flash_sections_info_i].sections[i].start && address <= flash_sections_info[flash_sections_info_i].sections[i].end) { return &flash_sections_info[flash_sections_info_i].sections[i]; } } return NULL; // we did not find the section } 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; }