2025-07-03 6:52 AM
Hello,
I am developing a RAM-based bootloader on STM32H5, to update my firmware application.
Application and bootloader resides on different flash areas, and the bootloader code is copied into RAM at startup.
[0x8000000 - 0x801FFFF] bootloader
[0x8020000 - 0x803FFFF] reserved
[0x8040000 - 0x80FFFFF] application
First, the bootloader erases all the application sectors.
Then the bootloader receives code fragments via fieldbus, and program the flash memory 16 bytes (flash-word) at time, at correctly aligned addresses:
int16_t HW_FLASH_Program(uint32_t addr, int32_t len, uint8_t *buff_p)
{
HAL_StatusTypeDef status;
uint8_t flash_word[FLASH_WORD_LEN];
uint32_t aligned_addr;
uint32_t offset;
uint32_t chunk;
HAL_FLASH_Unlock();
while (len > 0)
{
// back-align the address to 16 bytes
aligned_addr = addr & ~(FLASH_WORD_LEN - 1);
if ((addr == aligned_addr) && (len >= FLASH_WORD_LEN))
{
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, addr, (uint32_t)buff_p);
LL_ICACHE_Invalidate();
if (status != HAL_OK)
{
HAL_FLASH_Lock();
return -1;
}
addr += FLASH_WORD_LEN;
buff_p += FLASH_WORD_LEN;
len -= FLASH_WORD_LEN;
}
else
{
// address not aligned or length less than 16 bytes
// read the current contents of the flash word
for (uint32_t i = 0; i < FLASH_WORD_LEN; i++)
{
flash_word[i] = *((__IO uint8_t *)(aligned_addr + i));
}
// overwite only the affected part
offset = addr - aligned_addr;
chunk = FLASH_WORD_LEN - offset;
if (chunk > len)
{
chunk = len;
}
for (uint32_t i = 0; i < chunk; i++)
{
flash_word[offset + i] = buff_p[i];
}
// write the flash word
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, aligned_addr, (uint32_t) flash_word);
LL_ICACHE_Invalidate();
if (status != HAL_OK)
{
HAL_FLASH_Lock();
return -2;
}
addr += chunk;
buff_p += chunk;
len -= chunk;
}
}
HAL_FLASH_Lock();
return 0;
}
I can perform erase and program operations correctly, but I have an NMI exception during the verify operations, when trying to read back a particular flash location, due to an ECCD event.
I checked that the flash content is the same whether the applicaton is programmed via JTAG/SWD or bootloader, but in the first case I don't have the problem.
In particular, at 0x08040400 is placed the application CRC (0x9968) and the exception occours when reading the address 0x08040402 where are placed the padding at zero, as higlighted in bold, below:
[0x08040400 - 0x0804040F]: 68 99 00 00 | FF FF FF FF | 56 2E 31 30 | 31 00 00 00
MEMORY
{
...
CRC (r) : ORIGIN = 0x8040400, LENGTH = 0x00008
...
}
.crc :
{
. = ALIGN(4);
KEEP(*(.crc))
. = ALIGN(4);
} >CRC
const uint16_t crc __attribute__((section(".crc"))) = {0x9968};
In particular, I have seen that the .crc section code is received by the bootloader as 4 byte segment, that being shorter than the 16 byte flash-word, activates the following read-modify-write procedure:
1. Read 16 bytes flash-word at address 0x08040400 in a buffer.
2. Overwrite the first 4 location of the buffer, with the CRC + padding.
3. Write back the 16 bytes buffer to flash at address 0x08040400.
Thank you,
Carlo