Skip to main content
Associate III
November 28, 2025
Solved

Clean jump app to app

  • November 28, 2025
  • 4 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.

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

4 replies

TDK
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.

"If you feel a post has answered your question, please click ""Accept as Solution""."
gbm
Principal
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.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
HugoSTM32AuthorBest answer
Associate III
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

April 10, 2026

If your device keeps jumping between apps, it’s usually caused by background apps, notifications, or a software glitch. First, close all running apps and restart your device. Then check for any recently installed apps that might be causing conflicts and uninstall them if needed. https://perthbondcleaning.com.au/

You should also clear cache (from settings), disable unnecessary notifications, and update your system software. If the issue continues, check touchscreen sensitivity or run the device in safe mode to identify the problematic app.