Skip to main content
Graduate
November 28, 2025
Solved

Clean jump app to app

  • November 28, 2025
  • 3 replies
  • 218 views

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.

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

    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

    3 replies

    Super User
    November 29, 2025

    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.

    Graduate
    November 29, 2025

    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.

    HugoSTM32AuthorAnswer
    Graduate
    November 29, 2025

    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