cancel
Showing results for 
Search instead for 
Did you mean: 

How to correctly write 4 byte (Float) value to STM32F405 Flash memory

LPetr.1
Senior

Hey. I would like some clarification regarding writing to Flash memory. Specificially, 4 bytes (float values).

I have the following code:

 

 

void FLASH_write_single_float(uint32_t address, float data_to_send) {
    if (address < 0x080E0000 || address > 0x080FFFFF) {
        printf("Out of sector 11 bounds\n");
        return;
    }

    HAL_FLASH_Unlock();
    FLASH_WaitForLastOperation(1000);

    // Writing float as 32-bit word (4 bytes)
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *(uint32_t*)&data_to_send) == HAL_OK) {
        printf("FLASH_WRITE_OK\n");
    } else {
        printf("FLASH_WRITE_FAIL\n");
    }

    FLASH_WaitForLastOperation(2000);
    HAL_FLASH_Lock();
}




float FLASH_read_single_float(uint32_t address) {
	taskENTER_CRITICAL();
	float data_to_read = *((float*) address);
	taskEXIT_CRITICAL();
	return data_to_read;
}




void FLASH_erase_all() {
	FLASH_EraseInitTypeDef EraseInitStruct;
	uint32_t page_err;

	EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
	EraseInitStruct.Sector = FLASH_SECTOR_11;
	EraseInitStruct.NbSectors = 1;
	EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;

	HAL_FLASH_Unlock();
	FLASH_WaitForLastOperation(2000);
	HAL_FLASHEx_Erase(&EraseInitStruct, &page_err);
	FLASH_WaitForLastOperation(2000);
	HAL_FLASH_Lock();
	FLASH_WaitForLastOperation(2000);

}

 

 

 

and in my main.c I do:

 

 

  FLASH_erase_all();

  // Write and read multiple floats using 4-byte aligned addresses
  float value1 = 25.5;
  uint32_t value1_address = SECTOR_11_START + 0;  // Aligned to 4 bytes
  FLASH_write_single_float(value1_address, value1);
  float read_value1 = FLASH_read_single_float(value1_address);
  printf("read_value1 float = %.2f \n", read_value1);

  float value2 = 21.5;
  uint32_t value2_address = SECTOR_11_START + 4;  // Aligned to 4 bytes
  FLASH_write_single_float(value2_address, value2);
  float read_value2 = FLASH_read_single_float(value2_address);
  printf("read_value2 float = %.2f \n", read_value2);

  float value3 = 5.5;
  uint32_t value3_address = SECTOR_11_START + 8;  // Aligned to 4 bytes
  FLASH_write_single_float(value3_address, value3);
  float read_value3 = FLASH_read_single_float(value3_address);
  printf("read_value3 float = %.2f \n", read_value3);

  float value4 = 12.5;
  uint32_t value4_address = SECTOR_11_START + 12;  // Aligned to 4 bytes
  FLASH_write_single_float(value4_address, value4);
  float read_value4 = FLASH_read_single_float(value4_address);
  printf("read_value4 float = %.2f \n", read_value4);

  float value5 = 1.5;
  uint32_t value5_address = SECTOR_11_START + 16;  // Aligned to 4 bytes
  FLASH_write_single_float(value5_address, value5);
  float read_value5 = FLASH_read_single_float(value5_address);
  printf("read_value5 float = %.2f \n", read_value5);

  float value6 = 45.5;
  uint32_t value6_address = SECTOR_11_START + 20;  // Aligned to 4 bytes
  FLASH_write_single_float(value6_address, value6);
  float read_value6 = FLASH_read_single_float(value6_address);
  printf("read_value6 float = %.2f \n", read_value6);

  float value7 = 65.5;
  uint32_t value7_address = SECTOR_11_START + 24;  // Aligned to 4 bytes
  FLASH_write_single_float(value7_address, value7);
  float read_value7 = FLASH_read_single_float(value7_address);
  printf("read_value7 float = %.2f \n", read_value7);

 

 


Everything seems to be fine according to the logs:

 

 

Program started 
FLASH_WRITE_OK
read_value1 float = 25.50 
FLASH_WRITE_OK
read_value2 float = 21.50 
FLASH_WRITE_OK
read_value3 float = 5.50 
FLASH_WRITE_OK
read_value4 float = 12.50 
FLASH_WRITE_OK
read_value5 float = 1.50 
FLASH_WRITE_OK
read_value6 float = 45.50 
FLASH_WRITE_OK
read_value7 float = 65.50 

 

 





However, when I try to change the addresses to which I am writing (not alligned to 4 bytes):

 

 

  FLASH_erase_all();

  // Write and read multiple floats using 4-byte aligned addresses
  float value1 = 25.5;
  uint32_t value1_address = SECTOR_11_START + 10; 
  FLASH_write_single_float(value1_address, value1);
  float read_value1 = FLASH_read_single_float(value1_address);
  printf("read_value1 float = %.2f \n", read_value1);

  float value2 = 21.5;
  uint32_t value2_address = SECTOR_11_START + 20; 
  FLASH_write_single_float(value2_address, value2);
  float read_value2 = FLASH_read_single_float(value2_address);
  printf("read_value2 float = %.2f \n", read_value2);

  float value3 = 5.5;
  uint32_t value3_address = SECTOR_11_START + 30; 
  FLASH_write_single_float(value3_address, value3);
  float read_value3 = FLASH_read_single_float(value3_address);
  printf("read_value3 float = %.2f \n", read_value3);

  float value4 = 12.5;
  uint32_t value4_address = SECTOR_11_START + 40;  
  FLASH_write_single_float(value4_address, value4);
  float read_value4 = FLASH_read_single_float(value4_address);
  printf("read_value4 float = %.2f \n", read_value4);

  float value5 = 1.5;
  uint32_t value5_address = SECTOR_11_START + 50;  
  FLASH_write_single_float(value5_address, value5);
  float read_value5 = FLASH_read_single_float(value5_address);
  printf("read_value5 float = %.2f \n", read_value5);

  float value6 = 45.5;
  uint32_t value6_address = SECTOR_11_START + 60;  
  FLASH_write_single_float(value6_address, value6);
  float read_value6 = FLASH_read_single_float(value6_address);
  printf("read_value6 float = %.2f \n", read_value6);

  float value7 = 65.5;
  uint32_t value7_address = SECTOR_11_START + 70; 
  FLASH_write_single_float(value7_address, value7);
  float read_value7 = FLASH_read_single_float(value7_address);
  printf("read_value7 float = %.2f \n", read_value7);

 

 

it no longer able to read the values properly :

 

 

Program started 
ad_value1 float =FLASH_WRITE_FAIL
read_value1 float = -nan 
FLASH_WRITE_OK
read_value2 float = 21.50 
FLASH_WRITE_FAIL
read_value3 float = -nan 
FLASH_WRITE_OK
read_value4 float = 12.50 
FLASH_WRITE_FAIL
read_value5 float = -nan 
FLASH_WRITE_OK
read_value6 float = 45.50 
FLASH_WRITE_FAIL
read_value7 float = -nan 

 

 



I would like to understand what is the reason behind this. I have tried going through the STM32F405 datasheets:
https://www.st.com/resource/en/datasheet/dm00037051.pdf 

https://www.st.com/resource/en/reference_manual/dm00031020-stm32f405-415-stm32f407-417-stm32f427-437-and-stm32f429-439-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf

But was not able to find the answers I am looking for. I hope I can get some clarifications here. Thanks in advance.

 

8 REPLIES 8

This is not specific to float: you must not write words to non-word-aligned addresses.

You can disassemble the word to halfwords or bytes as per alignment and use a different level of parallelism for writing. I don't use Cube/HAL so can't tell how to do that in Cube.

Reading is not restricted in this way.

JW

Karl Yamashita
Lead III

You're incrementing by decimal 10 so you're not aligned correctly. Try hex 0x10, 0x20, 0x30, etc..

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

Yes I figured that this is to do with allignment, but I do not understand why? I tried to find a section in the reference manual that explains flash memory allignment and why it works this way.

Why can we not write unaligned data to the flash memory?  Is this specific to STM32F405 or all STM32 in general?

Are you suggesting that if I try to write 4 bytes one byte at a time to unaligned addresses I will have no problem, but if I try to write 4 bytes (32 bits) at once to unalligned addresses it will not work?

> Are you suggesting that if I try to write 4 bytes one byte at a time to unaligned addresses I will have no problem, but if I try to write 4 bytes (32 bits) at once to unalligned addresses it will not work?

As long as we are talking about writing to FLASH as described in the Flash chapter of RM, then yes: if you use 32-bit parallelism, you have to write to word-aligned addresses.

I don't use Cube/HAL so I don't know what the function you've used (HAL_FLASH_Program()) exactly does - that's upon you to investigate.

JW

The RM does say that byte, half-word (16 bits?) word (32 bits?) and double-word (64 bits?) should all be possible:

AndrewNeil_1-1726155479406.png

 

 

 

Karl Yamashita
Lead III

@Andrew Neil Yes you can still write as a word or any of the other writes, but it still has to align to within a column. Right now the OP is trying to write part of his float in column 8 and C when he use decimal 10, 20, 30, etc. In this case for decimal 10, it fails to write anything and still shows 0xFFFFFFFF

 

KarlYamashita_1-1726157401277.png

 

Here is when writing at SECTOR_11_START + 12 which is now aligned in a column and not overlapping into another column. So in this case it does write the value in flash correctly.

KarlYamashita_0-1726157160871.png

I originally thought the OP was trying to increment the address so it would align like this. So I told him to use hex 0x10, 0x20 and so on

KarlYamashita_2-1726157853552.png

 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

The size of the write determines the permitted granularity, word and half-word can't SPAN

Other STM32 have MORE restrictions, depends on the flash-line widths, which frequently contain more bits, hidden, which contain ECC or HAMMING type data.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..