cancel
Showing results for 
Search instead for 
Did you mean: 

Get back in IAP from APP

HugoSTM32
Associate II

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

1 REPLY 1
Saket_Om
ST Employee

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.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om