--Updated, see below--
I'm trying to write a struct of size around 680 bytes to Sector 1, Bank 2 of the flash in an STM32H757XIH6. I'm pretty new to this kind of thing so I'm slowly building on the code. I'm using the STM32 HAL driver. The address of this sector is 0x08100000.
Here's the code:
typedef struct {
uint32_t data_header;
Parameter parameter[NUMBER_PARAMETERS];
int screen_paras[MAX_SCREENS][MAX_WIDGETS];
} Persistent_data;
void save_data() {
Persistent_data save_data;
uint32_t data_header = DATA_HEADER;
save_data.data_header = data_header;
memcpy(save_data.parameter, parameter, sizeof(save_data.parameter));
memcpy(save_data.screen_paras, screen_paras, sizeof(save_data.screen_paras));
size_t size = sizeof(Persistent_data);
uint32_t word_count = (size + 3) / 4; //32bit alignment
Flash_Write(FLASH_START_ADDRESS, (uint32_t*)&save_data, word_count);
}
HAL_StatusTypeDef Flash_Write(uint32_t address, uint32_t* data, uint32_t length) {
HAL_StatusTypeDef status = HAL_OK;
// Ensure address is within the flash range
if (address < FLASH_USER_START_ADDR || (address + length) > FLASH_USER_END_ADDR) {
return HAL_ERROR;
}
// Unlock the Flash
HAL_FLASH_Unlock();
// Erase the flash sector
FLASH_EraseInitTypeDef eraseInitStruct = {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Banks = FLASH_BANK_2,
.Sector = FLASH_SECTOR_1,
.NbSectors = 1,
.VoltageRange = FLASH_VOLTAGE_RANGE_3,
};
uint32_t sectorError = 0;
status = HAL_FLASHEx_Erase(&eraseInitStruct, §orError);
if (status != HAL_OK) {
HAL_FLASH_Lock();
return status;
}
// Write the data
for (int i = 0; i < length / 4; i++) { // Writing 32-bit words
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, data[i]);
if (status != HAL_OK) {
break;
}
address += 4; // Increment address by 4 bytes (32 bits)
}
// Lock the Flash
HAL_FLASH_Lock();
return status;
}
When I try to save the save_data (with all it's members) a hard fault is generated from the line status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, data[i]);
Tracing it further it gets to *dest_addr = *src_addr;
in stm32h7xx_hal_flash.c.
From there I'm not sure how to interpret the crash stack, next is <signal handler called>() at 0xffffffed
ffffffed: Failed to execute MI command:
-data-disassemble -s 4294967277 -e 4294967529 -- 3
Error message from debugger back end:
Cannot access memory at address 0xffffffec
Please let me know if I can provide any more info
-----Update 1:---- I have updated the code to suit the 256-bit/32-byte word as suggested. New code snippets:
typedef struct {
uint32_t data_header;
Parameter parameter[NUMBER_PARAMETERS];
int screen_paras[MAX_SCREENS][MAX_WIDGETS];
} Persistent_data;
void save_data() {
Persistent_data save_data;
uint32_t data_header = DATA_HEADER;
save_data.data_header = data_header;
memcpy(save_data.parameter, parameter, sizeof(save_data.parameter));
memcpy(save_data.screen_paras, screen_paras, sizeof(save_data.screen_paras));
size_t size = sizeof(Persistent_data);
uint32_t word_count = (size + 31) / 32; //32bit alignment
Flash_Write(FLASH_START_ADDRESS, (uint32_t*)&save_data, word_count);
}
void load_data() {
Persistent_data load_data;
size_t size = sizeof(Persistent_data);
uint32_t word_count = (size + 31) / 32; //align
Flash_Read(FLASH_START_ADDRESS, (uint32_t*)&load_data, word_count);
if (load_data.data_header == DATA_HEADER) {
memcpy(parameter, load_data.parameter, sizeof(parameter));
memcpy(screen_paras, load_data.screen_paras, sizeof(screen_paras));
}
}
HAL_StatusTypeDef Flash_Write(uint32_t address, uint32_t* data, uint32_t length) {
HAL_StatusTypeDef status = HAL_OK;
// Ensure address is within the flash range
if (address < FLASH_USER_START_ADDR || (address + length) > FLASH_USER_END_ADDR) {
return HAL_ERROR;
}
// Unlock the Flash
HAL_FLASH_Unlock();
// Erase the flash sector
FLASH_EraseInitTypeDef eraseInitStruct = {
.TypeErase = FLASH_TYPEERASE_SECTORS,
.Banks = FLASH_BANK_2,
.Sector = FLASH_SECTOR_1,
.NbSectors = 1,
.VoltageRange = FLASH_VOLTAGE_RANGE_3,
};
uint32_t sectorError = 0;
status = HAL_FLASHEx_Erase(&eraseInitStruct, §orError);
if (status != HAL_OK) {
HAL_FLASH_Lock();
return status;
}
//Write the data
for (int i = 0; i < length / 32; i++) { // Writing 32-byte (256 bit) words
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, (uint32_t)&data[i * 8]);
if (status != HAL_OK) {
break;
}
address += 32; // Increment address by 32 bytes (256 bits)
}
// Lock the Flash
HAL_FLASH_Lock();
return status;
}
/**
* @brief Read data from flash memory
* @param address Start address to read (must be 256-bit aligned)
* @param data Pointer to the buffer to store the read data
* @param length Number of bytes to read (must be a multiple of 32)
*/
void Flash_Read(uint32_t address, uint32_t* data, uint32_t length) {
if (address < FLASH_USER_START_ADDR || (address + length) > FLASH_USER_END_ADDR) {
return; // Out of bounds
}
for (uint32_t i = 0; i < length / 32; i++) { // Reading 32-byte (256-bit) words
// Read 32 bytes (256 bits) from flash starting at the given address
for (uint32_t j = 0; j < 8; j++) {
data[i * 8 + j] = *(__IO uint32_t*)(address + j * 4); // 4 bytes per uint32_t word
}
address += 32; // Increment address by 32 bytes (256 bits)
}
}
New problem: When I read the data back, it isn't correct. The data_header doesn't match. There's data there, but none of it is right. Could it be something to do with the way I've referenced/used pointers? Or the way the memory is iterated over?
I think the issue may be that you are attempting to write in overlapping regions, which is prohibited per this post. Do you know which write is failing? Is it your first write or the second write?
You are incrementing the address by 4 bytes when you should be incrementing by 32 bytes, since you are writing in chunks of "FLASH_TYPEPROGRAM_FLASHWORD". See this post or this other post which are bumping the write offsets by 32 bytes on each write.
This post defines a "WORD" as 4 bytes but the H7 Series post I linked previously has this:
// If using any other STM32H7 Series, uncomment the line below
#define FLASHWORD 8
Indicating some devices define a WORD as 8 bytes, strangely enough.
You could try writing in smaller chunks such as FLASH_TYPEPROGRAM_BYTE if your device permits such an operation.