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

C​ode footprint needs to run entirely from RAM, or different Flash BANK ..

What do you mean Tesla ?

Do you have an example

Thanks

The code is the following

  osThreadDef(defaultTask, StartDefaultTask, osPriorityLow, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
 
  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  osThreadDef(unoTask, StartUnoTask, osPriorityNormal, 0, 128);
  taskUnoTaskHandle = osThreadCreate(osThread(unoTask), NULL);
 
 
void StartUnoTask(void const * argument)
{
	com_Init();
	for(;;){
		com_Task();
        taskYIELD();
	}
}
 
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN 5 */
	applica_Init();
  /* Infinite loop */
	for(;;)
	{
		applica_Task();
		taskYIELD();
	}
  /* USER CODE END 5 */
}
 
/* -------------------------------------------------------------------------
    Task app
 -------------------------------------------------------------------------*/
void applica_Task(void)
{
	  __disable_irq();
	  while (FLASH_EraseSectors(2 ,1) == false)
	  {
 
	  }
	  __enable_irq();
}

With this code.. calling the erase of the flash inside the DefaultTask could work ?

He means that you can only run code from RAM while your flash memory is being erased.

The only practical way is to place ALL your code in RAM (VTOR also!).

You can do this by modifying the linker script + startup code, so that your .text section, isr_vector (basically all the compiled instructions), are still *placed* in flash, but *assumed* to be at a RAM memory address.

Note:

Exactly the same happens with your .data section which contains initial values for (non-constant) global variables-- those initial values are *stored* in flash, but the global variables are assumed to be at a RAM address-- your startup script copies the values from flash to ram before you even reach the main function.

You need to aquire a very basic understanding of linker script and startup code, but the modifications itself are not complicated.

Some gotchas:

1) Calling RAM functions from your startup code is slightly more involved because there is likely a big address difference that can no longer be encoded in the immediate form of the branch instruction:

bl SystemInit

becomes:

ldr r0, =SystemInit
blx r0

2) Debugger: breakpoints in RAM are handled differently, which makes it helpful to run to slightly before RAM executation starts because the "copy instructions into RAM" step would overwrite all your breakpoints otherwise leading to frustration. I have a label "Run_Main" for this and tell my debugger to set a breakpoint to "Run_Main" at init (instead of main).

Relevant startup-code snippet:

Run_Main:
  ldr r0, =main
  blx r0

Bob S
Principal

Which F4 CPU are you using?

Some of them support dual-bank flash with read-while-write functionality (can read/execute from one flash bank while writing/erasing the other other bank). For example, the F405 does not support read-while-write so you are out of luck unless you can move all necessary code into RAM. The F427/429 do have dual FLASH Banks and support read-while-write.

SGasp.1
Senior

Hi Bob...

The cpu is STM32F401..

I am developing the bootloader part..

In the bootloader code i want to receive the new flash to update by using the uart and receiving the data from another microcontroller..

The bootloader app is in another address region of the normal app..

Do I need also in this case to move the code in RAM ?

The code is the following

osThreadDef(defaultTask, StartDefaultTask, osPriorityLow, 0, 128);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
 
  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  osThreadDef(unoTask, StartUnoTask, osPriorityNormal, 0, 128);
  taskUnoTaskHandle = osThreadCreate(osThread(unoTask), NULL);
 
 
void StartUnoTask(void const * argument)
{
	com_Init();
	for(;;){
		com_Task();
        taskYIELD();
	}
}
 
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN 5 */
	applica_Init();
  /* Infinite loop */
	for(;;)
	{
		applica_Task();
		taskYIELD();
	}
  /* USER CODE END 5 */
}
 
/* -------------------------------------------------------------------------
    Task app
 -------------------------------------------------------------------------*/
void applica_Task(void)
{
	  __disable_irq();
	  while (FLASH_EraseSectors(2 ,1) == false)
	  {
 
	  }
	  __enable_irq();
}

Bob S
Principal

Why are you using an RTOS in your bootloader? Is it doing lots of other things as well? I've written a bootloader for the F407, dowload new firmware via UART or USB or Ethernet. No RTOS, writes to flash stalling the CPU are OK because each block of firmware is sent and then the other end (the PC) waits for a response before sending the next block of data. Works fine.

If you really really REALLY need an RTOS in the bootloader, then, yeah, you will probably need to fit it in RAM. Or as @Community member​ suggested in this thread https://community.st.com/s/question/0D73W000001MQn7/detail?s1oid=00Db0000000YtG6&s1nid=0DB0X000000DYbd - if you can modify your design and add an external SPI FLASH to store the data, then disable the RTOS just during the "copy yo main FLASH" part of the operation.

SGasp.1
Senior

Hi Bob.. Ok makes sense what you are saying.. I could disable the rtos and move everything the communication task in the main while loop..

The point is doing that can I erase the flash with the routine that I wrote here ?

Do I need to call it just once for erasing the flash or do I need to call it inside a loop?

The sector that you are trying to ease should not overlap with the code that is executing at that time. e.g suppose that your code reside in the sector 1,2 and 3, and you want to ease sector 12 for some reason you can do this with no problem.

I have done a project where I used the sector 12 for user data storage and it works.

But it does not used any rtos and I did it bare metal. You have to do some experiments to see if this works for you.

Manny
Associate III

It should work, are you performing any other flash operation on any of the other tasks? Try stopping(suspending) the other task when you are erasing a sector and see if that works in one go.