Skip to main content
Graduate II
October 7, 2021
Solved

Erasing flash during RTOS task execution on STM32F4

  • October 7, 2021
  • 12 replies
  • 8148 views

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

    This topic has been closed for replies.
    Best answer by Manny

    @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

    12 replies

    Visitor II
    October 7, 2021

    Hello @SGasp.1​ ,

    As flash erasing is a blocking and time intensive task, it should on a lower priority task.

    Usually, if the erasure is not needed immediately, it is to be performed page per page within a lower task priority.

    Otherwise, if you have activated a watchdog, don't forget to feed it between page erasures or it might trigger a reset depending on the flash range to be erased and how much time it would take.

    I hope this helps you.

    BeST Regards,

    Walid

    Visitor II
    January 5, 2024

    If it's blocking then how can this FLASH_WaitForLastOperation run after FLASH_Program_Word?

    SGasp.1Author
    Graduate II
    October 7, 2021

    Thanks Walid..

    But it is enough to call it one or maybe inside a loop in this way ?

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

    Thanks a lot

    Visitor II
    October 7, 2021

    What do you mean by 'destroy the tasks'?

    SGasp.1Author
    Graduate II
    October 7, 2021

    Hi Aharm.. thannks for your answer..

    I mean can I call these instructions inside a task

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

    without blocking a Higher priority task which is responsible for the communication with another board?

    Thanks

    Visitor II
    October 7, 2021

    The FreeRtos Scheduler uses ISR to perform its task switching, if you disable the interrupts globally, the timer(used by rtos) interrupt will also stop, thus no task switching.

    SGasp.1Author
    Graduate II
    October 7, 2021

    Ok so If I am able to enter in this task where is located the following code

     while (FLASH_EraseSectors(2 ,1) == false)
     {
     
     }

    I should be able to erase the sectors..

    because I tried without inside a while loop but I wasn't able to delete the sectors calling it just once..

    Is it correct ?

    Thanks for your huge support ...

    Simone

    Graduate II
    October 7, 2021

    Other access to FLASH will stall the processor, for 128KB sectors don't they spec 2seconds worst case.

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

    SGasp.1Author
    Graduate II
    October 7, 2021

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

    What do you mean Tesla ?

    Do you have an example

    Thanks

    Visitor II
    October 7, 2021

    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

    Super User
    October 7, 2021

    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.1Author
    Graduate II
    October 7, 2021

    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();
    }

    Super User
    October 8, 2021

    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.1Author
    Graduate II
    October 8, 2021

    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?

    SGasp.1Author
    Graduate II
    October 16, 2021

    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 ?