Programming FLASH ROM in STM32

Sanskar Biswal
TheTeamMavericks
Published in
4 min readMay 25, 2020
Fig.1 STM32F4 Discovery Kit

Depending on who you are and what specific task you might need to achieve, you may find yourself in a position where you might have to save and then read data from the FLASH ROM space in microcontrollers. In this guide, I will detail the steps for an STM32F407VGT chip, however you can easily adapt it to your chip by referring to its data-sheet.

What is the FLASH Memory?

The FLASH or the ROM (Read Only Memory), is a chip on most microcontrollers and microprocessors which stored the program it needs to execute. In microcontrollers, the ROM is built into the IC whereas ROM is a separate IC peripheral for microprocessors. Since STM32 is a microcontroller, it naturally follows that its has an on-chip FLASH memory.

FLASH memory is typically divided into sectors, with each sector corresponding to a range of memory addresses. The top/first sector is where the program code is stored, so it is worth remembering that if you need to use the FLASH memory, do not overwrite the first sector. The safest approach is to start with the last sector and use only that one for any FLASH I/O operation.

FLASH Memory in STM32F4

Fig.1 Sector Addressing in STM32F4

The STM32F407VGTx, has 12 sectors in it’s FLASH memory with the first four, ie Sector 0 to Sector 3 being 16 KB each. Sector 4 is 64 KB and finally Sector 5–11 is 128 KB each. The address is really important as we will refer to these addresses when writing and reading data from the FLASH Memory sectors.

Getting Started

You can use STMCubeMX to generate a project for Keil. There is no need to enable any peripherals since we will make use of randomly generated data to store and read from FLASH.

If you are new to STM32F4, I have a beginners tutorial to setup a project in Keil using CubeMX. https://medium.com/theteammavericks/a-beginners-guide-to-developing-on-stm32-b7fd38966aa0

Once you are setup with the project, we need to import some libraries for FLASH I/O. If one wants, it is possible to do a register level programming to access FLASH ROM, but for a beginner to intermediate developer, it is sufficient to make use of a library.

https://github.com/MYaqoobEmbedded/STM32-Tutorials/tree/master/Tutorial%2030%20-%20FLASH%20Memory

I recommend the libraries from the link above. It is developed by another developer who has also provided a lot of instructional videos on YouTube for STM32 development.

Download the MY_FLASH.h and MY_FLASH.c to your project directory under the folder MDK-ARM/. In your Project Explorer in Keil, right-click on MDK-ARM tab and select ‘add existing files’. Select the MY_FLASH files and they should now appear in the hierarchy of MDK-ARM in the Project Explorer.

The Code

Note: This code will be inside the main function. If an external function is doing the FLASH operations, then they need to be called from within the main function.

The brief steps to be followed for FLASH I/O are:

  1. Select and assign working sector. Usually, the last sector is used for this purpose. In our case, this will be sector 11.
MY_FLASH_SetSectorAddrs(11, 0x080E0000); // Sector 11 Addr.

2. Erase the FLASH Sector, if new data needs to be written.

MY_FLASH_EraseSector();

3. In our example, we are writing an array of struct values. Hence, I enclosed the procedure into a function. This can be called either in a while loop or if you have data being generated in real-time. In either case, you will have to pass the structure as a variable to the function.

/**
*@brief Write Struct Data to FLASH
*@param Struct Data
*@param Target Address
*/
void writeXL2FLASH(struct randData * data){
int i;
pData = (uint32_t* )data;
HAL_FLASH_Unlock();
for(i=0;i<sizeof(buffer);i+=4){
HAL_StatusTypeDef retVal = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, save_addr, *pData);
HAL_Delay(10);
if(retVal == HAL_OK){
pData++;
save_addr+=4;
HAL_Delay(10);
}
}
HAL_FLASH_Lock();
}

What the code above achieves is very simple.

  • Unlocks the FLASH Memory for I/O.
  • Passes the data, which has been converted into an array of unsigned integers. Thus, even if your data is multi-byte, there will be no issues since we are writing one byte at a time.
  • In my case, each element of the structure is a float variable, which is 4 bytes long. Thus, we increase the next address by 4. The data is converted into bytes of pData. Thus, since we can only write one word at a time, we increment it by 1.
  • Once, the operation is complete, we Lock the FLASH again.

Note: 1 Word => 4 bytes

4. Reading From Flash Memory.

/* Read Data From FLASH*/
t_data = (uint32_t*)&rx_Data;
for(int i=0;i<sizeof(rx_Data);i+=4,t_data++,t_addr+=4){
*t_data = *(uint32_t*)t_addr;
switch(i){
case 0:
tx_Data.XL_x = *(float*)t_data;
break;
case 4:
tx_Data.XL_y = *(float*)t_data;
break;
case 8:
tx_Data.XL_z = *(float*)t_data;
break;
case 12:
tx_Data.GYR_x = *(float*)t_data;
break;
case 16:
tx_Data.GYR_y = *(float*)t_data;
break;
case 20:
tx_Data.GYR_z = *(float*)t_data;
break;
default:
break;
}

The code above is pretty self-explanatory. We loop through the FLASH address and just read it. There is no hassle of having to go through it via the FLASH I/O methods. My struct was meant to read data from an MPU6050 and save and store data to enable wireless data-collection. Thus, my for-loop is calibrated accordingly. You may however need to make changes for your use case.

Concluding Remarks

It is my hope that this article can act as a primer to anyone struggling to find resources beyond the regular FLASH I/O operations and work with a more complicated concept like storing structure data instead of just raw bytes.

--

--

Sanskar Biswal
TheTeamMavericks

Electronics Engineer | Firmware Developer | Programmer | Poet | Writer