STM32H7 Flash Writing Problem: Read ends up in HardFault handler
Hi,
I'm using an STM32H723 and store my configuration data in flash. Here The procedure is: erase the flash once, then write to the erased flash. On read check the flash for a magic word to find where data have been written. Next write happens the same way, it uses the magic word to find an unused part of the flash to write to (in order to save erase cycles). So data are written several times until a new erase is necessary.
Now sometimes I end up in the HardFault handler because of an illegal read:
void *Flash_Storage_Read(const size_t length)
{
uint32_t base_addr = FLASH_STORAGE_START_ADDR;
uint32_t final_addr = base_addr + length;
uint32_t *finalData=(uint32_t*)final_addr;
const uint8_t *flashID=(uint8_t*)final_addr;
while ((final_addr<FLASH_STORAGE_END_ADDR) &&
(*finalData!=0xFFFFFFFF)) -------> this read access causes the HardFault_Handler() to be called
{
base_addr+=length;
final_addr+=length;
finalData=(uint32_t*)final_addr;
}
return (void*)base_addr;
}The problem is, when this happens, it happens at different flash-addresses, so it is not a problem of the address range I'm using (and whenever it happens, it always fits to the range defined in .ld-file). So this lets me assume the problem is caused by my write function.
This is what it looks like (somewhat simplified):
uint8_t Flash_Storage_Write(const void* data,const size_t length)
{
uint32_t base_addr = FLASH_STORAGE_START_ADDR;
uint32_t final_addr = base_addr + length;
uint32_t *finalData=(uint32_t*)base_addr;
const uint8_t *flashID=(uint8_t*)final_addr;
while ((final_addr<FLASH_STORAGE_END_ADDR) &&
(*finalData!=0xFFFFFFFF))
{
base_addr+=length;
final_addr+=length;
finalData=(uint32_t*)base_addr;
}
if (final_addr>=FLASH_STORAGE_END_ADDR)
{
if (!Flash_Storage_Erase()) return false;
base_addr = FLASH_STORAGE_START_ADDR;
final_addr = base_addr + length;
}
if (final_addr>=FLASH_STORAGE_END_ADDR)
return 0;
__disable_irq();
HAL_FLASH_Unlock();
uint32_t write_addr = base_addr & ~(FLASHWORD_SIZE - 1);
uint32_t end_addr = (final_addr + FLASHWORD_SIZE - 1) & ~(FLASHWORD_SIZE - 1);
const uint8_t* src=(const uint8_t*)data;
__attribute__((aligned(32))) uint8_t flashword[FLASHWORD_SIZE];
while (write_addr < end_addr) {
memcpy(flashword, (const void*)write_addr, FLASHWORD_SIZE);
for (uint32_t i = 0; i < FLASHWORD_SIZE; ++i) {
uint32_t abs_index = write_addr + i;
if (abs_index >= base_addr && abs_index < final_addr) {
flashword[i] = src[abs_index - base_addr];
}
}
uint8_t needs_write =0;
for (int i = 0; i < FLASHWORD_SIZE; ++i) {
if (((uint8_t*)write_addr)[i] != flashword[i]) {
needs_write = 1;
break;
}
}
if (needs_write) {
const uint64_t* qw = (const uint64_t*)flashword;
HAL_StatusTypeDef status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, write_addr, (uint32_t)qw);
if (status != HAL_OK) {
HAL_FLASH_Lock();
return false;
}
}
write_addr += FLASHWORD_SIZE;
}
HAL_FLASH_Lock();
__enable_irq();
SCB_InvalidateDCache_by_Addr((uint32_t*)FLASH_STORAGE_START_ADDR,
FLASH_STORAGE_END_ADDR - FLASH_STORAGE_START_ADDR + 1);
return 1;
}Quick note: completely disabling and enabling the IRQs was just a test to find the reason for the troubles, it does not make a difference.
So...any idea what could be wrong here?
Thanks!
