cancel
Showing results for 
Search instead for 
Did you mean: 

Trouble Jumping to Bootloader from Application on STM32H747 with Riverdi Display and TouchGFX

Sasa1234
Associate III

Hello everyone,

I'm facing an issue with jumping from my application to the bootloader on an STM32H747 microcontroller. I'm using a 7-inch Riverdi display and have developed graphical interfaces using TouchGFX. My application, which I've built using only the M7 core (disabling the M4 core) and FreeRTOS for task management and graphics, has its main file structured as man1.c attached.I've also created a bootloader program with the following structure:  The bootloader works perfectly when the STM32H747xx_FLASH.ld file contains the following instruction:

Assolutamente! Ecco la traduzione del tuo post in inglese, adatta per un forum tecnico come quello di STM:

Subject: Trouble Jumping to Bootloader from Application on STM32H747 with Riverdi Display and TouchGFX

Hello everyone,

I'm facing an issue with jumping from my application to the bootloader on an STM32H747 microcontroller. I'm using a 7-inch Riverdi display and have developed graphical interfaces using TouchGFX. My application, which I've built using only the M7 core (disabling the M4 core) and FreeRTOS for task management and graphics, has its main file structured as follows:

I've also created a bootloader program with the following structure:

The bootloader works perfectly when the STM32H747xx_FLASH.ld file contains the following instruction:

MEMORY
{
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
/*FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K*/ /* Memory is divided. Actual start is 0x08000000 and actual length is 2048K */

FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 250K

DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
SDRAM (xrw) : ORIGIN = 0xD0000000, LENGTH = 4M
SDRAM2 (xrw) : ORIGIN = 0xD0400000, LENGTH = 4M
}

 

However, when I try to jump to the bootloader from my application using a jump_to_bootloader() function, the jump to the bootloader fails. This is code snipet:

 

typedef void (*pFunction)(void);
 
 
#define BOOT_ADDR 0x080B50000
void jump_to_bootloader(void)
{
 
 
 
__disable_irq();  // Disabilita tutti gli interrupt
 
HAL_RCC_DeInit(); // Disabilita tutti i clock
HAL_DeInit();     // Deinizializza le periferiche
 
 
 
SCB_DisableICache();
SCB_DisableDCache();
 
// Disabilita SysTick timer
   // SysTick->CTRL = 0;
   // SysTick->LOAD = 0;
   // SysTick->VAL  = 0;
 
 
// Pulisci flag di reset
__HAL_RCC_CLEAR_RESET_FLAGS();
 
 
 
__set_MSP(*(__IO uint32_t*)BOOT_ADDRESS); // Imposta il nuovo Stack Pointer
 
 
SCB->VTOR = BOOT_ADDRESS;
 
// Puntatore alla funzione di reset dell'applicativo
uint32_t JumpAddr = *(__IO uint32_t*)(BOOT_ADDRESS+ 4);
pFunction Jump = (pFunction)JumpAddr;
 
__enable_irq(); // Riabilita gli interrupt prima del salto
// Esegui il salto
Jump(); // Salta all’applicazione
// Se il salto fallisce, reset
NVIC_SystemReset();
}

 

 I've made to the .ld files of both the application and the bootloader.

// Application .ld

/* Memories definition */
MEMORY
{
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
/*FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K*/ /* Memory is divided. Actual start is 0x08000000 and actual length is 2048K */

FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 724K

DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
QUADSPI (r) : ORIGIN = 0x90000000, LENGTH = 64M
SDRAM (xrw) : ORIGIN = 0xD0000000, LENGTH = 4M
SDRAM2 (xrw) : ORIGIN = 0xD0400000, LENGTH = 4M
}

// Bootloader.ld

 

/* Memories definition */
MEMORY
{
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
/*FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K*/ /* Memory is divided. Actual start is 0x08000000 and actual length is 2048K */

FLASH (rx) : ORIGIN = 0x08B500000, LENGTH = 250K

DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
SDRAM (xrw) : ORIGIN = 0xD0000000, LENGTH = 4M
SDRAM2 (xrw) : ORIGIN = 0xD0400000, LENGTH = 4M
}

 

 

Could someone please advise on what modifications I need to make in both the application and the bootloader code to successfully jump to the bootloader? Is there something I'm missing in the process?How may I had to manage all peripherals?

Thank you in advance for your help!

 

 

 

21 REPLIES 21

Hello @MM..1 ,

The good news is that the jump mechanism itself is much more stable now; the CAN bus no longer goes into error when I repeatedly send the jump command (verified with a CAN bus analyzer).

However, I'm facing a new issue: Neither the bootloader nor the application transmits any CAN messages, even though the code for transmission is present and should be executing. I'm not seeing any messages on my CAN bus analyzer. 

jump back to the application.

Current Status & Problem:

The good news is that the jump mechanism itself is much more stable now; the CAN bus no longer goes into error when I repeatedly send the jump command (verified with a CAN bus analyzer).

However, I'm facing a new issue: Neither the bootloader nor the application transmits any CAN messages, even though the code for transmission is present and should be executing. I'm not seeing any messages on my CAN bus analyzer. 

These function init FDCAN1 Interrupt in stm32h7xx_it.c:

void FDCAN1_IT0_IRQHandler(void)
{
  /* USER CODE BEGIN FDCAN1_IT0_IRQn 0 */

  /* USER CODE END FDCAN1_IT0_IRQn 0 */
  HAL_FDCAN_IRQHandler(&hfdcan1);
  /* USER CODE BEGIN FDCAN1_IT0_IRQn 1 */

  /* USER CODE END FDCAN1_IT0_IRQn 1 */
}

CAN peripheral:

 

void TX_CANMessage_from_ECU(uint32_t ID, uint8_t *Tx)
{


	// Configure TX Header for FDCAN1
	TxHeader1.Identifier = ID;
	TxHeader1.IdType = FDCAN_STANDARD_ID;
	TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
	TxHeader1.DataLength = FDCAN_DLC_BYTES_3;
	TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
	TxHeader1.BitRateSwitch = FDCAN_BRS_OFF;
	TxHeader1.FDFormat = FDCAN_CLASSIC_CAN;
	TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
	TxHeader1.MessageMarker = 0;







	if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, Tx)!= HAL_OK)
	{
		Error_Handler();
	}




}


/* FDCAN1 init function */
void MX_FDCAN1_Init(void)
{

	/* USER CODE BEGIN FDCAN1_Init 0 */

	/* USER CODE END FDCAN1_Init 0 */

	/* USER CODE BEGIN FDCAN1_Init 1 */

	/* USER CODE END FDCAN1_Init 1 */
	hfdcan1.Instance = FDCAN1;
	hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
	hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
	hfdcan1.Init.AutoRetransmission = DISABLE;
	hfdcan1.Init.TransmitPause = DISABLE;
	hfdcan1.Init.ProtocolException = DISABLE;
	hfdcan1.Init.NominalPrescaler = 16;
	hfdcan1.Init.NominalSyncJumpWidth = 1;
	hfdcan1.Init.NominalTimeSeg1 = 2;
	hfdcan1.Init.NominalTimeSeg2 = 2;
	hfdcan1.Init.DataPrescaler = 1;
	hfdcan1.Init.DataSyncJumpWidth = 1;
	hfdcan1.Init.DataTimeSeg1 = 1;
	hfdcan1.Init.DataTimeSeg2 = 1;

	hfdcan1.Init.MessageRAMOffset = 0;
	hfdcan1.Init.StdFiltersNbr = 1;
	hfdcan1.Init.ExtFiltersNbr = 0;
	hfdcan1.Init.RxFifo0ElmtsNbr = RX_MSG; //2; //1;
	hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
	hfdcan1.Init.RxFifo1ElmtsNbr = RX_MSG; //1; //0;
	hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;
	hfdcan1.Init.RxBuffersNbr = 0;
	hfdcan1.Init.RxBufferSize = FDCAN_DATA_BYTES_8;
	hfdcan1.Init.TxEventsNbr = 0;
	hfdcan1.Init.TxBuffersNbr = 0;
	hfdcan1.Init.TxFifoQueueElmtsNbr =  TX_MSG; //3;  //2;
	hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
	hfdcan1.Init.TxElmtSize = FDCAN_DATA_BYTES_8;






	if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
	{
		Error_Handler();
	}
	/* USER CODE BEGIN FDCAN1_Init 2 */

	FDCAN_FilterTypeDef sFilterConfig;

	sFilterConfig.IdType = FDCAN_STANDARD_ID;
	sFilterConfig.FilterIndex = 0;
	sFilterConfig.FilterType = FDCAN_FILTER_MASK;
	sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
	sFilterConfig.FilterID1 = 0x321;
	sFilterConfig.FilterID2 = 0x7FF;

	sFilterConfig.RxBufferIndex = 0;


	if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
	{
		/* Filter configuration Error */
		Error_Handler();
	}



	/* USER CODE END FDCAN1_Init 2 */

}

static uint32_t HAL_RCC_FDCAN_CLK_ENABLED=0;

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{

	GPIO_InitTypeDef GPIO_InitStruct = {0};
	RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
	if(fdcanHandle->Instance==FDCAN1)
	{
		/* USER CODE BEGIN FDCAN1_MspInit 0 */

		/* USER CODE END FDCAN1_MspInit 0 */

		/** Initializes the peripherals clock
		 */
		PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
		PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL;
		if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
		{
			Error_Handler();
		}

		/* FDCAN1 clock enable */
		HAL_RCC_FDCAN_CLK_ENABLED++;
		if(HAL_RCC_FDCAN_CLK_ENABLED==1){
			__HAL_RCC_FDCAN_CLK_ENABLE();
		}

		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		/**FDCAN1 GPIO Configuration
    PB9     ------> FDCAN1_TX
    PA11     ------> FDCAN1_RX
		 */
		GPIO_InitStruct.Pin = GPIO_PIN_9;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		GPIO_InitStruct.Pin = GPIO_PIN_11;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

		/* USER CODE BEGIN FDCAN1_MspInit 1 */

		/* USER CODE END FDCAN1_MspInit 1 */
	}
	else if(fdcanHandle->Instance==FDCAN2)
	{
		/* USER CODE BEGIN FDCAN2_MspInit 0 */

		/* USER CODE END FDCAN2_MspInit 0 */

		/** Initializes the peripherals clock
		 */
		PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
		PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL;
		if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
		{
			Error_Handler();
		}

		/* FDCAN2 clock enable */
		HAL_RCC_FDCAN_CLK_ENABLED++;
		if(HAL_RCC_FDCAN_CLK_ENABLED==1){
			__HAL_RCC_FDCAN_CLK_ENABLE();
		}

		__HAL_RCC_GPIOB_CLK_ENABLE();
		/**FDCAN2 GPIO Configuration
    PB5     ------> FDCAN2_RX
    PB13     ------> FDCAN2_TX
		 */
		GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_13;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN2;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		/* USER CODE BEGIN FDCAN2_MspInit 1 */

		/* USER CODE END FDCAN2_MspInit 1 */
	}
}

void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle)
{

	if(fdcanHandle->Instance==FDCAN1)
	{
		/* USER CODE BEGIN FDCAN1_MspDeInit 0 */

		/* USER CODE END FDCAN1_MspDeInit 0 */
		/* Peripheral clock disable */
		HAL_RCC_FDCAN_CLK_ENABLED--;
		if(HAL_RCC_FDCAN_CLK_ENABLED==0){
			__HAL_RCC_FDCAN_CLK_DISABLE();
		}

		/**FDCAN1 GPIO Configuration
    PB9     ------> FDCAN1_TX
    PA11     ------> FDCAN1_RX
		 */
		HAL_GPIO_DeInit(GPIOB, GPIO_PIN_9);

		HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11);

		/* USER CODE BEGIN FDCAN1_MspDeInit 1 */

		/* USER CODE END FDCAN1_MspDeInit 1 */
	}

	/* USER CODE BEGIN FDCAN2_MspDeInit 1 */



}







void START_CAN_HW()
{


	// Start FDCAN1
	if(HAL_FDCAN_Start(&hfdcan1)!= HAL_OK)
	{
		Error_Handler();
	}

	HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);




	/**
	 * @brief  Notifica di ricezione di messaggio CAN
	 */



	if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
	{



		/* Notification Error */


		Error_Handler();
	}





}

 

This is the system_stm32h7xx_dualcore_boot_cm4_cm7.c file  of bootlader.

void TX_CANMessage_from_ECU(uint32_t ID, uint8_t *Tx)
{


	// Configure TX Header for FDCAN1
	TxHeader1.Identifier = ID;
	TxHeader1.IdType = FDCAN_STANDARD_ID;
	TxHeader1.TxFrameType = FDCAN_DATA_FRAME;
	TxHeader1.DataLength = FDCAN_DLC_BYTES_3;
	TxHeader1.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
	TxHeader1.BitRateSwitch = FDCAN_BRS_OFF;
	TxHeader1.FDFormat = FDCAN_CLASSIC_CAN;
	TxHeader1.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
	TxHeader1.MessageMarker = 0;







	if (HAL_FDCAN_AddMessageToTxFifoQ(&hfdcan1, &TxHeader1, Tx)!= HAL_OK)
	{
		Error_Handler();
	}




}


/* FDCAN1 init function */
void MX_FDCAN1_Init(void)
{

	/* USER CODE BEGIN FDCAN1_Init 0 */

	/* USER CODE END FDCAN1_Init 0 */

	/* USER CODE BEGIN FDCAN1_Init 1 */

	/* USER CODE END FDCAN1_Init 1 */
	hfdcan1.Instance = FDCAN1;
	hfdcan1.Init.FrameFormat = FDCAN_FRAME_CLASSIC;
	hfdcan1.Init.Mode = FDCAN_MODE_NORMAL;
	hfdcan1.Init.AutoRetransmission = DISABLE;
	hfdcan1.Init.TransmitPause = DISABLE;
	hfdcan1.Init.ProtocolException = DISABLE;
	hfdcan1.Init.NominalPrescaler = 16;
	hfdcan1.Init.NominalSyncJumpWidth = 1;
	hfdcan1.Init.NominalTimeSeg1 = 2;
	hfdcan1.Init.NominalTimeSeg2 = 2;
	hfdcan1.Init.DataPrescaler = 1;
	hfdcan1.Init.DataSyncJumpWidth = 1;
	hfdcan1.Init.DataTimeSeg1 = 1;
	hfdcan1.Init.DataTimeSeg2 = 1;

	hfdcan1.Init.MessageRAMOffset = 0;
	hfdcan1.Init.StdFiltersNbr = 1;
	hfdcan1.Init.ExtFiltersNbr = 0;
	hfdcan1.Init.RxFifo0ElmtsNbr = RX_MSG; //2; //1;
	hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_8;
	hfdcan1.Init.RxFifo1ElmtsNbr = RX_MSG; //1; //0;
	hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_8;
	hfdcan1.Init.RxBuffersNbr = 0;
	hfdcan1.Init.RxBufferSize = FDCAN_DATA_BYTES_8;
	hfdcan1.Init.TxEventsNbr = 0;
	hfdcan1.Init.TxBuffersNbr = 0;
	hfdcan1.Init.TxFifoQueueElmtsNbr =  TX_MSG; //3;  //2;
	hfdcan1.Init.TxFifoQueueMode = FDCAN_TX_FIFO_OPERATION;
	hfdcan1.Init.TxElmtSize = FDCAN_DATA_BYTES_8;






	if (HAL_FDCAN_Init(&hfdcan1) != HAL_OK)
	{
		Error_Handler();
	}
	/* USER CODE BEGIN FDCAN1_Init 2 */

	FDCAN_FilterTypeDef sFilterConfig;

	sFilterConfig.IdType = FDCAN_STANDARD_ID;
	sFilterConfig.FilterIndex = 0;
	sFilterConfig.FilterType = FDCAN_FILTER_MASK;
	sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;
	sFilterConfig.FilterID1 = 0x321;
	sFilterConfig.FilterID2 = 0x7FF;

	sFilterConfig.RxBufferIndex = 0;


	if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)
	{
		/* Filter configuration Error */
		Error_Handler();
	}



	/* USER CODE END FDCAN1_Init 2 */

}

static uint32_t HAL_RCC_FDCAN_CLK_ENABLED=0;

void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* fdcanHandle)
{

	GPIO_InitTypeDef GPIO_InitStruct = {0};
	RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
	if(fdcanHandle->Instance==FDCAN1)
	{
		/* USER CODE BEGIN FDCAN1_MspInit 0 */

		/* USER CODE END FDCAN1_MspInit 0 */

		/** Initializes the peripherals clock
		 */
		PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
		PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL;
		if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
		{
			Error_Handler();
		}

		/* FDCAN1 clock enable */
		HAL_RCC_FDCAN_CLK_ENABLED++;
		if(HAL_RCC_FDCAN_CLK_ENABLED==1){
			__HAL_RCC_FDCAN_CLK_ENABLE();
		}

		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_GPIOA_CLK_ENABLE();
		/**FDCAN1 GPIO Configuration
    PB9     ------> FDCAN1_TX
    PA11     ------> FDCAN1_RX
		 */
		GPIO_InitStruct.Pin = GPIO_PIN_9;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		GPIO_InitStruct.Pin = GPIO_PIN_11;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN1;
		HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

		/* USER CODE BEGIN FDCAN1_MspInit 1 */

		/* USER CODE END FDCAN1_MspInit 1 */
	}
	else if(fdcanHandle->Instance==FDCAN2)
	{
		/* USER CODE BEGIN FDCAN2_MspInit 0 */

		/* USER CODE END FDCAN2_MspInit 0 */

		/** Initializes the peripherals clock
		 */
		PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_FDCAN;
		PeriphClkInitStruct.FdcanClockSelection = RCC_FDCANCLKSOURCE_PLL;
		if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
		{
			Error_Handler();
		}

		/* FDCAN2 clock enable */
		HAL_RCC_FDCAN_CLK_ENABLED++;
		if(HAL_RCC_FDCAN_CLK_ENABLED==1){
			__HAL_RCC_FDCAN_CLK_ENABLE();
		}

		__HAL_RCC_GPIOB_CLK_ENABLE();
		/**FDCAN2 GPIO Configuration
    PB5     ------> FDCAN2_RX
    PB13     ------> FDCAN2_TX
		 */
		GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_13;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
		GPIO_InitStruct.Alternate = GPIO_AF9_FDCAN2;
		HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

		/* USER CODE BEGIN FDCAN2_MspInit 1 */

		/* USER CODE END FDCAN2_MspInit 1 */
	}
}

void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* fdcanHandle)
{

	if(fdcanHandle->Instance==FDCAN1)
	{
		/* USER CODE BEGIN FDCAN1_MspDeInit 0 */

		/* USER CODE END FDCAN1_MspDeInit 0 */
		/* Peripheral clock disable */
		HAL_RCC_FDCAN_CLK_ENABLED--;
		if(HAL_RCC_FDCAN_CLK_ENABLED==0){
			__HAL_RCC_FDCAN_CLK_DISABLE();
		}

		/**FDCAN1 GPIO Configuration
    PB9     ------> FDCAN1_TX
    PA11     ------> FDCAN1_RX
		 */
		HAL_GPIO_DeInit(GPIOB, GPIO_PIN_9);

		HAL_GPIO_DeInit(GPIOA, GPIO_PIN_11);

		/* USER CODE BEGIN FDCAN1_MspDeInit 1 */

		/* USER CODE END FDCAN1_MspDeInit 1 */
	}

	/* USER CODE BEGIN FDCAN2_MspDeInit 1 */



}







void START_CAN_HW()
{


	// Start FDCAN1
	if(HAL_FDCAN_Start(&hfdcan1)!= HAL_OK)
	{
		Error_Handler();
	}

	HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0);
	HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);




	/**
	 * @brief  Notifica di ricezione di messaggio CAN
	 */



	if (HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
	{



		/* Notification Error */


		Error_Handler();
	}





}

This is the system_stm32h7xx_dualcore_boot_cm4_cm7.c file  of bootlader.

/**
  ******************************************************************************
  * @file    system_stm32h7xx_dualcore_boot_cm4_cm7.c
  * @author  MCD Application Team
  * @brief   CMSIS Cortex-Mx Device Peripheral Access Layer System Source File.
  *          This provides system initialization template function is case of
  *          an application using a dual core STM32H7 device where
  *          Cortex-M7 and Cortex-M4 boot are enabled at the FLASH option bytes
  *
  *   This file provides two functions and one global variable to be called from
  *   user application:
  *      - SystemInit(): This function is called at startup just after reset and
  *                      before branch to main program. This call is made inside
  *                      the "startup_stm32h7xx.s" file.
  *
  *      - SystemCoreClock variable: Contains the core clock, it can be used
  *                                  by the user application to setup the SysTick
  *                                  timer or configure other parameters.
  *
  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
  *                                 be called whenever the core clock is changed
  *                                 during program execution.
  *
  *
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2017 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.
  *
  ******************************************************************************
  */

/** @addtogroup CMSIS
  * @{
  */

/** @addtogroup stm32h7xx_system
  * @{
  */

/** @addtogroup STM32H7xx_System_Private_Includes
  * @{
  */

#include "stm32h7xx.h"
#include <math.h>

#if !defined  (HSE_VALUE)
#define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
#endif /* HSE_VALUE */

#if !defined  (CSI_VALUE)
  #define CSI_VALUE    ((uint32_t)4000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* CSI_VALUE */

#if !defined  (HSI_VALUE)
  #define HSI_VALUE    ((uint32_t)64000000) /*!< Value of the Internal oscillator in Hz*/
#endif /* HSI_VALUE */


/**
  * @}
  */

/** @addtogroup STM32H7xx_System_Private_TypesDefinitions
  * @{
  */

/**
  * @}
  */

/** @addtogroup STM32H7xx_System_Private_Defines
  * @{
  */

/************************* Miscellaneous Configuration ************************/
/* Note: Following vector table addresses must be defined in line with linker
         configuration. */
/*!< Uncomment the following line if you need to relocate the vector table
     anywhere in FLASH BANK1 or AXI SRAM, else the vector table is kept at the automatic
     remap of boot address selected */

#define USER_VECT_ADDRESS



#if defined(USER_VECT_ADDRESS)
  #define VECT_TAB_BASE_ADDRESS   0x080A0000U  /*!< Custom Vector Table base address */
  #define VECT_TAB_OFFSET         0x00000000U  /*!< Vector Table offset field (must be a multiple of 0x400) */
#endif













#if defined(USER_VECT_TAB_ADDRESS)
#if defined(CORE_CM4)
/*!< Uncomment the following line if you need to relocate your vector Table
     in D2 AXI SRAM else user remap will be done in FLASH BANK2. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS   D2_AXISRAM_BASE   /*!< Vector Table base address field.
                                                       This value must be a multiple of 0x400. */
#define VECT_TAB_OFFSET         0x00000000U       /*!< Vector Table base offset field.
                                                       This value must be a multiple of 0x400. */
#else
#define VECT_TAB_BASE_ADDRESS   FLASH_BANK2_BASE  /*!< Vector Table base address field.
                                                       This value must be a multiple of 0x400. */
#define VECT_TAB_OFFSET         0x00000000U       /*!< Vector Table base offset field.
                                                       This value must be a multiple of 0x400. */
#endif /* VECT_TAB_SRAM */
#elif defined(CORE_CM7)
/*!< Uncomment the following line if you need to relocate your vector Table
     in D1 AXI SRAM else user remap will be done in FLASH BANK1. */
/* #define VECT_TAB_SRAM */
#if defined(VECT_TAB_SRAM)
#define VECT_TAB_BASE_ADDRESS   D1_AXISRAM_BASE   /*!< Vector Table base address field.
                                                       This value must be a multiple of 0x400. */
#define VECT_TAB_OFFSET         0x00000000U       /*!< Vector Table base offset field.
                                                       This value must be a multiple of 0x400. */
#else
#define VECT_TAB_BASE_ADDRESS   FLASH_BANK1_BASE  /*!< Vector Table base address field.
                                                       This value must be a multiple of 0x400. */
#define VECT_TAB_OFFSET         0x00000000U       /*!< Vector Table base offset field.
                                                       This value must be a multiple of 0x400. */
#endif /* VECT_TAB_SRAM */
#else
#error Please #define CORE_CM4 or CORE_CM7
#endif /* CORE_CM4 */
#endif /* USER_VECT_TAB_ADDRESS */
/******************************************************************************/

/**
  * @}
  */

/** @addtogroup STM32H7xx_System_Private_Macros
  * @{
  */

/**
  * @}
  */

/** @addtogroup STM32H7xx_System_Private_Variables
  * @{
  */
  /* This variable is updated in three ways:
      1) by calling CMSIS function SystemCoreClockUpdate()
      2) by calling HAL API function HAL_RCC_GetHCLKFreq()
      3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
         Note: If you use this function to configure the system clock; then there
               is no need to call the 2 first functions listed above, since SystemCoreClock
               variable is updated automatically.
  */
  uint32_t SystemCoreClock = 64000000;
  uint32_t SystemD2Clock = 64000000;
  const  uint8_t D1CorePrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};

/**
  * @}
  */

/** @addtogroup STM32H7xx_System_Private_FunctionPrototypes
  * @{
  */

/**
  * @}
  */

/** @addtogroup STM32H7xx_System_Private_Functions
  * @{
  */

/**
  * @brief  Setup the microcontroller system
  *         Initialize the FPU setting and  vector table location
  *         configuration.
  * @param  None
  * @retval None
  */
void SystemInit (void)
{
  /* FPU settings ------------------------------------------------------------*/
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    SCB->CPACR |= ((3UL << (10*2))|(3UL << (11*2)));  /* set CP10 and CP11 Full Access */
  #endif

    /*SEVONPEND enabled so that an interrupt coming from the CPU(n) interrupt signal is
     detectable by the CPU after a WFI/WFE instruction.*/
 SCB->SCR |= SCB_SCR_SEVONPEND_Msk;

#if defined(CORE_CM7)
  /* Reset the RCC clock configuration to the default reset state ------------*/
   /* Increasing the CPU frequency */
  if(FLASH_LATENCY_DEFAULT  > (READ_BIT((FLASH->ACR), FLASH_ACR_LATENCY)))
  {
    /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
    MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, (uint32_t)(FLASH_LATENCY_DEFAULT));
  }

  /* Set HSION bit */
  RCC->CR |= RCC_CR_HSION;

  /* Reset CFGR register */
  RCC->CFGR = 0x00000000;

  /* Reset HSEON, HSECSSON, CSION, HSI48ON, CSIKERON, PLL1ON, PLL2ON and PLL3ON bits */
  RCC->CR &= 0xEAF6ED7FU;

   /* Decreasing the number of wait states because of lower CPU frequency */
  if(FLASH_LATENCY_DEFAULT  < (READ_BIT((FLASH->ACR), FLASH_ACR_LATENCY)))
  {
    /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
    MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, (uint32_t)(FLASH_LATENCY_DEFAULT));
  }

  /* Reset D1CFGR register */
  RCC->D1CFGR = 0x00000000;

  /* Reset D2CFGR register */
  RCC->D2CFGR = 0x00000000;

  /* Reset D3CFGR register */
  RCC->D3CFGR = 0x00000000;

  /* Reset PLLCKSELR register */
  RCC->PLLCKSELR = 0x02020200;

  /* Reset PLLCFGR register */
  RCC->PLLCFGR = 0x01FF0000;
  /* Reset PLL1DIVR register */
  RCC->PLL1DIVR = 0x01010280;
  /* Reset PLL1FRACR register */
  RCC->PLL1FRACR = 0x00000000;

  /* Reset PLL2DIVR register */
  RCC->PLL2DIVR = 0x01010280;

  /* Reset PLL2FRACR register */

  RCC->PLL2FRACR = 0x00000000;
  /* Reset PLL3DIVR register */
  RCC->PLL3DIVR = 0x01010280;

  /* Reset PLL3FRACR register */
  RCC->PLL3FRACR = 0x00000000;

  /* Reset HSEBYP bit */
  RCC->CR &= 0xFFFBFFFFU;

  /* Disable all interrupts */
  RCC->CIER = 0x00000000;

  /* Enable CortexM7 HSEM EXTI line (line 78)*/
  EXTI_D2->EMR3 |= 0x4000UL;

  if((DBGMCU->IDCODE & 0xFFFF0000U) < 0x20000000U)
  {
    /* if stm32h7 revY*/
    /* Change  the switch matrix read issuing capability to 1 for the AXI SRAM target (Target 7) */
    *((__IO uint32_t*)0x51008108) = 0x000000001U;
  }

#endif /* CORE_CM7*/


// Modifica 26/05

#if defined(USER_VECT_ADDRESS)
  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET;
#endif






#if defined(CORE_CM4)
  /* Configure the Vector Table location add offset address for cortex-M4 ------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal D2 AXI-RAM or in Internal FLASH */
#endif /* USER_VECT_TAB_ADDRESS */

#elif defined(CORE_CM7)
  /*
   * Disable the FMC bank1 (enabled after reset).
   * This, prevents CPU speculation access on this bank which blocks the use of FMC during
   * 24us. During this time the others FMC master (such as LTDC) cannot use it!
   */
  FMC_Bank1_R->BTCR[0] = 0x000030D2;

  /* Configure the Vector Table location -------------------------------------*/
#if defined(USER_VECT_TAB_ADDRESS)
  SCB->VTOR = VECT_TAB_BASE_ADDRESS | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal D1 AXI-RAM or in Internal FLASH */
#endif /* USER_VECT_TAB_ADDRESS */

#else
#error Please #define CORE_CM4 or CORE_CM7
#endif /* CORE_CM4 */
}

/**
   * @brief  Update SystemCoreClock variable according to Clock Register Values.
  *         The SystemCoreClock variable contains the core clock , it can
  *         be used by the user application to setup the SysTick timer or configure
  *         other parameters.
  *
  * @note   Each time the core clock changes, this function must be called
  *         to update SystemCoreClock variable value. Otherwise, any configuration
  *         based on this variable will be incorrect.
  *
  * @note   - The system frequency computed by this function is not the real
  *           frequency in the chip. It is calculated based on the predefined
  *           constant and the selected clock source:
  *
  *           - If SYSCLK source is CSI, SystemCoreClock will contain the CSI_VALUE(*)
  *           - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(**)
  *           - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(***)
  *           - If SYSCLK source is PLL, SystemCoreClock will contain the CSI_VALUE(*),
  *             HSI_VALUE(**) or HSE_VALUE(***) multiplied/divided by the PLL factors.
  *
  *         (*) CSI_VALUE is a constant defined in stm32h7xx_hal.h file (default value
  *             4 MHz) but the real value may vary depending on the variations
  *             in voltage and temperature.
  *         (**) HSI_VALUE is a constant defined in stm32h7xx_hal.h file (default value
  *             64 MHz) but the real value may vary depending on the variations
  *             in voltage and temperature.
  *
  *         (***)HSE_VALUE is a constant defined in stm32h7xx_hal.h file (default value
  *              25 MHz), user has to ensure that HSE_VALUE is same as the real
  *              frequency of the crystal used. Otherwise, this function may
  *              have wrong result.
  *
  *         - The result of this function could be not correct when using fractional
  *           value for HSE crystal.
  * @param  None
  * @retval None
  */
void SystemCoreClockUpdate (void)
{
  uint32_t pllp, pllsource, pllm, pllfracen, hsivalue, tmp;
  uint32_t common_system_clock;
  float_t fracn1, pllvco;

  /* Get SYSCLK source -------------------------------------------------------*/

  switch (RCC->CFGR & RCC_CFGR_SWS)
  {
  case RCC_CFGR_SWS_HSI:  /* HSI used as system clock source */
    common_system_clock = (uint32_t) (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3));
    break;

  case RCC_CFGR_SWS_CSI:  /* CSI used as system clock  source */
    common_system_clock = CSI_VALUE;
    break;

  case RCC_CFGR_SWS_HSE:  /* HSE used as system clock  source */
    common_system_clock = HSE_VALUE;
    break;

  case RCC_CFGR_SWS_PLL1:  /* PLL1 used as system clock  source */

    /* PLL_VCO = (HSE_VALUE or HSI_VALUE or CSI_VALUE/ PLLM) * PLLN
    SYSCLK = PLL_VCO / PLLR
    */
    pllsource = (RCC->PLLCKSELR & RCC_PLLCKSELR_PLLSRC);
    pllm = ((RCC->PLLCKSELR & RCC_PLLCKSELR_DIVM1)>> 4)  ;
    pllfracen = ((RCC->PLLCFGR & RCC_PLLCFGR_PLL1FRACEN)>>RCC_PLLCFGR_PLL1FRACEN_Pos);
    fracn1 = (float_t)(uint32_t)(pllfracen* ((RCC->PLL1FRACR & RCC_PLL1FRACR_FRACN1)>> 3));

    if (pllm != 0U)
    {
      switch (pllsource)
      {
        case RCC_PLLCKSELR_PLLSRC_HSI:  /* HSI used as PLL clock source */

        hsivalue = (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3)) ;
        pllvco = ( (float_t)hsivalue / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );

        break;

        case RCC_PLLCKSELR_PLLSRC_CSI:  /* CSI used as PLL clock source */
          pllvco = ((float_t)CSI_VALUE / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );
        break;

        case RCC_PLLCKSELR_PLLSRC_HSE:  /* HSE used as PLL clock source */
          pllvco = ((float_t)HSE_VALUE / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );
        break;

      default:
          hsivalue = (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3)) ;
          pllvco = ((float_t)hsivalue / (float_t)pllm) * ((float_t)(uint32_t)(RCC->PLL1DIVR & RCC_PLL1DIVR_N1) + (fracn1/(float_t)0x2000) +(float_t)1 );
        break;
      }
      pllp = (((RCC->PLL1DIVR & RCC_PLL1DIVR_P1) >>9) + 1U ) ;
      common_system_clock =  (uint32_t)(float_t)(pllvco/(float_t)pllp);
    }
    else
    {
      common_system_clock = 0U;
    }
    break;

  default:
    common_system_clock = (uint32_t) (HSI_VALUE >> ((RCC->CR & RCC_CR_HSIDIV)>> 3));
    break;
  }

  /* Compute SystemClock frequency --------------------------------------------------*/
  tmp = D1CorePrescTable[(RCC->D1CFGR & RCC_D1CFGR_D1CPRE)>> RCC_D1CFGR_D1CPRE_Pos];

  /* common_system_clock frequency : CM7 CPU frequency  */
  common_system_clock >>= tmp;

  /* SystemD2Clock frequency : CM4 CPU, AXI and AHBs Clock frequency  */
  SystemD2Clock = (common_system_clock >> ((D1CorePrescTable[(RCC->D1CFGR & RCC_D1CFGR_HPRE)>> RCC_D1CFGR_HPRE_Pos]) & 0x1FU));

#if defined(CORE_CM4)
  SystemCoreClock = SystemD2Clock;
#else
  SystemCoreClock = common_system_clock;
#endif /* CORE_CM4 */
}


/**
  * @}
  */

/**
  * @}
  */

/**
  * @}
  */

 By the way, it seems that main function is not executed.....

Instrument the HardFault_Handler() in both the loader and application, so you can a) identify situations where it is called, and b) which one is in control. Having Error_Handler() called in a way that identifies the source file and line (__FILE__, __LINE__) can also allow for rapid debugging and identification of problems.

Make sure SystemInit() sets up SCB->VTOR correctly, pointing to the Vector Table for the active image.

As I've previously stated, my preference is to have the code in Reset_Handler explicitly set the SP to the __initial_sp (or whatever symbol you use). Code in the handler can also manage the expedited control transfer to the application.

The use of the linker symbol for the Vector Table in SystemInit() can save tracking and transcription issues, ie the address follows the linker script and doesn't need the code and defines to be edited.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi @Tesla DeLorean,

I've made some changes to the projects, following the specifications in the attached files, but I'm hitting a wall – I'm not getting the outcomes I need. Could I be overlooking something crucial?

My display's code was generated with TouchGFX, and I'm suspecting there might be an issue with peripherals like DMA, or the ones managing graphics/QSPI memory, preventing a clean reset. Maybe a workaround is necessary?

Any insights or suggestions would be incredibly helpful! Thanks in advance for your time and assistance.

urbito
Senior II

Isnt it safer for example, if you have an EEPROM, when you receive the signal from CAN to go to bootloader, to put a byte in eeprom, restart the mcu so it goes to bootloader, check the eeprom, and then if the byte is there, start the CAN procedure you need to do? 

 

hope it helps.

 

greetings.

Hi @urbito ,

 

Thank for your suggestion but I made your  mechanism with a Flag and in my code, if there is this flag, the function "jump_to_bootloader()" is called but unfornately it does not work!!!!

 

 

 

 

Hi @Tesla DeLorean ,

I want to write this post in order to understand if it is clear for me your suggestions:

  • I understand   SystemInit() is called very early during startup (before main()).
  • Its primary role (among others) is to set the   SCB>VTOR register. This register tells the Cortex-M processor where to find the Vector Table for the active application.
  • The Vector Table is essentially a list of addresses for exception handlers (like Reset, HardFault) and interrupt service routines (ISRs).
  • Crucially, I should use a linker symbol (like _VECTOR_TABLE_START) to set SCB->VTOR. This way, if my application's start address changes in the linker script (e.g., from 0x08A0000 to something else), I don't have to manually update the C code. The linker
; In my startup_app.s file
    .global Reset_Handler
    .thumb_func
    .extern __initial_sp

Reset_Handler:
    ldr r0, =__initial_sp
    msr msp, r0
    bl SystemInit
    bl main
.pool
.end​

ensures the symbol points to the correct address.

  • My question here is: Is it enough to simply assign SCB->VTOR = (uint32_t)&__VECTOR_TABLE_START; in SystemInit(), assuming __VECTOR_TABLE_START is correctly defined in my linker script?
  1. Reset_Handler and Explicit Stack Pointer (SP) Setup:

    • The Reset_Handler is the very first piece of code executed after a microcontroller reset.
    • Its immediate task is to set up the Stack Pointer (SP). While the hardware might initialize SP from the Vector Table's first entry, explicitly setting it in Reset_Handler provides more control and clarity.
    • I should use another linker symbol (like __initial_sp) to get the correct initial stack address (typically the top of RAM).
    • The Reset_Handler then calls SystemInit() and finally jumps to main(). This sequence is the "expedited control transfer" to my application.
    • My question here is: Does the assembly snippet I'm using look correct for explicitly setting the MSP and then branching to SystemInit and main?   thank you for your time and attention!!!!

You'll likely need a __DSB() / SCB_CleanDCache() to ensure the magic value gets written to RAM completely before you do the NVIC_SystemReset()

Code in the Reset_Handler also needs to initialize the statics before going of too main()

MOVS SP, R0 should suffice. To load the primary stack pointer

 

https://community.st.com/t5/stm32-mcus-embedded-software/stm32h743-how-to-start-the-system-boot-loader-via-software/td-p/339086

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Hi @Tesla DeLorean ,

 

I modified code as attached but it does not work! :(

 

Try go back to start.

A. Normal situation for custom bootloader is place it on flash start 8000000.

B. Size of bootloader require meet sectors boundary

C. App can be placed on first next free sector in flash.

The flash memory is divided into two independent banks. Each bank is organized as follows:
• A user flash memory block of 512 Kbytes (STM32H7xxxG) or 1-Mbyte (STM32H7xxxI)
containing eight user sectors of 128 Kbytes (4 K flash memory words)

Most simple method to start is option boot ADDR settings no trouble with jump functions chaos. When you stay with function , try start with most simple 5 lines code. VTOR is set in sysinit then main code not require it. On dual core is more sense reboot it right.

Hi, thanks again for your help!
There’s one thing I forgot to mention...

To handle the display graphics, I’m using TouchGFX, along with several other peripherals such as QSPI, various timers, CAN, SPI, and UART interfaces, all of which are initialized at the beginning of the code.

So my question is:
If I perform a reset using  NVIC_SystemReset(),do I need to deinitialize everything before triggering the reset?