2024-09-11 09:53 PM - edited 2024-09-11 09:54 PM
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.
2024-09-12 01:43 AM
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
2024-09-12 01:56 AM
You're incrementing by decimal 10 so you're not aligned correctly. Try hex 0x10, 0x20, 0x30, etc..
2024-09-12 02:05 AM - edited 2024-09-12 02:08 AM
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?
2024-09-12 02:06 AM
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?
2024-09-12 02:12 AM
> 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
2024-09-12 08:39 AM
The RM does say that byte, half-word (16 bits?) word (32 bits?) and double-word (64 bits?) should all be possible:
2024-09-12 09:21 AM - edited 2024-09-12 09:23 AM
@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
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.
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
2024-09-12 09:59 AM
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.