FLASH Programming in STM32
Every microcontroller have some memory allocated for the user flash. Today We will use this memory to store some data in it. The benefit of using this flash memory is that, even after the power disconnect, the data remains safe in the flash memory.
This tutorial is devided into two halves. The first Half will cover those microcontrollers, whose memory is divided into pages. For eg- Cortex M3, and M0 series. The second Half is for those microcontrollers, whose memory is divided into Sectors.
H7 Series users can get the files from https://github.com/controllerstech/STM32/tree/master/FLASH_PROGRAM/H7%20SERIES
FLASH PAGE TYPE
For the first half, I am using STM32F103 microcontroller, and you can see the memory distribution in the picture below
As you can see above that the main memory (Flash memory) is distributed in 128 pages. Each page is of 1 KB, thus making the total memory of 128 KB
Now always remember that we should start programming as lower as possible in the flash memory. This is because the start of the flash is already allocated to the program, that is being executed on your controller right now. I have explained it properly in the video, you can check that out in the end.
Each page can hold 1024 Bytes of data, and i don’t have much data to write, so I will choose the last page of the flash memory, i.e. 0x0801FC00 – 0x0801FFFF
Some insight into the CODE
Write Data to FLASH
Below is the function to write the data into the Flash.
uint32_t Flash_Write_Data (uint32_t StartPageAddress, uint32_t *Data, uint16_t numberofwords);
The function Flash_Write_Data
takes the following parameters
- @ StartPageAddress is the address of the Start page, or memory in the page, from where you want to start writing the data.
- @ Data is the pointer to the 32 bit data array, that you want to write into the flash.
- @ numberofwords is the number of words, that you want to write in the memory.
The function is very big to be able to explain here. But here are few important hings that it does in order to write the data into the given memory location.
- Flash will be Unlocked to make modifications.
- Based on the number of words and start page address, it will calculate the number of pages required to store that data into.
- Next, the required number of pages will be erased, and the new data will be written into them.
- Flash will be Locked again.
Read Data from FLASH
Below is the function to read the data from the Flash.
void Flash_Read_Data (uint32_t StartPageAddress, uint32_t *RxBuf, uint16_t numberofwords);
The function Flash_Read_Data
reads the data from the flash. It takes the following parameters
- StartPageAddress is the Start address of the page, from where you want to start reading the data.
- RxBuf is the address of the 32 bit array, where you want to store the data.
- numberofwords is the number of words that you want to read from the memory.
Main Function
char *data = "hello FLASH from ControllerTech\
This is a test to see how many words can we work with";
uint32_t data2[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9};
uint32_t Rx_Data[30];
char string[100];
int number = 123;
float val = 123.456;
float RxVal;
Flash_Write_Data(0x08004410 , (uint32_t *)data2, 9);
Flash_Read_Data(0x08004410 , Rx_Data, 10);
int numofwords = (strlen(data)/4)+((strlen(data)%4)!=0);
Flash_Write_Data(0x08004810 , (uint32_t *)data, numofwords);
Flash_Read_Data(0x08004810 , Rx_Data, numofwords);
Convert_To_Str(Rx_Data, string);
Flash_Write_NUM(0x08005C10, number);
RxVal = Flash_Read_NUM(0x08005C10);
Flash_Write_NUM(0x08012000, val);
RxVal = Flash_Read_NUM(0x08012000);
Here I am writing 4 different data types to the different locations in the memory.
After we perform the read, the same data will be available, and this indicates that the write and read was successful.
Result
FLASH SECTOR TYPE
Some microcontrollers have memory distributed in Sectors.
In my STM32F446RE, there are 7 sectors and the size is varying between them. Similarly, some microcontrollers can have 11, 15 or 23 sectors. This code will cover all these types, irrespective of the number of sectors the controller have.
IMPORTANT
If the memory for the controller is arranged in dual banks, like Bank1 or Bank2, by defaults these Banks are disabled and the memory uses only single Bank addressing. Check the sector addresses in the single Bank distribution.
Also, if the sector sizes are different than as shown in the picture above, All you need to do is, define new sectors as according to your device datasheet in the function static uint32_t GetSector(uint32_t Address)
Some insight into the CODE
Write Data to FLASH
uint32_t Flash_Write_Data (uint32_t StartSectorAddress, uint32_t *Data, uint16_t numberofwords)
{
static FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t SECTORError;
int sofar=0;
/* Unlock the Flash to enable the flash control register access *************/
HAL_FLASH_Unlock();
/* Erase the user Flash area */
/* Get the number of sector to erase from 1st sector */
uint32_t StartSector = GetSector(StartSectorAddress);
uint32_t EndSectorAddress = StartSectorAddress + numberofwords*4;
uint32_t EndSector = GetSector(EndSectorAddress);
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
EraseInitStruct.Sector = StartSector;
EraseInitStruct.NbSectors = (EndSector - StartSector) + 1;
/* Note: If an erase operation in Flash memory also concerns data in the data or instruction cache,
you have to make sure that these data are rewritten before they are accessed during code
execution. If this cannot be done safely, it is recommended to flush the caches by setting the
DCRST and ICRST bits in the FLASH_CR register. */
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
{
return HAL_FLASH_GetError ();
}
/* Program the user Flash area word by word
(area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
while (sofar<numberofwords)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, StartSectorAddress, Data[sofar]) == HAL_OK)
{
StartSectorAddress += 4; // use StartPageAddress += 2 for half word and 8 for double word
sofar++;
}
else
{
/* Error occurred while writing data in Flash memory*/
return HAL_FLASH_GetError ();
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();
return 0;
}
- Flash_Write_Data will write data to the given memory location.
- It will calculate the start sector number based on the address given in the parameter
- then, the sector address of the sector where the data is going to end
- and finally the sector number of the last sector
- It will than erase the required number of sectors and program it with the new data
Read Data from FLASH
void Flash_Read_Data (uint32_t StartSectorAddress, uint32_t *RxBuf, uint16_t numberofwords)
{
while (1)
{
*RxBuf = *(__IO uint32_t *)StartSectorAddress;
StartSectorAddress += 4;
RxBuf++;
if (!(numberofwords--)) break;
}
}
Flash_Read_Data will read the given amount of words from the memory location, and save it in the RxBuf
Main Function
char *data = "hello FLASH from ControllerTech\
This is a test to see how many words can we work with";
uint32_t data2[] = {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9};
uint32_t Rx_Data[30];
char string[100];
int number = 123;
float val = 123.456;
float RxVal;
Flash_Write_Data(0x08004100 , (uint32_t *)data2, 9);
Flash_Read_Data(0x08004100 , Rx_Data, 10);
int numofwords = (strlen(data)/4)+((strlen(data)%4)!=0);
Flash_Write_Data(0x08008100 , (uint32_t *)data, numofwords);
Flash_Read_Data(0x08008100 , Rx_Data, numofwords);
Convert_To_Str(Rx_Data, string);
Flash_Write_NUM(0x0800C100, number);
RxVal = Flash_Read_NUM(0x0800C100);
Flash_Write_NUM(0x0800D100, val);
RxVal = Flash_Read_NUM(0x0800D100);
Here I am writing 4 different data types to the different locations in the memory.
After we perform the read, the same data will be available, and this indicates that the write and read was successful.
Result