2025-11-28 2:44 PM - last edited on 2025-11-29 3:47 AM by Andrew Neil
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.
Solved! Go to Solution.
2025-11-29 2:46 AM - last edited on 2025-11-29 3:47 AM by Andrew Neil
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
2025-11-28 4:12 PM - edited 2025-11-28 4:12 PM
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.
2025-11-28 10:58 PM
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.
2025-11-29 2:46 AM - last edited on 2025-11-29 3:47 AM by Andrew Neil
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