2025-10-01 9:57 AM
I'm developing a bootloader for a project using the STM32H563VGT6 with 1MB of internal flash memory. I've developed a bootloader in the past for STM32H743 which works correcty.
In this H5 bootloader I seem to have problems writing to the internal flash memory. Below is the code I have to write a block of data to flash memory.
uint32_t Flash_Write_Data (uint32_t StartSectorAddress, uint32_t *data, uint16_t numberofwords)
{
static FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t SECTORError;
int sofar=0;
/* Unlock the Flash to enable the flash control register access *************/
HAL_FLASH_Unlock();
/* Erase the user Flash area */
/* Get the number of sector to erase from 1st sector */
uint32_t StartSector = GetSector(StartSectorAddress);
uint32_t EndSectorAddress = StartSectorAddress + numberofwords*4;
uint32_t EndSector = GetSector(EndSectorAddress);
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
EraseInitStruct.Sector = StartSector;
// The the proper BANK to erase the Sector
if (StartSectorAddress < 0x08100000)
EraseInitStruct.Banks = FLASH_BANK_1;
else EraseInitStruct.Banks = FLASH_BANK_2;
EraseInitStruct.NbSectors = (EndSector - StartSector) + 1;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
{
return HAL_FLASH_GetError ();
}
/* Program the user Flash area 8 WORDS at a time
* (area defined by FLASH_USER_START_ADDR and FLASH_USER_END_ADDR) ***********/
while (sofar<numberofwords)
{
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD_EDATA, StartSectorAddress, (uint32_t ) &data[sofar]) == HAL_OK)
{
StartSectorAddress += 4*8; //
sofar+=8;
}
else
{
/* Error occurred while writing data in Flash memory*/
return HAL_FLASH_GetError ();
}
}
/* Lock the Flash to disable the flash control register access (recommended
to protect the FLASH memory against possible unwanted operation) *********/
HAL_FLASH_Lock();
return 0;
}I'm calling this to write a block of 4096 bytes of data to flash address 0x08020000. The HAL_FLASHEx_Erase() seems to execute ok and returns HAL_OK status, but when I view the area of memory that should be erased the old data still exists. The variable SECTORError is still at 0xFFFFFFFF when coming out of the flash erase function. Then, once I get down to write the data to flash with HAL_FLASH_Program(), the function returns a status with HAL_TIMEOUT.
One major difference I saw between the STM32H7 and H5 is the mapping of memory sectors so maybe I have this setup wrong. The STM32H743 I was using in my last project only had 8 sectors per flash memory bank (2 banks for 2MB flash memory) with 128KB per sector. Based on what I've been able to get from the STM32H563 datasheet, the H5 has 32 sectors for each bank (only 1 bank of 1MB for the H5 I am using) with 32KB per sector. So with the code above, the GetSector function returns sector 4 that is used in the EraseInitStruct in which Sector is set to 4 and NbSectors is set to 1. Below shows how I have the memory sectors setup...any advice would be appreciated.
static uint32_t GetSector(uint32_t Address)
{
uint32_t sector = 0;
/* BANK 1 */
if((Address >= 0x08000000) && (Address < 0x08008000)) { sector = FLASH_SECTOR_0;}
else if((Address >= 0x08008000) && (Address < 0x08010000)) { sector = FLASH_SECTOR_1;}
else if((Address >= 0x08010000) && (Address < 0x08018000)) { sector = FLASH_SECTOR_2;}
else if((Address >= 0x08018000) && (Address < 0x08020000)) { sector = FLASH_SECTOR_3;}
else if((Address >= 0x08020000) && (Address < 0x08028000)) { sector = FLASH_SECTOR_4;}
else if((Address >= 0x08028000) && (Address < 0x08030000)) { sector = FLASH_SECTOR_5;}
else if((Address >= 0x08030000) && (Address < 0x08038000)) { sector = FLASH_SECTOR_6;}
else if((Address >= 0x08038000) && (Address < 0x08040000)) { sector = FLASH_SECTOR_7;}
else if((Address >= 0x08040000) && (Address < 0x08048000)) { sector = FLASH_SECTOR_8;}
else if((Address >= 0x08048000) && (Address < 0x08050000)) { sector = FLASH_SECTOR_9;}
else if((Address >= 0x08050000) && (Address < 0x08058000)) { sector = FLASH_SECTOR_10;}
else if((Address >= 0x08058000) && (Address < 0x08060000)) { sector = FLASH_SECTOR_11;}
else if((Address >= 0x08060000) && (Address < 0x08068000)) { sector = FLASH_SECTOR_12;}
else if((Address >= 0x08068000) && (Address < 0x08070000)) { sector = FLASH_SECTOR_13;}
else if((Address >= 0x08070000) && (Address < 0x08078000)) { sector = FLASH_SECTOR_14;}
else if((Address >= 0x08078000) && (Address < 0x08080000)) { sector = FLASH_SECTOR_15;}
else if((Address >= 0x08080000) && (Address < 0x08088000)) { sector = FLASH_SECTOR_16;}
else if((Address >= 0x08088000) && (Address < 0x08090000)) { sector = FLASH_SECTOR_17;}
else if((Address >= 0x08090000) && (Address < 0x08098000)) { sector = FLASH_SECTOR_18;}
else if((Address >= 0x08098000) && (Address < 0x080A0000)) { sector = FLASH_SECTOR_19;}
else if((Address >= 0x080A0000) && (Address < 0x080A8000)) { sector = FLASH_SECTOR_20;}
else if((Address >= 0x080A8000) && (Address < 0x080B0000)) { sector = FLASH_SECTOR_21;}
else if((Address >= 0x080B0000) && (Address < 0x080B8000)) { sector = FLASH_SECTOR_22;}
else if((Address >= 0x080B8000) && (Address < 0x080C0000)) { sector = FLASH_SECTOR_23;}
else if((Address >= 0x080C0000) && (Address < 0x080C8000)) { sector = FLASH_SECTOR_24;}
else if((Address >= 0x080C8000) && (Address < 0x080D0000)) { sector = FLASH_SECTOR_25;}
else if((Address >= 0x080D0000) && (Address < 0x080D8000)) { sector = FLASH_SECTOR_26;}
else if((Address >= 0x080D8000) && (Address < 0x080E0000)) { sector = FLASH_SECTOR_27;}
else if((Address >= 0x080E0000) && (Address < 0x080E8000)) { sector = FLASH_SECTOR_28;}
else if((Address >= 0x080E8000) && (Address < 0x080F0000)) { sector = FLASH_SECTOR_29;}
else if((Address >= 0x080F0000) && (Address < 0x080F8000)) { sector = FLASH_SECTOR_30;}
else if((Address >= 0x080F8000) && (Address < 0x08100000)) { sector = FLASH_SECTOR_31;}
Solved! Go to Solution.
2025-10-03 8:12 AM
I guess I did not fully understand the implementation of FLASH_TYPEPROGRAM_WORD_EDATA type. I see now that the HAL_FLASH_Program() checks for the EDATA area in order to use this program type.
There doesn't seem to be another type FLASH_TYPEPROGRAM_WORD allowed in H5 series, so that is why I thought the FLASH_TYPEPROGRAM_WORD_EDATA could be used for writing word size data. Thanks for the clarification, I believe I've been able to use the FLASH_TYPEPROGRAM_QUADWORD type to write the application program to the correct area of flash from the bootloader.
Just to confirm, it seems that the FLASH_TYPEPROGRAM_QUADWORD is the only size available to write to the standard user area of the internal flash.
2025-10-01 2:44 PM - edited 2025-10-01 2:46 PM
I figured out that the sector size on the STM32H563 is actually 8KB...so it has 32KB "groups" of 4 sectors, very poor working in datasheet. Therfore, each 1MB bank has 128 sectors of 8KB each. So now with that modification the Flash erase is working properly now but the Flash Write of a word still returns HAL_TIMEOUT, any ideas how to resolve this?
2025-10-02 2:27 AM
His "modern" Chips have a hiden ECC for flash lines, this means that You have to write 1 Flash line.
On the H565 this means You have to write blockes of 128 Bit (16Byte) with a single command.
2025-10-02 7:20 AM
Hello @PFlor.2
Did you the check the implementation of flash erase and program in the example below?
2025-10-02 7:35 AM
Yes, the only difference is the HAL_FLASH_Program() used the quadword type of write in the example and I'm using word (FLASH_TYPEPROGRAM_WORD_EDATA)...according to the HAL code it should allow for halfword, word, quadword. Is the WORD type (FLASH_TYPEPROGRAM_WORD_EDATA) not supported properly by the STM32H5 series?
2025-10-02 7:38 AM
So the H565 does not support the HalfWord, and Word types, only the QuadWord type? Looking at the HAL code it should support all 3 types. I will try to implement with QuadWord type and see if the problem is resolved.
HAL_StatusTypeDef HAL_FLASH_Program(uint32_t TypeProgram, uint32_t FlashAddress, uint32_t DataAddress)
{
HAL_StatusTypeDef status;
__IO uint32_t *reg_cr;
#if defined (FLASH_SR_OBKERR)
__IO uint32_t *reg_obkcfgr;
#endif /* FLASH_SR_OBKERR */
/* Check the parameters */
assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));
/* Reset error code */
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
if (status == HAL_OK)
{
/* Set current operation type */
pFlash.ProcedureOnGoing = TypeProgram;
/* Access to SECCR or NSCR depends on operation type */
#if defined (FLASH_OPTSR2_TZEN)
reg_cr = IS_FLASH_SECURE_OPERATION() ? &(FLASH->SECCR) : &(FLASH_NS->NSCR);
#else
reg_cr = &(FLASH_NS->NSCR);
#endif /* FLASH_OPTSR2_TZEN */
if ((TypeProgram & (~FLASH_NON_SECURE_MASK)) == FLASH_TYPEPROGRAM_QUADWORD)
{
/* Check the parameters */
assert_param(IS_FLASH_USER_MEM_ADDRESS(FlashAddress));
/* Program a quad-word (128-bit) at a specified address */
FLASH_Program_QuadWord(FlashAddress, DataAddress);
}
#if defined (FLASH_SR_OBKERR)
else if ((TypeProgram == FLASH_TYPEPROGRAM_QUADWORD_OBK) || (TypeProgram == FLASH_TYPEPROGRAM_QUADWORD_OBK_ALT))
{
/* Check the parameters */
assert_param(IS_FLASH_OBK_ADDRESS(FlashAddress));
/* Program a quad-word (128-bit) of OBK at a specified address */
FLASH_Program_QuadWord_OBK(FlashAddress, DataAddress);
}
#endif /* FLASH_SR_OBKERR */
#if defined (FLASH_EDATAR_EDATA_EN)
else if ((TypeProgram & (~FLASH_NON_SECURE_MASK)) == FLASH_TYPEPROGRAM_HALFWORD_EDATA)
{
/* Check the parameters */
assert_param(IS_FLASH_EDATA_ADDRESS(FlashAddress));
/* Program a Flash high-cycle data half-word at a specified address */
FLASH_Program_HalfWord(FlashAddress, DataAddress);
}
else if ((TypeProgram & (~FLASH_NON_SECURE_MASK)) == FLASH_TYPEPROGRAM_WORD_EDATA)
{
/* Check the parameters */
assert_param(IS_FLASH_EDATA_ADDRESS(FlashAddress));
/* Program a Flash high-cycle data half-word at a specified address */
FLASH_Program_Word(FlashAddress, DataAddress);
}
#endif /* FLASH_EDATAR_EDATA_EN */
else
{
/* Check the parameters */
assert_param(IS_FLASH_OTP_ADDRESS(FlashAddress));
/* Program an OTP half-word at a specified address */
FLASH_Program_HalfWord(FlashAddress, DataAddress);
}
/* Wait for last operation to be completed */
status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
#if defined (FLASH_SR_OBKERR)
/* If the program operation is completed, disable the PG */
CLEAR_BIT((*reg_cr), (TypeProgram & ~(FLASH_NON_SECURE_MASK | FLASH_OBK | FLASH_OTP | FLASH_OBKCFGR_ALT_SECT)));
/* Clear alternate sector bit */
if (TypeProgram == FLASH_TYPEPROGRAM_QUADWORD_OBK_ALT)
{
reg_obkcfgr = IS_FLASH_SECURE_OPERATION() ? &(FLASH->SECOBKCFGR) : &(FLASH_NS->NSOBKCFGR);
CLEAR_BIT((*reg_obkcfgr), FLASH_OBKCFGR_ALT_SECT);
}
#else
/* If the program operation is completed, disable the PG */
CLEAR_BIT((*reg_cr), (TypeProgram & ~(FLASH_NON_SECURE_MASK | FLASH_OTP)));
#endif /* FLASH_SR_OBKERR */
}
/* return status */
return status;
}
2025-10-02 7:38 AM
Hello @PFlor.2
First you need to check if the config with quadword work fine. And then update to FLASH_TYPEPROGRAM_WORD_EDATA.
2025-10-02 9:15 AM
I have confirmed that the HAL_FLASH_Program() does work correctly with FLASH_TYPEPROGRAM_QUADWORD type but not with FLASH_TYPEPROGRAM_WORD_EDATA type. Is this a known problem? Is this documented somewhere?
This is not the first problem I've encountered where the STM32H563 does not support HAL functions correctly and performs differently from other STM32 products and has caused multiple delays in development.
2025-10-03 2:19 AM
Hello @PFlor.2
The EDATA area did not start at 0x08020000. Please see in the screenshot below the address start of EDAT area in BANK1 and BAK2 from reference manual.
2025-10-03 8:12 AM
I guess I did not fully understand the implementation of FLASH_TYPEPROGRAM_WORD_EDATA type. I see now that the HAL_FLASH_Program() checks for the EDATA area in order to use this program type.
There doesn't seem to be another type FLASH_TYPEPROGRAM_WORD allowed in H5 series, so that is why I thought the FLASH_TYPEPROGRAM_WORD_EDATA could be used for writing word size data. Thanks for the clarification, I believe I've been able to use the FLASH_TYPEPROGRAM_QUADWORD type to write the application program to the correct area of flash from the bootloader.
Just to confirm, it seems that the FLASH_TYPEPROGRAM_QUADWORD is the only size available to write to the standard user area of the internal flash.