How to Read Flash Memory (STM32 Microcontroller)

The grand plan is to implement a bootloader. A bootloader should be able to read and write to its flash memory. Therefore, I am breaking the bootloader project into smaller pieces. I am using an ARM Cortex-M4 microcontroller from ST, STM32F411CE.

About the controller:

Microcontroller: STM32F411CE

Flash Memory size: 512KB

RAM size: 128KB

Boot Pin and Address alias:

For this section, please read the reference manual RM0383 (STM32F411xC/E advanced Arm®-based 32-bit MCUs – Reference manual) (Section 3: Embedded Flash memory interface).

Let us start with addressing the alias and how the boot pin switches to different memories. STM32F411CE is a 32-bit microcontroller, so the addresses are 32bit wide and start with 0x00000000 à starting address. This starting address is an alias pointing to a different address memory, either Flash or RAM.

Based on the boot pin configuration, it could be either Flash or RAM.

Flash address: 0x0800 0000

RAM address: 0x2000 0000

If the Boot 0 pin is set to 0, the starting address 0x0000 0000 will alias to 0x0800 0000, which is the Flash address. If Boot 0 and Boot 1 pins are set to 1, then 0x0000 0000 will alias to 0x2000 0000, which is the RAM address. In other words, if Boot 0 pin is set to 0, reading and writing to the address 0x0000 0000 is the same as reading/writing to the address 0x0800 0000 and vice-versa.

image

Memory view when in debug mode

image

Flash Memory organization:

I am using STM32F411CE which has a memory capacity of 512KB. The flash memory is organized into pages as given in the datasheet (image below). Think of pages as pages of a book. When an erase operation is done, it is done in pages. This organization map also helps us in allocating/planning the memory for bootloader, applications and maybe even write some persistent data to non-volatile memory.

image

Read from STM32 Flash:

Let us understand how naming of data size for a 32bit ARM controller.

Data Size
1 Word 4 Bytes (32 bits)
Half Word 2 Bytes (16 bits)
1 Byte 8 bits

Even though I can do bit operations, would rather use the union C to do the work

union flashdata{
    uint32_t data_word;
    uint8_t data_bytes[4];
}flashmem_data;
uint32_t *memptr = (uint32_t *)0x08000000; //pointer to the address in Flash memory

for(int i = 0; i < 32; i++)
{
    flashmem_data.data_word = *memptr++;
    printf("Data [%02d]: 0x%02x%02x%02x%02x\r\n",
        i,
        flashmem_data.data_bytes[3],
        flashmem_data.data_bytes[2],
        flashmem_data.data_bytes[1],
        flashmem_data.data_bytes[0]);

  HAL_Delay(200);
}


Project Download:

You can download the source code and project (STM32 Cube) from here: https://github.com/singularengineer/STM32_Project_Snippets/tree/main/STM32F411_ReadFlash

Output

clip_image001