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.
Memory view when in debug mode
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.
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
So glad to see another post. Will you be posting regularly or in intervals of 5 years?
Thank You! 5 years is quite a long time. But no, this time I plan on being more active. This post is just a 1st step towards writing a complete bootloader from scratch. So next post will be on how to write to flash, then CRC, then then bootloader and failsafe and so on. Thanks again!