cancel
Showing results for 
Search instead for 
Did you mean: 

Clean jump app to app

HugoSTM32
Associate III

Hello,

WORKING ON : STM32H753

I am looking to implement a jump from one application to another on an STM32H7 (Cortex-M7), so that the new application starts as if the microcontroller had just been reset: MSP initialized, VTOR set, caches (and MPU maybe?) correctly managed, peripherals reset, SysTick and IRQs disabled.

Knowing that my APP1 is a custom bootloader at address 0x08000000 and my APP2 is my main application with lots of peripherals, timers, DMA, etc. at address 0x08020000.

I tried many sequences to make a jump without crashing.

My jump from APP2 (app) to APP1 (bootloader) seems to work without bugs: 

		//disable interrupts
	    __disable_irq();

	    //disable Systick
	    SysTick->CTRL = 0;
	    SysTick->LOAD = 0;
	    SysTick->VAL  = 0;

	    //deinit
	    HAL_RCC_DeInit();
	    HAL_DeInit();

//	    __enable_irq();

	    // vide cache
	    SCB_DisableICache();
	    SCB_DisableDCache();

	    __DSB();
	    __ISB();

		// je définis ma table des vecteurs au début de mon IAP donc à IAP_ADRESS (0x08000000), avec les cortex M7 SCB est un ptr vers la struc SCB_type qui contient notamment VTOR
		SCB->VTOR = IAP_ADDRESS;          // table vecteurs IAP

		// le premier élement de la table des vecteur est le MSP (Main stack pointer) on doit l'initialiser au début du VTOR OFFSET 0
		__set_MSP(*(__IO uint32_t*)IAP_ADDRESS); // MSP correct
		// on récupère l'addresse de la fonction de ResetHandler qui est le 2eme élement du VTOR OFFSET 4
		JumpAddress = *(__IO uint32_t*)(IAP_ADDRESS + 4);
		// JumpToIAP appelle la fonction qui se trouve à l'addresse du ResetHandler
		JumpToIAP = (pFunction)JumpAddress;

		__enable_irq();

		__DSB();
		__ISB();

		// on appelle la fonction resetHandler pour basculer vers l'IAP
		JumpToIAP();

My jump from APP1 (bootloader) to APP2 (app) seems to work without bugs but i only if I put it in comments :

(i dont know why?)

 

//	SCB_DisableDCache();
//	SCB_DisableICache();

:

	//disable interrupts
    __disable_irq();

    //disable Systick
    SysTick->CTRL = 0;
    SysTick->LOAD = 0;
    SysTick->VAL  = 0;

    //deinit
    // on désactive toutes les horloges pour éviter d'utiliser la config d'horloge de l'app (Peut etre mis en commentaire si pas dérangeant pour améliorer la rapidité)
    HAL_RCC_DeInit();
    // on désactive touts les périphériques (UART,timer, GPIO etc) HAL pour éviter d'utiliser la config de l'app (Peut etre mis en commentaire si pas dérangeant pour améliorer la rapidité)
    HAL_DeInit();


//    // vide cache
//	SCB_DisableDCache();
//	SCB_DisableICache();


	// je définis ma table des vecteurs au début de mon IAP donc à IAP_ADRESS (0x08000000), avec les cortex M7 SCB est un ptr vers la struc SCB_type qui contient notamment VTOR
	SCB->VTOR = APPLICATION_ADDRESS;          // table vecteurs IAP
	// le premier élement de la table des vecteur est le MSP (Main stack pointer) on doit l'initialiser au début du VTOR OFFSET 0
	__set_MSP(*(__IO uint32_t*)APPLICATION_ADDRESS); // MSP correct
	// on récupère l'addresse de la fonction de ResetHandler qui est le 2eme élement du VTOR OFFSET 4
	JumpAddress = *(__IO uint32_t*)(APPLICATION_ADDRESS + 4);
	// JumpToIAP appelle la fonction qui se trouve à l'addresse du ResetHandler
	JumpToApplication = (pFunction)JumpAddress;
	// on appelle la fonction resetHandler pour basculer vers l'IAP

	__enable_irq();

    __DSB();
    __ISB();

	JumpToApplication();

I am looking for a robust method that simulates a complete reset: all devices reset to their initial state, caches and MPU correctly configured, allowing APP 1 or 2 to start normally as a single program without using a system reset.

1 ACCEPTED SOLUTION

Accepted Solutions
HugoSTM32
Associate III

Ok yes,

Here is the explanation: the issue comes from a compiler optimization problem related to the CMSIS code in core_cm7.h.
The SCB_DisableDCache function uses local variables that the compiler may optimize away at higher optimization levels (O1/O2/O3), which breaks the cache clean/invalidate loops.

/**
  \brief   Disable D-Cache
  \details Turns off D-Cache
  */
__STATIC_FORCEINLINE void SCB_DisableDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     uint32_t ccsidr;
     uint32_t sets;
     uint32_t ways;

    SCB->CSSELR = 0U;                       /* select Level 1 data cache */
    __DSB();

    SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk;  /* disable D-Cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean & invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
                       ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

More details and the fix are described here :
https://community.st.com/t5/stm32-mcus-embedded-software/problems-using-the-cache-and-scb-disabledcache-in-bootloader/m-p/154741

View solution in original post

3 REPLIES 3
TDK
Super User

Are DCACHE and ICACHE enabled? If not, don't disable them.

You will need to systematically de-initialize peripherals that are initialized.

You should enable interrupts before jumping. If interrupts are still firing, you did not de-initialize things.

Generic jump code is here and will do 99% of this for you.

How to jump to system bootloader from application ... - STMicroelectronics Community

 

Don't jump within an interrupt, or within a task.

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

Two standard suggestions:

1. Go through reset every time you want to run a new piece of software. It is much easier and more reliable than all those "deinits".

2. Set the optimzation level to anything above the default -O0; otherwise the code may not work due to MSP-based addressing of locals.

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

Ok yes,

Here is the explanation: the issue comes from a compiler optimization problem related to the CMSIS code in core_cm7.h.
The SCB_DisableDCache function uses local variables that the compiler may optimize away at higher optimization levels (O1/O2/O3), which breaks the cache clean/invalidate loops.

/**
  \brief   Disable D-Cache
  \details Turns off D-Cache
  */
__STATIC_FORCEINLINE void SCB_DisableDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
     uint32_t ccsidr;
     uint32_t sets;
     uint32_t ways;

    SCB->CSSELR = 0U;                       /* select Level 1 data cache */
    __DSB();

    SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk;  /* disable D-Cache */
    __DSB();

    ccsidr = SCB->CCSIDR;

                                            /* clean & invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCCISW = (((sets << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
                       ((ways << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);

    __DSB();
    __ISB();
  #endif
}

More details and the fix are described here :
https://community.st.com/t5/stm32-mcus-embedded-software/problems-using-the-cache-and-scb-disabledcache-in-bootloader/m-p/154741