2019-03-21 04:38 PM
I'm having trouble reading/writing to internal flash on an STM32H743XI. For a while I've been erasing/programming sectors of internal flash from a custom bootloader without issue but I somehow got the chip into a state now where 4 sectors can no longer be read from and instead trigger a hardfault. I think it has to do with ECC but I'm having trouble verifying that or clearing the error. The issue persists through power cycle. The HAL functions for erasing/programming flash still execute on these bad sectors and return HAL_OK but if I try to read data anywhere in these sectors the MCU hardfaults.
Anyone have an idea of what the issue is and how to resolve it?
Debugger is also unable to access this memory as shown below:
2020-04-30 09:11 PM
The most likely cause of this issue was an incorrect flashing of one or more 256 bit blocks. Read up about ECC in the reference manual on the flash program operation section. It says you must program a full 256 bit block or risk ECC errors. Or partially programming the same block twice can cause ECC errors. Eg, only writing one byte to a flash block instead of the full 32 bytes.
If this happens you will get a hardfault if the CPU tries to access the broken flash location. The debugger will also not be able to read from that location, there will be a gap of 8 words it just shows as ????????.
You can check for this condition by looking at the SNECCERR and DBECCERR in flash SR. It also gives you the address of the first faulty block in the ECC_FAxR register.
This can be dangerous for in field updating. IF you dont flash one block correctly (eg the last block) then try do a CRC on the flash you just programmed it will hard fault. Even more dangerous when your bootloader does the CRC and gets stuck!
2021-03-09 06:19 AM
We are also getting the strange 32 byte blocks (randomly) that can't be accessed. We have looked at registers when this happens and does not appear to be any protection getting turned on - the flash registers are the same between boards with readable flash and ones with bad sections.
We also have problems when we try to use the standard HAL flash libraries - they just don't work for large amounts of data. If anyone has code that reliably programs the H7 flash memory, we would love to see it.
2021-03-09 11:50 AM
We use STM32 HAL flash functions on STM32H753 for in service firmware update. We have done hundreds if not thousands of firmware updates with no corruption now. We use simple flash unlock, erase, program, lock. I cant post the code but it does not have anything special in it. Just calls HAL_FLASH_Program. For firmware download, we erase a large block, big enough to take the entire firmware image, then program the flash and verify checksum. Then at boot up, we search for newly installed firmware images where they are verified, then the application code is erased and replaced with the new firmware image. We flash 700kB firmware images regularly.
However, during early development I did manage to corrupt some blocks which caused ECC errors and repeating hard faults during CRC checking. So, I can see there is a potential issue there.
2021-03-09 10:04 PM
I have written the bootloader for STM32H743. Normally I avoid using HAL but for this it was easier. First take care that HAL_GetTick is working correctly since it is used inside the HAL programming routines. For the reset it is quite simple code. I have had some corruption in the beginning but this was due to unfinished erase on a sector which could only be repaired with my debugger and a chip erase.
I post my programming code.
Erase:
/*---------------------------------------------------------------------------*/
/** @brief Erase a Sector of FLASH
This performs all operations necessary to erase a sector in FLASH memory.
The page should be checked to ensure that it was properly erased. A sector must
first be fully erased before attempting to program it.
See the reference manual or the FLASH programming manual for details.
@param[in] sector (0 - 11 for some parts, 0-23 on others)
*/
void target_flash_erase(DWORD sector_, DWORD address_)
{
HAL_StatusTypeDef result;
FLASH_EraseInitTypeDef eraseType;
uint32_t error;
eraseType.TypeErase = FLASH_TYPEERASE_SECTORS;
if(sector_ > 7u)
{
eraseType.Banks = FLASH_BANK_2;
eraseType.Sector = sector_ - 8u;
}
else
{
eraseType.Banks = FLASH_BANK_1;
eraseType.Sector = sector_; /* 0 to 7 */
}
eraseType.NbSectors = 1u;
eraseType.VoltageRange = FLASH_VOLTAGE_RANGE_4;
result = HAL_FLASHEx_Erase(&eraseType, &error);
}
Program:
/*---------------------------------------------------------------------------*/
/** @brief Write a 256 bit word to FLASH
*/
void target_flash_program_256(DWORD address_, uint64_t DataAddress_)
{
FLASH->CR1 |= FLASH_VOLTAGE_RANGE_4;
FLASH->CR2 |= FLASH_VOLTAGE_RANGE_4;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address_, DataAddress_);
}
2024-01-25 08:32 AM
I had some trouble reading internal FLASH of an stm32H755.
Following your indication I discovered that there was an ECC error.
In my case I fixed by erasing the sector.
But, is there any way to check the flash state before reading it in order to prevent hardfaults?
2024-01-25 08:50 AM
Not sure, would probably be via the FLASH peripheral rather than a direct access.
You can return from Hard Faults, so could implement something like a structured error handler, with a try/catch type arrangement.
2024-01-25 03:08 PM - edited 2024-01-25 03:10 PM
> is there any way to check the flash state before reading it in order to prevent hardfaults?
Yes of course. When you expect a memory fault by accessing a specific address, the following trick can be used to "probe" this address: Mask the Bus Fault before accessing the location and check after the access. If the Bus fault has been raised, clear it.
/*
* Probe read access to address in the MCU memory space
* Return: true = OK, false = error
* Supported: Cortex-M3, M4/F, M7
* NOTE: call this with interrupts disabled to avoid side effects
*/
bool BSP_probe_address(volatile const char *address)
{
static const uint32_t BFARVALID_MASK = (0x80 << SCB_CFSR_BUSFAULTSR_Pos);
bool res = true;
/* Clear BFARVALID flag by writing 1 to it */
SCB->CFSR |= BFARVALID_MASK;
/* Ignore BusFault by enabling BFHFNMIGN; disable faults and interrupts */
uint32_t mask = __get_FAULTMASK();
__disable_fault_irq();
SCB->CCR |= SCB_CCR_BFHFNMIGN_Msk;
/* probe the address by performing 8-bit read */
__DSB();
*address;
__DMB();
if (SCB->CFSR & BFARVALID_MASK)
{
/* Yes, Bus Fault occurred */
res = false;
}
/* Re-enable BusFault by clearing BFHFNMIGN */
SCB->CCR &= ~SCB_CCR_BFHFNMIGN_Msk;
__set_FAULTMASK(mask);
__enable_fault_irq();
__DSB();
return res;
}
2024-01-30 01:49 AM
Hi @Pavel A.,
thanks for your sharing. Just for my comprehension: is this trick valid for all addresses or just for FLASH?
If I well understand, I should deactivate interrupts during address test. What if Idon't it?
2024-01-30 12:39 PM
> is this trick valid for all addresses or just for FLASH?
This should work for any non-cached address that allows byte access.
> I should deactivate interrupts during address test. What if Idon't it?
Then an interrupt can occur in any point of the probe test, and the fault can occur because of something that the handler did.
2024-01-30 11:38 PM
>This should work for any non-cached address that allows byte access.
OK. I'm using it to check the FLASH addresses that should be cached (after sector reset I have to invalidate the cache of their addresses...), so I couldn't apply this trick?