cancel
Showing results for 
Search instead for 
Did you mean: 

Unable to erase sector of internal flash using HAL

CCNConner
Associate II

Problem:
HAL_FLASHEx_Erase returns error 0x20000, and HAL_FLASH_Program does return HAL_OK but does not actually write any data to the flash.

Goal: Erase and install new firmware on flash on its own inside the bootloader.

I am developing a bootloader for the STM32H533RET6. I have TrustZone enabled, and configured the secure and non-secure regions. I am trying to erase and write to the non-secure part of the flash, from the bootloader which is secure (and separate from the actual application). I have disabled any write protection that I am aware of inside the option bytes. I also use the Memory Management Tool inside CubeMX to configure the secure and non-secure regions. For the non-secure region of the flash I have set "Access Permissions" to "RW by any privilege level". I do have a Flash watermark set on bank 1 but this does not cover any of the non-secure flash regions. No watermark is set on bank 2. 

Below is the code I use to erase and write to a sector on the flash:

uint32_t Erase_And_Write_Data(uint32_t start_address, uint32_t* data, uint32_t words_size)
{
	FLASH_EraseInitTypeDef erase_init;
	uint32_t sector_error;

	HAL_FLASH_Unlock();

	// Determine sectors and bank based on start_address
	uint32_t first_sector = (start_address - 0x08000000) / INTERNAL_FLASH_SECTOR_SIZE;
	uint32_t last_sector = ((start_address - 0x08000000) + (words_size*4)) / INTERNAL_FLASH_SECTOR_SIZE;
	uint32_t sector_count = last_sector - first_sector + 1;
	uint32_t bank = start_address < 0x08040000? FLASH_BANK_1 : FLASH_BANK_2;

	// Erase sector
	erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
	erase_init.Sector = first_sector;
	erase_init.NbSectors = sector_count;
	erase_init.Banks = bank;
	if(HAL_FLASHEx_Erase(&erase_init, &sector_error) != HAL_OK) {
		HAL_FLASH_Lock();
		return HAL_FLASH_GetError();
	}

	// Write to sector
	uint32_t written = 0;
	while(written < words_size) {
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD, start_address + (written * 4), (uint32_t)&data[written]) != HAL_OK) {
			HAL_FLASH_Lock();
			return HAL_FLASH_GetError();
		}
		written += 4;
	}

	HAL_FLASH_Lock();
	return 0;
}

 

The STM32H533 flash consists of 2 banks each being 256Kbytes in size. This then is divided into sectors of 8KB making up 64 total sectors, where 0-31 is bank1 and 32-63 is bank2. I have validated that putting in a start_address results in the correct sectors, sector count and bank. I have also just tried hardcoding a sector and a bank, but this all results in the same 0x20000 error.
To test the HAL_FLASH_Program I disabled the HAL_FLASHEx_Erase. I then called the HAL_FLASH_Program on an address of a sector that I knew was empty, as I erased it using the STM32CubeProgrammer. After executing the HAL_FLASH_Program, it did infact return a HAL_OK, but after checking the data on the address I wrote to, nothing was written and everything was still 0xFFFFFFFF.

Any help or advice is appreciated.

1 ACCEPTED SOLUTION

Accepted Solutions
CCNConner
Associate II

Thanks for the replies.

By experimenting and stepping through the code I saw that inside the HAL_FLASHEx_Erase() the IS_FLASH_SECURE_OPERATION() is evaluated to determine whether the secure or non-secure control register should be used. This resulted always in the secure control registers being used even though I am erasing a sector inside a non-secure region.
To check if this is why it is failing I added the FLASH_NON_SECURE_MASK flag to the TypeErase property of the EraseInitTypeDef struct like this:

	FLASH_EraseInitTypeDef erase_init;
	erase_init.TypeErase = FLASH_TYPEERASE_SECTORS | FLASH_NON_SECURE_MASK;
	erase_init.Sector = first_sector;
	erase_init.NbSectors = sector_count;
	erase_init.Banks = bank;

This prevented the error and also actually erased the sector, so it worked.

I also added the flag to the HAL_FLASH_Program() function and this made it actually write the data to the sector aswell:

	// Write to sector
	uint32_t written = 0;
	while(written < words_size) {
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD | FLASH_NON_SECURE_MASK, start_address + (written * 4), (uint32_t)&data[written]) != HAL_OK) {
			HAL_FLASH_Lock();
			return HAL_FLASH_GetError();
		}
		written += 4;
	}

 

However this is probably not the proper way to implement this, and is definitely a result of me doing something wrong somewhere else.
I believe it has something to do with calling this from the secure world when I need to erase from the non-secure region.
Is there a function that switches the context of the flash or something I need to implement to specify that I want the flash to use the non-secure control registers instead?

View solution in original post

5 REPLIES 5
gbm
Principal

Your sector number formula is probably incorrect for the second bank. The sector numbers start from 0 IN EACH bank, so that the sector at BASE + 256 KiB is sector 0 of the second bank. See figures 25..28 in the RefMan.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice

Thank you for the reply.
I have unfortunately tried that already by hardcoding the values in, with the same error as result. Additionally erasing sectors from bank 1 also fails, so the problem is not just limited to the second bank. 

Hard coded example that fails:

	// Erase sector
	erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
	erase_init.Sector = 28;
	erase_init.NbSectors = 1;
	erase_init.Banks = FLASH_BANK_2;
	if(HAL_FLASHEx_Erase(&erase_init, &sector_error) != HAL_OK) {
		HAL_FLASH_Lock();
		return HAL_FLASH_GetError();
	}

 

TDK
Super User

WRPERR indicates write protection is not disabled.

 

Edit: The forum software ate the screenshots I posted along with this. I'm sick of this forum software. Fix the bugs ST.

If you feel a post has answered your question, please click "Accept as Solution".
gbm
Principal

Have you set ALL the fields of the structure? Start with this:

FLASH_EraseInitTypeDef erase_init = {0};

 Or, better yet, that:

FLASH_EraseInitTypeDef erase_init = {
    .TypeErase = FLASH_TYPEERASE_SECTORS,
    .Sector = 28,
    .NbSectors = 1,
    .Banks = FLASH_BANK_2
};

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
CCNConner
Associate II

Thanks for the replies.

By experimenting and stepping through the code I saw that inside the HAL_FLASHEx_Erase() the IS_FLASH_SECURE_OPERATION() is evaluated to determine whether the secure or non-secure control register should be used. This resulted always in the secure control registers being used even though I am erasing a sector inside a non-secure region.
To check if this is why it is failing I added the FLASH_NON_SECURE_MASK flag to the TypeErase property of the EraseInitTypeDef struct like this:

	FLASH_EraseInitTypeDef erase_init;
	erase_init.TypeErase = FLASH_TYPEERASE_SECTORS | FLASH_NON_SECURE_MASK;
	erase_init.Sector = first_sector;
	erase_init.NbSectors = sector_count;
	erase_init.Banks = bank;

This prevented the error and also actually erased the sector, so it worked.

I also added the flag to the HAL_FLASH_Program() function and this made it actually write the data to the sector aswell:

	// Write to sector
	uint32_t written = 0;
	while(written < words_size) {
		if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD | FLASH_NON_SECURE_MASK, start_address + (written * 4), (uint32_t)&data[written]) != HAL_OK) {
			HAL_FLASH_Lock();
			return HAL_FLASH_GetError();
		}
		written += 4;
	}

 

However this is probably not the proper way to implement this, and is definitely a result of me doing something wrong somewhere else.
I believe it has something to do with calling this from the secure world when I need to erase from the non-secure region.
Is there a function that switches the context of the flash or something I need to implement to specify that I want the flash to use the non-secure control registers instead?