Flash Memory Map & Sectors
Embedded → Bootloaders + OTA
The map a bootloader lives by
Every bootloader-plus-application design starts with the same question: where in flash does each piece live?Internal flash isn't one giant byte-addressable blob you can overwrite freely — it's carved into fixed regions called sectors (STM32 F4/F7-class, unequal sizes) or pages (G0/L4-class, equal sizes). You can only erase a whole sector at once (resetting every byte to 0xFF) and then program it word by word — never write a single byte in isolation. That constraint is why bootloader design is a memory-map problem before it's a code problem: the bootloader must occupy its own sector(s), separate from the application's, or erasing the app to write a new one would erase the bootloader too.
A real sector-based map: STM32F429
The video above shows the HAL calls for erasing and programming a sector. The map below is what those calls actually operate on — a real STM32F429's 2MB flash, split into unequal sectors (the first few are small on purpose, so a bootloader needing only 16-32KB doesn't waste a huge sector on itself):
Sector 0 [old firmware bytes]
Notice programming is blocked until the sector is erased first — exactly like HAL_FLASH_Program cannot set bits back to 1 on real hardware.
The HAL erase + program sequence
Writing new firmware into a sector is always the same three-step dance, and skipping the unlock or the erase is the single most common flash-programming bug:
// 1. Unlock the flash controller — it boots locked to prevent accidental writes
HAL_FLASH_Unlock();
// 2. Erase the target sector(s) — this is the ONLY way to reset bits to 1;
// HAL_FLASH_Program can only clear bits (1 -> 0), never set them (0 -> 1)
FLASH_EraseInitTypeDef eraseInit = {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Sector = FLASH_SECTOR_5, // app sector, e.g. 0x08020000
.NbSectors = 1,
.VoltageRange = FLASH_VOLTAGE_RANGE_3,
};
uint32_t sectorError = 0;
if (HAL_FLASHEx_Erase(&eraseInit, §orError) != HAL_OK) {
// sectorError holds the offending sector if this fails
Error_Handler();
}
// 3. Program word-by-word (or byte-by-byte on some families) into the now-erased sector
for (uint32_t i = 0; i < imageSizeWords; i++) {
uint32_t addr = APP_START_ADDR + (i * 4);
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, imageWords[i]);
}
HAL_FLASH_Lock(); // re-lock — don't leave the controller writable outside a flash operation0xFF.Practice
Completion saves automatically after you read through to the end.
Next lesson →