stm32f1/lib/flash_internal.c

194 lines
5.8 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,
},
};
/** 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;
}