2025-11-25 6:43 AM - edited 2025-11-25 7:04 AM
Hello,
Im beginner,
STM32H753 on the EVAL BOARD,
Objective:
At startup, the IAP is ignored with a condition on the jumpToIAPFlag flag that checks whether the reset is related to POWER ON or NRST (hardware button), which would therefore be a normal startup. The flag is then initialized to 0 and we jump directly to APP.
Once in my APP, I want to be able to return to the IAP (by reading a bit on frames). At first, I did the same as for jumping from IAP to APP, but in the end, a soft reset should be enough for the jumpToIAPFlag to remain at 1 and not pass through the POWER ON or NRST reset conditions, and therefore my IAP menu should open.
Everything related to frame logic, etc. is functional, but my APP to IAP no longer works since I started using a variable (jumpToIAPFlag) that is common to both my IAP and my APP.
The result is that when I send the frame to open my IAP, there is indeed a reset, but my IAP does not launch. Instead, my APP launches as if my jumpToIAPFlag value had not been saved in memory.
I added a small shared memory area like this (in both FLASH.ld): IAP :
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 508K
/* Mémoire partager en IAP et APP */
RAM_EXEC_NOINIT (xrw) : ORIGIN = 0x2407F000, LENGTH = 4K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
SECTIONS
{
......
.noinit (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.noinit))
} > RAM_EXEC_NOINIT
}APP :
MEMORY
{
BANK1_FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 896K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 508K
/* Mémoire partager en IAP et APP */
RAM_EXEC_NOINIT (xrw) : ORIGIN = 0x2407F000, LENGTH = 4K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
SECTIONS
{
......
.noinit (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.noinit))
} > RAM_EXEC_NOINIT
}
and then I declared the flag in both projects like this :
__attribute__((section(".noinit"))) volatile uint8_t jumpToIAPFlag;I then trigger the reset + flag = 1 here (commenting out the old method with a jump) :
void processMaintenanceS2C(void)
{
// //pFunction permet de pointer vers une fonction
// typedef void (*pFunction)(void);
// pFunction JumpToIAP;
// uint32_t JumpAddress;
if ((FrameS2C[1] & 0x08) == 0x08)
{
// Si bit 3 de l'octet 1 vaut 1 alors jump to IAP
// on signale qu'il y a une demande d'IAP
jumpToIAPFlag = 1;
// Reset logiciel pour relancer le micro et démarrer IAP
NVIC_SystemReset();
// // on désactive toutes les interruptions globale pour éviter les crash si une interruption arrive pendant le jump (FORTEMENT RECOMMANDE)
// __disable_irq();
// // on désactive la Data cache et Instruction cache pour éviter les données résiduelles de l'app
// SCB_DisableICache(); // Laisser disable si jamais il reste une instruction en cache ca pourrait faire crash l'IAP
// SCB_DisableDCache(); // Laisser disable même si non critique, mais peu de gain de rapidité
// // 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();
//
// // 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;
// // on appelle la fonction resetHandler pour basculer vers l'IAP
// JumpToIAP();
}
UART_maintenanceFrame();
}et ensuite le main.c de l'IAP :
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "menu.h"
#include "stdbool.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define IAP_ADDRESS (uint32_t)0x08000000
#define Conf 0
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
__attribute__((section(".noinit"))) volatile uint8_t jumpToIAPFlag;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MPU_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
bool ReadSwitch(uint8_t switchNum);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MPU Configuration--------------------------------------------------------*/
MPU_Config();
/* Enable the CPU Cache */
/* Enable I-Cache---------------------------------------------------------*/
SCB_EnableICache();
/* Enable D-Cache---------------------------------------------------------*/
SCB_EnableDCache();
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
SCB->VTOR = IAP_ADDRESS;
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
// au premier démarrage il faut forcer le flag jumpToIAPFlag à 0 pour jump à l'app
// on regarde dans le registre CSR qu contient le flag pour savoir comment le dernier reset à été déclenché
// on compare avec les bits des reset par NRST hardware et POWER ON et on laisse passer le reset via soft (swap IAP - APP)
if (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF)) {
jumpToIAPFlag = 0;
}
// on nettoie les flag de reset
RCC->RSR |= RCC_RSR_RMVF;
// meme chose avec macro HAL
//__HAL_RCC_CLEAR_RESET_FLAGS();
if (jumpToIAPFlag == 1)
{
#if Conf == 1
HAL_UART_DeInit(&huart1);
uint8_t baudRateConfig = (ReadSwitch(1) << 0 | ReadSwitch(2) << 1);
// uint8_t autreConfig = (ReadSwitch(3) << 0 | ReadSwitch (4) << 1);
switch (baudRateConfig)
{
case 0x00:
huart1.Init.BaudRate = 115200;
break;
case 0x01:
huart1.Init.BaudRate = 56000;
break;
case 0x02:
huart1.Init.BaudRate = 38400;
break;
case 0x03:
huart1.Init.BaudRate = 9600;
break;
}
if (HAL_UART_Init(&huart1) != HAL_OK) {
Error_Handler();
}
#endif
/* Initialise Flash */
FLASH_If_Init();
/* Display main menu */
Main_Menu ();
}
else
{
//si reset matériel démarrage classique vers APP
jumpToAPP();
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
|RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief USART1 Initialization Function
* None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
/**
* @brief GPIO Initialization Function
* None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pins : Conf1_Pin Conf2_Pin */
GPIO_InitStruct.Pin = Conf1_Pin|Conf2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
bool ReadSwitch(uint8_t switchNum){
switch(switchNum){
case 1: return (HAL_GPIO_ReadPin(Conf1_GPIO_Port, Conf1_Pin) == GPIO_PIN_SET);
case 2: return (HAL_GPIO_ReadPin(Conf2_GPIO_Port, Conf2_Pin) == GPIO_PIN_SET);
// case 3: return (HAL_GPIO_ReadPin(Conf3_GPIO_Port, Conf3_Pin) == GPIO_PIN_SET);
// case 4: return (HAL_GPIO_ReadPin(Conf4_GPIO_Port, Conf4_Pin) == GPIO_PIN_SET);
default: return false;
}
}
/* USER CODE END 4 */
/* MPU Configuration */
void MPU_Config(void)
{
MPU_Region_InitTypeDef MPU_InitStruct = {0};
/* Disables the MPU */
HAL_MPU_Disable();
/** Initializes and configures the Region and the memory to be protected
*/
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.BaseAddress = 0x0;
MPU_InitStruct.Size = MPU_REGION_SIZE_4GB;
MPU_InitStruct.SubRegionDisable = 0x87;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.AccessPermission = MPU_REGION_NO_ACCESS;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Enables the MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* file: pointer to the source file name
* line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
To conclude:
I want that when I start up normally (power on), the IAP jumps directly to the app, but from the app I can switch back to the IAP. The only solution I can see is to put a flag in a common memory area that does not get erased so that both the IAP and APP projects can use this flag, but I don't know how to do this and I don't think what I've done is the right way to do it.
Thank you
2025-11-25 7:25 AM
Hello @HugoSTM32
You can add debugging statements to verify the value of jumpToIAPFlag before and after the reset. For example:
printf("jumpToIAPFlag before reset: %d\n", jumpToIAPFlag);
This will help confirm whether the flag is being correctly retained across resets.
2025-11-26 1:09 AM - edited 2025-11-26 1:14 AM
Ok here all the prints :
In APP project when IAP command is received :
if ((FrameS2C[1] & 0x08) == 0x08)
{
// Si bit 3 de l'octet 1 vaut 1 alors jump to IAP
// on signale qu'il y a une demande d'IAP
jumpToIAPFlag = 1;
printf("\r\njumpToIAPFlag in APP project before NVIC_SystemReset(); = %d\r\n", jumpToIAPFlag);
// Reset logiciel pour relancer le micro et démarrer IAP
NVIC_SystemReset();In the IAP :
/* USER CODE BEGIN 2 */
// au premier démarrage il faut forcer le flag jumpToIAPFlag à 0 pour jump à l'app
// on regarde dans le registre CSR qu contient le flag pour savoir comment le dernier reset à été déclenché
// on compare avec les bits des reset par NRST hardware et POWER ON et on laisse passer le reset via soft (swap IAP - APP)
printf("\r\n jumpToIAPFlag in IAP project BEFORE reset flag check = %d\r\n", jumpToIAPFlag);
if (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF)) {
printf("\r\nif (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF) = IN \r\n", jumpToIAPFlag);
jumpToIAPFlag = 0;
}
// on nettoie les flag de reset
RCC->RSR |= RCC_RSR_RMVF;
// meme chose avec macro HAL
//__HAL_RCC_CLEAR_RESET_FLAGS();
printf("\r\n jumpToIAPFlag in IAP project AFTER reset flag check = %d\r\n", jumpToIAPFlag);
if (jumpToIAPFlag == 1)
{Results :
jumpToIAPFlag in APP project before NVIC_SystemReset(); = 1
jumpToIAPFlag in IAP project BEFORE reset flag check = 111
if (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF) = IN
jumpToIAPFlag in IAP project AFTER reset flag check = 0
So the flag is set to 1 when I receive the frame for IAP and the reset is performed correctly.
Problem 1: the flag value is not saved (“jumpToIAPFlag in IAP project BEFORE reset flag check = 111”)
Problem 2: I performed a software reset, but I still enter the loop conditioned on the POWER ON and NRST reset flags ("if (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF) = IN), so the flag is set to 0 --> I go straight back to my APP and my IAP manual is not displayed.
So I already think that my way of declaring a shared memory area that is not cleared after a reset is wrong here :
.noinit (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.noinit))
} > RAM_EXEC_NOINIT __attribute__((section(".noinit"))) volatile uint8_t jumpToIAPFlag;And for problem 2, I don't see why it doesn't work. I check the POWER ON and NRST reset flags carefully, so why do I enter the if statement with a software reset?
2025-11-26 3:29 AM
Okay, I changed the logic. I'm just using the flag in the IAP project and setting the flag directly to 1.
In the APP project, I no longer use the flag and I do a classic jump without doing a software reset
But I'm still curious about the future. If anyone has a solution to problem 1: creating a common memory area that can be used for two projects, and problem 2: why, after a software reset, I enter the if if (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF)) {
New logic to skip IAP at start, but enter in IAP from APP :
IAP :
/* USER CODE BEGIN 2 */
// au premier démarrage il faut forcer le flag jumpToIAPFlag à 0 pour jump à l'app
// on regarde dans le registre CSR qu contient le flag pour savoir comment le dernier reset à été déclenché
// on compare avec les bits des reset par NRST hardware et POWER ON et on laisse passer le reset via soft (swap IAP - APP)
uint8_t jumpToIAPFlag = 1;
printf("\r\n jumpToIAPFlag in IAP project BEFORE reset flag check = %d\r\n", jumpToIAPFlag);
if (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF)) {
printf("\r\nif (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF) = IN \r\n");
jumpToIAPFlag = 0;
}
// on nettoie les flag de reset
RCC->RSR |= RCC_RSR_RMVF;
// meme chose avec macro HAL
//__HAL_RCC_CLEAR_RESET_FLAGS();
printf("\r\n jumpToIAPFlag in IAP project AFTER reset flag check = %d\r\n", jumpToIAPFlag);
if (jumpToIAPFlag == 1)
{
APP :
//pFunction permet de pointer vers une fonction
typedef void (*pFunction)(void);
pFunction JumpToIAP;
uint32_t JumpAddress;
if ((FrameS2C[1] & 0x08) == 0x08)
{
// Si bit 3 de l'octet 1 vaut 1 alors jump to IAP
// // on signale qu'il y a une demande d'IAP
// jumpToIAPFlag = 1;
// printf("\r\njumpToIAPFlag in APP project before NVIC_SystemReset(); = %d\r\n", jumpToIAPFlag);
// // Reset logiciel pour relancer le micro et démarrer IAP
// NVIC_SystemReset();
// on désactive toutes les interruptions globale pour éviter les crash si une interruption arrive pendant le jump (FORTEMENT RECOMMANDE)
__disable_irq();
// on désactive la Data cache et Instruction cache pour éviter les données résiduelles de l'app
SCB_DisableICache(); // Laisser disable si jamais il reste une instruction en cache ca pourrait faire crash l'IAP
SCB_DisableDCache(); // Laisser disable même si non critique, mais peu de gain de rapidité
// 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();
// 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;
// on appelle la fonction resetHandler pour basculer vers l'IAP
JumpToIAP();
2025-11-26 3:51 AM
With "IAP" you mean a custom bootloader? In the same flash as the application?
If yes, maybe you forgot to add the shared no-init RAM to the bootloader's linker script, or the location attribute in the bootloader source code?
I'm using a H723 / H733 with exactly the stuff described above, incl a shared bootloader / app variable in some no-init DTCM area, works like a charm. To make it a little safer I'm using an uint32_t and check for a specific word (but in my case to stay in bootloader when jumping from app).
2025-11-26 4:24 AM
Yes, a custom bootloader in the same flash sector 0 of bank1, and my app starts at sector 1 of bank1.
In my case, it's normal that the flag in RAM doesn't retain its value with a software reset, but I tried again with a jump instead of a software reset and it crashed my program.
I think it's because I don't know how to properly declare a new section in memory (the .noinit section).
IAP linker :
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : STM32CubeIDE
**
** Abstract : Linker script for STM32H7 series
** 2048Kbytes FLASH and 1056Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 508K
/* Mémoire partager en IAP et APP */
RAM_EXEC_NOINIT (xrw) : ORIGIN = 0x2407F000, LENGTH = 4K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
/* Constant data goes into FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
.ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >FLASH
.ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >FLASH
.preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >FLASH
.init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >FLASH
.fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM_D1 AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM_D1
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM_D1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
.noinit (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.noinit))
} > RAM_EXEC_NOINIT
}
APP linker :
/*
******************************************************************************
**
** File : LinkerScript.ld
**
** Author : STM32CubeIDE
**
** Abstract : Linker script for STM32H7 series
** 2048Kbytes BANK1_FLASH and 1056Kbytes RAM
**
** Set heap size, stack size and stack location according
** to application requirements.
**
** Set memory bank area and size if external memory is used.
**
** Target : STMicroelectronics STM32
**
** Distribution: The file is distributed as is, without any warranty
** of any kind.
**
*****************************************************************************
** @attention
**
** Copyright (c) 2025 STMicroelectronics.
** All rights reserved.
**
** This software is licensed under terms that can be found in the LICENSE file
** in the root directory of this software component.
** If no LICENSE file comes with this software, it is provided AS-IS.
**
****************************************************************************
*/
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM_D1) + LENGTH(RAM_D1); /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
BANK1_FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 896K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 508K
/* Mémoire partager en IAP et APP */
RAM_EXEC_NOINIT (xrw) : ORIGIN = 0x2407F000, LENGTH = 4K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into BANK1_FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >BANK1_FLASH
/* The program code and other data goes into BANK1_FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >BANK1_FLASH
/* Constant data goes into BANK1_FLASH */
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >BANK1_FLASH
.ARM.extab (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >BANK1_FLASH
.ARM (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
__exidx_start = .;
*(.ARM.exidx*)
__exidx_end = .;
} >BANK1_FLASH
.preinit_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} >BANK1_FLASH
.init_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} >BANK1_FLASH
.fini_array (READONLY) : /* The READONLY keyword is only supported in GCC11 and later, remove it if using GCC10 or earlier. */
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} >BANK1_FLASH
/* used by the startup to initialize data */
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
*(.RamFunc) /* .RamFunc sections */
*(.RamFunc*) /* .RamFunc* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end */
} >RAM_D1 AT> BANK1_FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
{
/* This is used by the startup in order to initialize the .bss section */
_sbss = .; /* define a global symbol at bss start */
__bss_start__ = _sbss;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end */
__bss_end__ = _ebss;
} >RAM_D1
/* User_heap_stack section, used to check that there is enough RAM left */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM_D1
/* Remove information from the standard libraries */
/DISCARD/ :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
.ARM.attributes 0 : { *(.ARM.attributes) }
.noinit (NOLOAD) :
{
. = ALIGN(4);
KEEP(*(.noinit))
} > RAM_EXEC_NOINIT
}
i also check in .map in 2 projects and .noinit is in the same address :
.noinit 0x2407f000 0x1
0x2407f000 . = ALIGN (0x4)
*(.noinit)
.noinit 0x2407f000 0x1 ./Core/Src/global_vars.o
0x2407f000 jumpToIAPFlag.noinit 0x2407f000 0x1
0x2407f000 . = ALIGN (0x4)
*(.noinit)
.noinit 0x2407f000 0x1 ./Core/Src/main.o
0x2407f000 jumpToIAPFlag
2025-11-26 6:38 AM
Here's my version, same in BL & APP linker script:
...
/* DTCM: 128 kB
* 0x2000 0000 - 0x2001FFFF
* used as "general" RAM
* no DMA1/2 access, only MDMA memory to memory
*/
DTCM_RAM(xrw) : ORIGIN = 0x20000000, LENGTH = 112K /* DTCM */
DTCM_NOINIT(xrw) : ORIGIN = 0x2001C000, LENGTH = 1K /* DTCM no init */
DTCM_HPST(xrw) : ORIGIN = 0x2001C400, LENGTH = 15K /* DTCM heap & stack */
...
/* DTCM_NOINIT section - no init vars */
.NoInitSection (NOLOAD):
{
. = ALIGN(8);
*(.NoInitSection)
*(.NoInitSection*)
. = ALIGN(8);
} >DTCM_NOINIT
The biggest difference:
I do not use a soft reset to switch to BL, only jumping.
2025-11-27 2:53 AM
Just for the second problem, I now understand why I was still getting into the :
if (RCC->RSR & (RCC_RSR_PORRSTF | RCC_RSR_PINRSTF))This is because when a software reset is triggered, the microcontroller simulates an NRST reset. Here is some print:
After my NVIC_SystemReset();
I read the RSR register and notice that other flags are set to 1, RCC->RSR = 0x01460000
bit 17 : CPU reset
bit 18 : reserved
bit 22 : NRST reset
bit 24 : Soft reset
here in stm32h753xx.h :
/******************** Bit definition for RCC_RSR register *******************/
#define RCC_RSR_RMVF_Pos (16U)
#define RCC_RSR_RMVF_Msk (0x1UL << RCC_RSR_RMVF_Pos) /*!< 0x00010000 */
#define RCC_RSR_RMVF RCC_RSR_RMVF_Msk
#define RCC_RSR_CPURSTF_Pos (17U)
#define RCC_RSR_CPURSTF_Msk (0x1UL << RCC_RSR_CPURSTF_Pos) /*!< 0x00020000 */
#define RCC_RSR_CPURSTF RCC_RSR_CPURSTF_Msk
#define RCC_RSR_D1RSTF_Pos (19U)
#define RCC_RSR_D1RSTF_Msk (0x1UL << RCC_RSR_D1RSTF_Pos) /*!< 0x00080000 */
#define RCC_RSR_D1RSTF RCC_RSR_D1RSTF_Msk
#define RCC_RSR_D2RSTF_Pos (20U)
#define RCC_RSR_D2RSTF_Msk (0x1UL << RCC_RSR_D2RSTF_Pos) /*!< 0x00100000 */
#define RCC_RSR_D2RSTF RCC_RSR_D2RSTF_Msk
#define RCC_RSR_BORRSTF_Pos (21U)
#define RCC_RSR_BORRSTF_Msk (0x1UL << RCC_RSR_BORRSTF_Pos) /*!< 0x00200000 */
#define RCC_RSR_BORRSTF RCC_RSR_BORRSTF_Msk
#define RCC_RSR_PINRSTF_Pos (22U)
#define RCC_RSR_PINRSTF_Msk (0x1UL << RCC_RSR_PINRSTF_Pos) /*!< 0x00400000 */
#define RCC_RSR_PINRSTF RCC_RSR_PINRSTF_Msk
#define RCC_RSR_PORRSTF_Pos (23U)
#define RCC_RSR_PORRSTF_Msk (0x1UL << RCC_RSR_PORRSTF_Pos) /*!< 0x00800000 */
#define RCC_RSR_PORRSTF RCC_RSR_PORRSTF_Msk
#define RCC_RSR_SFTRSTF_Pos (24U)
#define RCC_RSR_SFTRSTF_Msk (0x1UL << RCC_RSR_SFTRSTF_Pos) /*!< 0x01000000 */
#define RCC_RSR_SFTRSTF RCC_RSR_SFTRSTF_Msk
#define RCC_RSR_IWDG1RSTF_Pos (26U)
#define RCC_RSR_IWDG1RSTF_Msk (0x1UL << RCC_RSR_IWDG1RSTF_Pos) /*!< 0x04000000 */
#define RCC_RSR_IWDG1RSTF RCC_RSR_IWDG1RSTF_Msk
#define RCC_RSR_WWDG1RSTF_Pos (28U)
#define RCC_RSR_WWDG1RSTF_Msk (0x1UL << RCC_RSR_WWDG1RSTF_Pos) /*!< 0x10000000 */
#define RCC_RSR_WWDG1RSTF RCC_RSR_WWDG1RSTF_Msk
#define RCC_RSR_LPWRRSTF_Pos (30U)
#define RCC_RSR_LPWRRSTF_Msk (0x1UL << RCC_RSR_LPWRRSTF_Pos) /*!< 0x40000000 */
#define RCC_RSR_LPWRRSTF RCC_RSR_LPWRRSTF_Msk
2025-11-27 3:36 AM
in core_cm7.h :
/**
\brief System Reset
\details Initiates a system reset request to reset the MCU.
*/
__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void)
{
__DSB(); /* Ensure all outstanding memory accesses included
buffered write are completed before reset */
SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) |
(SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */
__DSB(); /* Ensure completion of memory access */
for(;;) /* wait until reset */
{
__NOP();
}
}
Register SCB->AIRCR is described in PM0253: STM32F7 Series and STM32H7 Series Cortex®-M7 processor
programming manual.
There is actually only this one bit SCB_AIRCR_SYSRESETREQ_Msk that can be set to trigger a reset.
So...
find either another way to trigger a "soft reset", or do it like (seemingly) most people: jump to bootloader.
Is this soft reset + check method a common procedure? (I'm coming from the hardware side, learned MUCs on the job...)
2025-11-27 3:46 AM
I am not quite sure what your problem is but definitely you should clear the flag in the bootloader code when you decide to stay in the bootloader, no matter what is the reset cause: Something like:
if (jumpToIAPFlag)
{
jumpToIAPFlag = 0;
// bootloader code
}
else
// start the app