137 lines
4.4 KiB
C
137 lines
4.4 KiB
C
/** internal flash utilities
|
|
* @file
|
|
* @author King Kévin <kingkevin@cuvoodoo.info>
|
|
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
|
|
* @date 2016-2020
|
|
* @note peripherals used: none
|
|
*/
|
|
/* standard libraries */
|
|
#include <stdint.h> // standard integer types
|
|
#include <stdlib.h> // general utilities
|
|
|
|
/* STM32 (including CM3) libraries */
|
|
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
|
|
#include <libopencm3/stm32/desig.h> // device signature definitions
|
|
#include <libopencm3/stm32/dbgmcu.h> // 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,
|
|
},
|
|
};
|
|
|
|
static const struct flash_sections_info_s flash_sections_info[] = {
|
|
{
|
|
.device_id = 0x423,
|
|
.number = LENGTH(sections_f401xbc),
|
|
.sections = sections_f401xbc,
|
|
},
|
|
};
|
|
|
|
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;
|
|
}
|