cancel
Showing results for 
Search instead for 
Did you mean: 

When flashing code on STM32H7, blocks of 0s appear in reserved flash memory.

QLeco.1
Associate II

Hey everyone.

In my project, I want to reserve some flash sectors to write data that I don't want erased when flashing new code on my processor.

So I changed the .ld files to reserve my memory as follow :

M7 files :

STM32H755ZITX_FLASH.ld and STM32H755ZITX_RAM.ld :

/* Memories definition */
MEMORY
{
  RAM_D1 (xrw)    : ORIGIN = 0x24000000, LENGTH = 512K
  FLASH    (rx)   : ORIGIN = 0x08000000, LENGTH = 1408K  /* added m4 memory to m7 since I don't need it on the m4 */
  USER_FLASH (rx) : ORIGIN = 0x08180000, LENGTH = 512K
  DTCMRAM (xrw)   : ORIGIN...
...
}
/* The rest is unchanged */

M4 files :

STM32H755ZITX_FLASH.ld

MEMORY
{
FLASH (rx)   : ORIGIN = 0x08160000, LENGTH = 128K
RAM (xrw)    : ORIGIN = 0x10000000, LENGTH = 288K
}
 
/* rest is unchanged */

I can write to the reserved flash USER_FLASH using functions I defined without any apparent problem. Indeed, when I check my memory with a memory monitor, everything is writen correctly. Here are the functions :

#include "stm32h7xx_hal.h"
 
/**
  * @brief  Return the sector corresponding to the address
  * given in argument
  * @param  The address you want to know the
  * sector of.
  *
  * @retval The number corresponding to the sector, or
  *  -1 if an error occured
  */
int8_t GetSector(uint32_t address)
{
	if ((address >= 0x08000000 && address < 0x08020000) || (address >= 0x08100000 && address < 0x08120000))
	{
		return FLASH_SECTOR_0;
	}
	if ((address >= 0x08020000 && address < 0x08040000) || (address >= 0x08120000 && address < 0x08140000))
	{
		return FLASH_SECTOR_1;
	}
	if ((address >= 0x08040000 && address < 0x08060000) || (address >= 0x08140000 && address < 0x08160000))
	{
		return FLASH_SECTOR_2;
	}
	if ((address >= 0x08060000 && address < 0x08080000) || (address >= 0x08160000 && address < 0x08180000))
	{
		return FLASH_SECTOR_3;
	}
	if ((address >= 0x08080000 && address < 0x080A0000) || (address >= 0x08180000 && address < 0x081A0000))
	{
		return FLASH_SECTOR_4;
	}
	if ((address >= 0x080A0000 && address < 0x080C0000) || (address >= 0x081A0000 && address < 0x081C0000))
	{
		return FLASH_SECTOR_5;
	}
	if ((address >= 0x080C0000 && address < 0x080E0000) || (address >= 0x081C0000 && address < 0x081E0000))
	{
		return FLASH_SECTOR_6;
	}
	if ((address >= 0x080E0000 && address < 0x08100000) || (address >= 0x081E0000 && address < 0x08200000))
	{
		return FLASH_SECTOR_7;
	}
	return -1;
}
 
/**
  * @brief  Return the bank corresponding to the address
  * given in argument
  * @param  The address you want to know the
  * bank of.
  *
  * @retval The number corresponding to the bank, or
  *  -1 if an error occured
  */
int8_t GetBank(uint32_t address)
{
	if (address >= 0x08000000 && address < 0x08100000)
	{
		return FLASH_BANK_1;
	}
	if (address >= 0x08100000 && address < 0x08200000)
	{
		return FLASH_BANK_2;
	}
	return -1;
}
 
/**
  * @brief  Erase the specified FLASH memory sector
  * @param  Sector FLASH sector to erase
  *          This parameter can be a value of @ref FLASH_Sectors
  * @param	nbSectors the number of contiguous sector you want to erase.
  * 		 For instance, if nbSectors is 2 and StartSector is FLASH_SECTOR_3,
  * 		 sectors 3 and 4 are going to be erased.
  * 		 This parameter must be a value between 1 and (max number of sectors (8)- value of Initial sector)
  * @param  Banks Banks to be erased
  *          This parameter can be one of the following values:
  *            @arg FLASH_BANK_1: Bank1 to be erased
  *            @arg FLASH_BANK_2: Bank2 to be erased
  *            @arg FLASH_BANK_BOTH: Bank1 and Bank2 to be erased
  *
  * @retval None
  */
 
int32_t Flash_Erase_Sector(uint32_t StartSector, uint32_t Banks, uint32_t nbSectors)
{
	if (Banks < 0 || StartSector < 0 || nbSectors < 1 || nbSectors > 8-StartSector)
	{
		return -1;
	}
 
	FLASH_EraseInitTypeDef EraseInitStruct;
	uint32_t SECTORError;
 
	/* Unlock the Flash to enable the flash control register access *************/
	HAL_FLASH_Unlock();
 
	/* Erase the user Flash area*/
 
	/* Fill EraseInit structure*/
	EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
	EraseInitStruct.Sector = StartSector;
	EraseInitStruct.NbSectors = nbSectors;
	EraseInitStruct.Banks = Banks;
	EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
 
	if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
	{
		/*Error occurred while page erase.*/
		return HAL_FLASH_GetError ();
	}
 
	HAL_FLASH_Lock();
 
	return 0;
 
}
 
 
/**
  * @brief  Write (size*32) bytes of data in the flash memory
  * @param  StartAddress is the address where you want
  * to start writing to.
  * @param Data is a buffer containing the data you want
  * to write in the flash memory.
  * @param size the number of 32-bytes data you want to read
  * @param erase set to TRUE to erase memory before writing
  * set to FALSE to not erase memory.
  *
  * @retval Return the next available address on success, 0 if an error occured while
  * retrieving the sector/bank where you wanted to write or a
  * HAL_Error if an error occured while erasing or writing the flash.
  *
  * @note When writing to a sector, the whole sector will be erased first.
  * Make sure there wasn't any important data here first.
  */
 
uint32_t Flash_Write_Data_32 (uint32_t StartAddress, uint32_t * Data, int32_t size, bool erase)
{
 
	static FLASH_EraseInitTypeDef EraseInitStruct;
	uint32_t SECTORError;
	uint8_t nbSector = (size / 128000) + 1; // Les secteurs font 128 Kbytes
	uint8_t StartSector = GetSector(StartAddress);
	uint8_t bank = GetBank(StartAddress);
 
	if (bank < 0 || StartSector < 0 || StartSector + nbSector -1 > 7)
	{
		return 0;
	}
 
	/* Unlock the Flash to enable the flash control register access *************/
	HAL_FLASH_Unlock();
 
	if (erase)
	{
		/* Erase the user Flash area*/
 
		/* Fill EraseInit structure*/
		EraseInitStruct.TypeErase = FLASH_TYPEERASE_SECTORS;
		EraseInitStruct.Sector = StartSector;
		EraseInitStruct.NbSectors = nbSector;
		EraseInitStruct.Banks = bank;
		EraseInitStruct.VoltageRange = FLASH_VOLTAGE_RANGE_3;
 
		if (HAL_FLASHEx_Erase(&EraseInitStruct, &SECTORError) != HAL_OK)
		{
			/*Error occurred while page erase.*/
			return HAL_FLASH_GetError ();
		}
	}
 
	/* Program the user Flash area word by word*/
	while (size > 0)
	{
		if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, StartAddress, Data) == HAL_OK)
		{
			StartAddress += 32;
			Data += 8;
			size -= 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 StartAddress;
}
 
/**
  * @brief  Read data from the flash memory
  * @param [in]  StartAddress is the address where you want
  * to start Reading from.
  * @param [out] RxBuf is a buffer were read data will be placed.
  * Make sure it can contain at least size bytes of data.
  * @param [in]  Size is the number of 32-bytes data to read.
  *
  * @retval None
  */
 
void Flash_Read_Data_32 (uint32_t StartAddress, uint32_t *RxBuf, uint32_t size) // Size en 32octet
{
	for(int i=size; i>0 ; i--)
	{
 
		*RxBuf = *(__IO uint32_t *)StartAddress;
		StartAddress += 4;
		RxBuf ++;
 
	}
}

However, as soon as I flash my code, an apparently random number of 0s are written in the flash sector where I wrote during last execution. The blocks of 0s are all the same size though, and appear periodically every 0x200 bytes (at 0x08xxx000, 0x08xxx200, 0x08xxx400, 0x08xxx600, etc... - see attachments). The rest of the data I wrote are still here, and other sectors aren't affected.

Any idea what could cause this ? I tried to use watchpoint to see when this could happen, but without any success. Any help will be greatly appreciated.

I'm using STM32CubeIDE to flash my code and am using a NUCLEO-H755ZI-Q demo board to test my code.

Thank you and have a nice day !

QL

5 REPLIES 5
QLeco.1
Associate II

After further testing, it seems that the problem starts appearing not after writing to the flash and flashing the code again, but when the flash sector is erased and the code is flashed again afterwards.

Also, the size of the blocks of 0s seems to be influenced by the FLASH_VOLTAGE_RANGE value used when erasing the flash. The bigger the number, the bigger the blocks, but their size still vary each time I flash my code on my board.

Any help would still be appreciated.

Thanks,

QL

Piranha
Chief II

Don't you see a pattern in the GetSector() function? The whole bloat can be replaced with a simple subtraction and division!

Thanks for that, but it doesn't help solve the problem though :\

>  the size of the blocks of 0s seems to be influenced by the FLASH_VOLTAGE_RANGE value

Try to use only the minimal value (slower, yes). Check that the power to the MCU is stable.

Perhaps dump the memory from the MCU?

Have a Hard Fault Handler set up and reporting useful data.

Could it be sections are unwritten?

You show a bunch of code, but not how it is used/utilized

Units here look mismatched, is the basis 32-byte aligned?

		if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, StartAddress, Data) == HAL_OK)
		{
			StartAddress += 32;
			Data += 8;
			size -= 8;
		} 

What does size count? 32-byte / 256-bit chunks

128KB is 128 * 1024, not 128000

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..