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

UPDATE for H7 Series

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

uint32_t Flash_Write_Data (uint32_t StartPageAddress, uint32_t *Data, uint16_t numberofwords)
{

	static FLASH_EraseInitTypeDef EraseInitStruct;
	uint32_t PAGEError;
	int sofar=0;

	  /* Unlock the Flash to enable the flash control register access *************/
	   HAL_FLASH_Unlock();

	   /* Erase the user Flash area*/

	  uint32_t StartPage = GetPage(StartPageAddress);
	  uint32_t EndPageAdress = StartPageAddress + numberofwords*4;
	  uint32_t EndPage = GetPage(EndPageAdress);

	   /* Fill EraseInit structure*/
	   EraseInitStruct.TypeErase   = FLASH_TYPEERASE_PAGES;
	   EraseInitStruct.PageAddress = StartPage;
	   EraseInitStruct.NbPages     = ((EndPage - StartPage)/FLASH_PAGE_SIZE) +1;

	   if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
	   {
	     /*Error occurred while page erase.*/
		  return HAL_FLASH_GetError ();
	   }

	   /* Program the user Flash area word by word*/

	   while (sofar<numberofwords)
	   {
	     if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, StartPageAddress, Data[sofar]) == HAL_OK)
	     {
	    	 StartPageAddress += 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 takes the following parameters

  • @ StartPageAddress is the Start address of the 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 needs to be written in the memory
  • Flash will be Unlocked to make modifications
  • Based on the number of words, it will calculate the number of pages required to store that data
  • 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

void Flash_Read_Data (uint32_t StartPageAddress, uint32_t *RxBuf, uint16_t numberofwords)
{
	while (1)
	{

		*RxBuf = *(__IO uint32_t *)StartPageAddress;
		StartPageAddress += 4;
		RxBuf++;
		if (!(numberofwords--)) break;
	}
}

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

Check out the VIDEO Below

FLASH SECTOR TYPE

Some microcontrollers have memory distributed in Sectors.

sector type destribution

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

Check out the VIDEO Below

DOWNLOAD

You can buy me a coffee Sensor by clicking DONATE OR Just click DOWNLOAD to download the code

controllerstech

Subscribe
Notify of
guest
50 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Menu