I came across a very poorly described FMC (flash memory controller) controller on GD32F4xx. I Implement sector erasure, as in the example from GD32F4xx_Demo_Suites.
The code is executed from the second half of the flash memory (from addresses 0x08080000). The function normally clears all sectors except the zero one (at address 0x08000000) where the bootloader is located.
• I tried to disable interrupts, but it doesn't help. The VTOR is located in RAM.
• Sector protection is disabled (OB_WP0: *(uint8_t *)0x1fffc008 = 0xFF).
• The erase function does not return an error.
• The FMC controller is in single bank mode.
Are there any special features of erasing "block 0"? Maybe there is a more detailed description of the FMC controller somewhere?
Below is the implementation of sector erasure and division into sectors:
flash_mem_block_bounds_t bounds; ///< Bounds of memory block (sector)
uint32_t bankNum; ///< Bank num
uint32_t ctlRegNum; ///< Special value, which must be passed to the function fmc_sector_erase, to define sector which must be erased
} flash_sector_desc_t;
static const flash_sector_desc_t sectorMap[] = {
// Bank 0 (1MB)
{{0x08000000, 0x08003FFF}, 0, CTL_SECTOR_NUMBER_0 }, // 16KB sector
{{0x08004000, 0x08007FFF}, 0, CTL_SECTOR_NUMBER_1 }, // 16KB sector
{{0x08008000, 0x0800BFFF}, 0, CTL_SECTOR_NUMBER_2 }, // 16KB sector
{{0x0800C000, 0x0800FFFF}, 0, CTL_SECTOR_NUMBER_3 }, // 16KB sector
{{0x08010000, 0x0801FFFF}, 0, CTL_SECTOR_NUMBER_4 }, // 64KB sector
{{0x08020000, 0x0803FFFF}, 0, CTL_SECTOR_NUMBER_5 }, // 128KB sector
{{0x08040000, 0x0805FFFF}, 0, CTL_SECTOR_NUMBER_6 }, // 128KB sector
{{0x08060000, 0x0807FFFF}, 0, CTL_SECTOR_NUMBER_7 }, // 128KB sector
{{0x08080000, 0x0809FFFF}, 0, CTL_SECTOR_NUMBER_8}, // 128KB sector
{{0x080A0000, 0x080BFFFF}, 0, CTL_SECTOR_NUMBER_9}, // 128KB sector
{{0x080C0000, 0x080DFFFF}, 0, CTL_SECTOR_NUMBER_10}, // 128KB sector
{{0x080E0000, 0x080FFFFF}, 0, CTL_SECTOR_NUMBER_11}, // 128KB sector
};
op_result_t FMC_EraseBlock(uint32_t address) {
int sectorIndex;
sectorIndex = _getSectorIndex(address);
if (sectorIndex < 0) {
return RSLT_ERROR_WRONG_PARAM;
}
fmc_unlock();
fmc_state_enum result;
/* Clear pending flags */
fmc_flag_clear(FMC_FLAG_END | FMC_FLAG_WPERR | FMC_FLAG_PGMERR | FMC_FLAG_PGSERR | FMC_FLAG_RDDERR);
/* Erase sector */
result = fmc_sector_erase(sectorMap[sectorIndex].ctlRegNum);
/* Check for errors */
if (fmc_flag_get(FMC_FLAG_WPERR) == SET || fmc_flag_get(FMC_FLAG_PGMERR) == SET ||
fmc_flag_get(FMC_FLAG_PGSERR) == SET || (result != FMC_READY)) {
return RSLT_ERROR;
}
fmc_lock();
return RSLT_OK;
}
If change FMC to dual bank mode (DBS = 1), result the same.