cancel
Showing results for 
Search instead for 
Did you mean: 

Erasing flash during RTOS task execution on STM32F4

SGasp.1
Senior

Hi ..

I am using this function to erase some sectors on the flash

bool FLASH_EraseSectors(uint32_t starting_sector , uint8_t number_of_sectors)
{
	FLASH_EraseInitTypeDef erase_init;
	uint32_t page_error;
 
    /* Erase the user Flash area */
	erase_init.Banks        = FLASH_BANK_1;
	erase_init.TypeErase   	= FLASH_TYPEERASE_SECTORS;
	erase_init.NbSectors 	= number_of_sectors;
	erase_init.Sector     	= starting_sector;
	erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3;
 
	/* Unlock the Flash to enable the flash control register access *************/
	FLASH_Unlock();
 
	if (HAL_FLASHEx_Erase(&erase_init, &page_error) != HAL_OK)
	{
		FLASH_Lock();
		return false;
	}
	if (HAL_FLASHEx_Erase(&erase_init, &page_error) == HAL_OK)
	{
		FLASH_Lock();
		return true;
	}
 
}

I would like to erase some sectors without breaking the 2 tasks running...

The point is that it seems to destroy the tasks...

Is there a safe way to delete the sectors in flash during a task execution in FREERTOS ?

Thanks a lot

31 REPLIES 31

Hi Aharm.... Thanks for your answer...

The idea it is the same ..

I am using sector 1 and 2 for bootloader.. .and I want to erase the sector starting from number 3..

I don't understand why the following code it doesn't work..

  __disable_irq();
  while (FLASH_EraseSectors(2 ,1) == false)
  {
 
  }
  __enable_irq();

where

bool FLASH_EraseSectors(uint32_t starting_sector , uint8_t number_of_sectors)
{
	FLASH_EraseInitTypeDef erase_init;
	uint32_t page_error;
 
    /* Erase the user Flash area */
	erase_init.Banks        = FLASH_BANK_1;
	erase_init.TypeErase   	= FLASH_TYPEERASE_SECTORS;
	erase_init.NbSectors 	= number_of_sectors;
	erase_init.Sector     	= starting_sector;
	erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3;
 
	/* Unlock the Flash to enable the flash control register access *************/
	FLASH_Unlock();
 
	if (HAL_FLASHEx_Erase(&erase_init, &page_error) != HAL_OK)
	{
		FLASH_Lock();
		return false;
	}
	if (HAL_FLASHEx_Erase(&erase_init, &page_error) == HAL_OK)
	{
		FLASH_Lock();
		return true;
	}
 
}

In the STm32F7 micro instead I did it the same just calling once the function...

Do you have any idea ?

Thanks

Don't know much about using the HAL function, just can give you tips. Make sure that your code is small enough so that any part of it does not end up in the sector 2(the one you are erasing). Try erasing the last sector and see if that works.

Hi AHarm... I was able to make the erase and writing functions with the following functions

bool FLASH_EraseSectors(uint32_t starting_sector , uint8_t number_of_sectors)
{
	FLASH_EraseInitTypeDef erase_init;
	uint32_t page_error;
 
    /* Erase the user Flash area */
	erase_init.Banks        = FLASH_BANK_1;
	erase_init.TypeErase   	= FLASH_TYPEERASE_SECTORS;
	erase_init.NbSectors 	= number_of_sectors;
	erase_init.Sector     	= starting_sector;
	erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3;
 
	/* Unlock the Flash to enable the flash control register access *************/
	FLASH_Unlock();
 
	if (HAL_FLASHEx_Erase(&erase_init, &page_error) != HAL_OK)
	{
		FLASH_Lock();
		return false;
	}
	if (HAL_FLASHEx_Erase(&erase_init, &page_error) == HAL_OK)
	{
		FLASH_Lock();
		return true;
	}
 
}
 
bool FLASH_WriteSingleByte(uint32_t flashAddress, uint64_t Data)
{
 
	FLASH_Unlock();
 
	/* Program the user Flash area word by word */
	if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE, (uint32_t) flashAddress, Data) != HAL_OK)
	{
		FLASH_Lock();
		return false;
	}
 
	return true;
}

So now I am sure that the functions work...

But when I try to flash some bytes while the communication is running it doesn't work .. .

I receive data every 200 ms but I have a timer doing some operations every 1 ms ..

maybe the flash is interrupted by this problem ?

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */
 
  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM4) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */
  if (htim->Instance == TIM4) {
	  applica_Timer1ms();
	  uart_Timer1ms();
	  com_Timer1ms();
  }
  /* USER CODE END Callback 1 */
}

Should I suspend any interrupts and any timers while I flash some bytes ?

Thanks a lot

Manny
Associate III

Hi @SGasp.1​ ,

The stm32f4 support RWW(Read-while-write), see RWW section in https://www.st.com/resource/en/reference_manual/DM00031020-.pdf.

It support this feature in a specific condition, In your case you are trying to read(read-and-execute user code) while write(erasing a sector) at the same time.

Look into the datasheet and reference manual of the mcu you are using related to RWW.

If you cannot do both(execute code and erase sector) then you can suspend all task (and disable any interrupts you are using) when performing the erase, and see if that works for you.

hop this helps.

SGasp.1
Senior

Hi AHarm... I discovered that the following code is working

			__disable_irq();
			while (FlashWriteData(address_to_write, &HEX_array[0], bytes_to_flash/2) == -1)
					{
 
					}
 
			__enable_irq();

I am stopping any interrupt while I write the flash.. The point is how much does it take to flash 8 bytes for example ?

I am receiving the data to flash from a uart ..

I can send data to this board for example every 500ms ...

500ms are enough to flash the data ?

hi AHarm...

Thanks for your answer

The following code is working

	__disable_irq();
	while (FlashWriteData(address_to_write, &HEX_array[0], bytes_to_flash/2) == -1)
	{
 
	}
 
      __enable_irq();

I want to flash 8 bytes at time... I would like to understand how much does it take to flash 8 bytes,,,

Since I am blocking any interrupts I am stopping to receive the data to flash coming from an uart communication..

If I send data every 300 ms... Can I disable the interrupts and flash the data (8 bytes ) without loosing any data coming from the UART?

Thanks a lot

Simone

Manny
Associate III

@SGasp.1​ , flashing 8 bytes will not take much time, the time taker is the sector erase process that need to be done before writing any byte in that sector.

For your uart data, if you disable interrupts, the uart receive interrupts will also disable and thus you will loss data as uart can only hold a single byte at a time, case is different if you are using DMA(I don't have experience with DMA). You can implement a strategy to ensure that no data is loss on the communication side. For example you wait for an acknowledgment for the mcu before sending the next byte of data to be programed.

See the DFU(Device firmware update) protocol application note to use as a reference to design your own bootloader protocol.

link:

https://www.st.com/resource/en/application_note/cd00264342-usart-protocol-used-in-the-stm32-bootloader-stmicroelectronics.pdf

SGasp.1
Senior

Thanks AHarm.. your help was very useful... Not i am able to flash the bytes coming from the uart..

it is a hex file... you can see it in the attachments..

Just a question ..

Should I have to write the bytes in the flash starting from line 2 of the file ?

Can I skip it the first line ?

Can I also skip line 1726?

Thanks a lot again for your support

simosilva
Senior

Hi @SGasp.1​ ,

your functions look fine just fine, the thing is that every sector erase is atomic and cannot be interrupted and so it's the write.

To not block the write operation and let te UART communication work every time a packet is received, you can add a semaphore or a simple flag.

here some pseudocodes.

Uart IT Callback:

StopWriteFlag = TRUE;
MessageReceived =TRUE;

UART task:

if(MessageReceived == TRUE)
{
    ParseReceivedMessage();
   
    StopWriteFlag = FALSE;
    MessageReceived =FALSE;
}

write task:

if (StopWriteFlag != TRUE)
{
    __disable_irq();
    while (FlashWriteData(address_to_write, &HEX_array[0], bytes_to_flash/2) == -1)
    {
     }
     __enable_irq();
}

0693W00000FDzveQAD.jpgI am not sure, but I can share some info about the hex file, hex file a text(ASCII) file that have information about binary data. It can and is used for programming(your mcu e.g). You can should take a look at the generated .bin file, in my opinion it is more clear. You just need to know where the user code memory is, in the mcu.

As .bin file is a binary file, simple text editor would not be a good option for viewing, use a hex viewer softer(I use FlexHex).

See the attached file, it is a bliki code for the stm32f103(blue pill), note that the file start from address 0x00000000, this data is to be programmed at the address 0x08000000 in the blue pill. Also see the attached stm32cubeProgrammer view of the code when inside the mcu. The stm32cubeprorammer is shows the address little differently. The STVP would have made it clear but currently I don't have a ST-Link at the movement.

0693W00000FDzviQAD.jpg