/* 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 "BootMark.h"
|
#include "MCUFlash.h"
|
#include "SoftCRC.h"
|
#include <stdio.h>
|
#include <string.h>
|
|
/* USER CODE END Includes */
|
|
/* Private typedef -----------------------------------------------------------*/
|
/* USER CODE BEGIN PTD */
|
|
/* USER CODE END PTD */
|
|
/* Private define ------------------------------------------------------------*/
|
/* USER CODE BEGIN PD */
|
|
/* USER CODE END PD */
|
|
/* Private macro -------------------------------------------------------------*/
|
/* USER CODE BEGIN PM */
|
|
/* USER CODE END PM */
|
|
/* Private variables ---------------------------------------------------------*/
|
|
UART_HandleTypeDef huart1;
|
DMA_HandleTypeDef hdma_usart1_rx;
|
DMA_HandleTypeDef hdma_usart1_tx;
|
|
/* USER CODE BEGIN PV */
|
|
/* 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_DMA_Init(void);
|
static void MX_USART1_UART_Init(void);
|
/* USER CODE BEGIN PFP */
|
|
/* USER CODE END PFP */
|
|
/* Private user code ---------------------------------------------------------*/
|
/* USER CODE BEGIN 0 */
|
|
// ============================================================
|
// 调试宏定义
|
// ============================================================
|
// 启用后直接跳转到APP1,不做任何校验(用于下载器直接烧录APP调试)
|
// #define DEBUG_DIRECT_JUMP_APP1
|
|
// 调试输出宏
|
#define DEBUG_UART huart1
|
#define BootDebug(fmt, ...) printf("[BOOT] " fmt, ##__VA_ARGS__)
|
|
// 重定向printf到UART1
|
int fputc(int ch, FILE *f)
|
{
|
HAL_UART_Transmit(&DEBUG_UART, (uint8_t *)&ch, 1, 0xFFFF);
|
return ch;
|
}
|
|
// LED控制宏(用于状态指示)
|
#define LED_ON() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)
|
#define LED_OFF() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)
|
#define LED_TOGGLE() HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0)
|
|
// 跳转到APP的函数
|
static void JumpToApp(uint32_t appAddr);
|
// 执行固件更新
|
static int32_t PerformUpdate(const BootMark_t *pMark);
|
// Bootloader主逻辑
|
static void Bootloader_Main(void);
|
|
/* USER CODE END 0 */
|
|
/**
|
* @brief The application entry point.
|
* @retval int
|
*/
|
int main(void)
|
{
|
|
/* USER CODE BEGIN 1 */
|
/* Enable the CPU Cache */
|
|
/* Enable I-Cache---------------------------------------------------------*/
|
// SCB_EnableICache();
|
|
/* Enable D-Cache---------------------------------------------------------*/
|
// SCB_EnableDCache();
|
/* USER CODE END 1 */
|
|
/* MPU Configuration--------------------------------------------------------*/
|
MPU_Config();
|
|
/* 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 */
|
|
/* USER CODE END SysInit */
|
|
/* Initialize all configured peripherals */
|
MX_GPIO_Init();
|
MX_DMA_Init();
|
MX_USART1_UART_Init();
|
/* USER CODE BEGIN 2 */
|
|
// 启动Bootloader主逻辑
|
Bootloader_Main();
|
|
/* USER CODE END 2 */
|
|
/* Infinite loop */
|
/* USER CODE BEGIN WHILE */
|
while (1)
|
{
|
/* USER CODE END WHILE */
|
|
/* USER CODE BEGIN 3 */
|
// 不应该执行到这里
|
LED_TOGGLE();
|
HAL_Delay(100);
|
}
|
/* 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_SCALE0);
|
|
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_ON;
|
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
|
RCC_OscInitStruct.PLL.PLLM = 4;
|
RCC_OscInitStruct.PLL.PLLN = 60;
|
RCC_OscInitStruct.PLL.PLLP = 2;
|
RCC_OscInitStruct.PLL.PLLQ = 2;
|
RCC_OscInitStruct.PLL.PLLR = 2;
|
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
|
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
|
RCC_OscInitStruct.PLL.PLLFRACN = 0;
|
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_PLLCLK;
|
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
|
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
|
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
|
|
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
|
{
|
Error_Handler();
|
}
|
}
|
|
/**
|
* @brief USART1 Initialization Function
|
* @param 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 = 921600;
|
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 */
|
|
}
|
|
/**
|
* Enable DMA controller clock
|
*/
|
static void MX_DMA_Init(void)
|
{
|
|
/* DMA controller clock enable */
|
__HAL_RCC_DMA1_CLK_ENABLE();
|
|
/* DMA interrupt init */
|
/* DMA1_Stream0_IRQn interrupt configuration */
|
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
|
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
|
/* DMA1_Stream1_IRQn interrupt configuration */
|
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
|
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
|
|
}
|
|
/**
|
* @brief GPIO Initialization Function
|
* @param 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_GPIOC_CLK_ENABLE();
|
__HAL_RCC_GPIOH_CLK_ENABLE();
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
/*Configure GPIO pin Output Level */
|
HAL_GPIO_WritePin(GPIOC, RED_Pin|GREEN_Pin|BLUE_Pin, GPIO_PIN_SET);
|
|
/*Configure GPIO pin : KEY_Pin */
|
GPIO_InitStruct.Pin = KEY_Pin;
|
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
HAL_GPIO_Init(KEY_GPIO_Port, &GPIO_InitStruct);
|
|
/*Configure GPIO pin : RED_Pin */
|
GPIO_InitStruct.Pin = RED_Pin;
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
HAL_GPIO_Init(RED_GPIO_Port, &GPIO_InitStruct);
|
|
/*Configure GPIO pins : GREEN_Pin BLUE_Pin */
|
GPIO_InitStruct.Pin = GREEN_Pin|BLUE_Pin;
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
|
/*AnalogSwitch Config */
|
HAL_SYSCFG_AnalogSwitchConfig(SYSCFG_SWITCH_PC2, SYSCFG_SWITCH_PC2_CLOSE);
|
|
/* USER CODE BEGIN MX_GPIO_Init_2 */
|
|
/* USER CODE END MX_GPIO_Init_2 */
|
}
|
|
/* USER CODE BEGIN 4 */
|
|
/* 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 Period elapsed callback in non blocking mode
|
* @note This function is called when TIM17 interrupt took place, inside
|
* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
|
* a global variable "uwTick" used as application time base.
|
* @param htim : TIM handle
|
* @retval None
|
*/
|
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
|
{
|
/* USER CODE BEGIN Callback 0 */
|
|
/* USER CODE END Callback 0 */
|
if (htim->Instance == TIM17)
|
{
|
HAL_IncTick();
|
}
|
/* USER CODE BEGIN Callback 1 */
|
|
/* USER CODE END Callback 1 */
|
}
|
|
/* USER CODE BEGIN 4 */
|
|
/**
|
* @brief 执行固件更新 (Copy Staging -> APP)
|
*/
|
static int32_t PerformUpdate(const BootMark_t *pMark)
|
{
|
int32_t ret;
|
uint32_t offset;
|
uint32_t remaining;
|
uint32_t chunk;
|
uint8_t buffer[256]; // Reduced buffer size to prevent stack overflow (Stack is 4KB)
|
uint32_t appAddr = BOOT_APP_ADDR;
|
uint32_t stagingAddr = BOOT_OTA_STAGING_ADDR;
|
uint32_t firmwareSize = pMark->u32FirmwareSize;
|
|
BootDebug("Starting Firmware Update...\r\n");
|
BootDebug(" - Source: 0x%08X\r\n", stagingAddr);
|
BootDebug(" - Dest: 0x%08X\r\n", appAddr);
|
BootDebug(" - Size: %u bytes\r\n", firmwareSize);
|
|
// 1. Erase APP Area
|
BootDebug("Erasing APP area...\r\n");
|
// Erase max APP size (256KB) to be safe
|
ret = MCUFlash_Erase(appAddr, BOOT_APP_MAX_SIZE);
|
if (ret != 0) {
|
BootDebug("ERROR: Erase failed: %d\r\n", ret);
|
return BOOT_ERR_FLASH;
|
}
|
|
// Verify Erase (Check first and last word)
|
if (*(volatile uint32_t*)appAddr != 0xFFFFFFFF) {
|
BootDebug("ERROR: Erase verification failed at start (0x%08X)\r\n", appAddr);
|
return BOOT_ERR_FLASH;
|
}
|
|
// 2. Copy Loop
|
BootDebug("Copying firmware...\r\n");
|
offset = 0;
|
remaining = firmwareSize;
|
|
while (remaining > 0) {
|
chunk = (remaining > sizeof(buffer)) ? sizeof(buffer) : remaining;
|
|
// Read from Staging
|
ret = MCUFlash_Read(stagingAddr + offset, buffer, chunk);
|
if (ret != 0) {
|
BootDebug("ERROR: Read staging failed at offset 0x%X\r\n", offset);
|
return BOOT_ERR_FLASH;
|
}
|
|
// Write to APP
|
ret = MCUFlash_Write(appAddr + offset, buffer, chunk);
|
if (ret != 0) {
|
BootDebug("ERROR: Write APP failed at offset 0x%X\r\n", offset);
|
return BOOT_ERR_FLASH;
|
}
|
|
offset += chunk;
|
remaining -= chunk;
|
|
// Progress indicator
|
if ((offset % (32*1024)) == 0) {
|
BootDebug(".");
|
}
|
}
|
BootDebug("\r\nCopy complete.\r\n");
|
|
// 3. Verify APP Area (CRC Check)
|
BootDebug("Verifying APP CRC...\r\n");
|
uint32_t calcCRC = 0;
|
uint32_t wordCount = (firmwareSize + 3) / 4;
|
|
// APP is memory mapped, read directly
|
calcCRC = SoftCRC_Calculate((uint32_t *)appAddr, wordCount);
|
|
if (calcCRC != pMark->u32FirmwareCRC) {
|
BootDebug("ERROR: CRC Mismatch! Calc: 0x%08X, Expect: 0x%08X\r\n", calcCRC, pMark->u32FirmwareCRC);
|
return BOOT_ERR_CRC;
|
}
|
|
BootDebug("Verification Successful!\r\n");
|
return BOOT_OK;
|
}
|
|
/**
|
* @brief Bootloader主逻辑
|
*/
|
static void Bootloader_Main(void)
|
{
|
int32_t ret;
|
BootMark_t bootMark;
|
|
// 等待UART稳定
|
HAL_Delay(200);
|
|
BootDebug("\r\n");
|
BootDebug("========================================\r\n");
|
BootDebug(" STM32H743 Bootloader (Single Bank) \r\n");
|
BootDebug("========================================\r\n");
|
|
// 初始化Boot标记模块
|
BootDebug("Initializing...\r\n");
|
ret = BootMark_Init();
|
if (ret != BOOT_OK) {
|
BootDebug("ERROR: Init failed: %d\r\n", ret);
|
}
|
|
// 读取Boot标记
|
ret = BootMark_Read(&bootMark);
|
|
// 检查是否有更新待处理
|
if (ret == BOOT_OK && bootMark.u32UpdateFlag == BOOT_UPDATE_PENDING) {
|
BootDebug("Found Pending Update:\r\n");
|
BootDebug(" - Version: %u\r\n", bootMark.u32Version);
|
BootDebug(" - Size: %u\r\n", bootMark.u32FirmwareSize);
|
BootDebug(" - CRC: 0x%08X\r\n", bootMark.u32FirmwareCRC);
|
|
// 验证暂存区固件
|
BootDebug("Verifying Staging Area...\r\n");
|
if (BootMark_VerifyStaging(&bootMark) == BOOT_OK) {
|
BootDebug("Staging Valid. Starting Update Process...\r\n");
|
|
// 执行更新
|
if (PerformUpdate(&bootMark) == BOOT_OK) {
|
BootDebug("Update Completed Successfully.\r\n");
|
|
// 清除更新标志
|
BootDebug("Clearing Update Flag...\r\n");
|
BootMark_Clear();
|
|
BootDebug("Rebooting...\r\n");
|
HAL_Delay(100);
|
HAL_NVIC_SystemReset();
|
} else {
|
BootDebug("FATAL: Update Failed!\r\n");
|
BootDebug("System halted. Please re-flash via SWD or retry.\r\n");
|
while(1) {
|
LED_TOGGLE();
|
HAL_Delay(100);
|
}
|
}
|
} else {
|
BootDebug("ERROR: Staging Verification Failed (CRC Mismatch or Invalid).\r\n");
|
BootDebug("Canceling Update.\r\n");
|
BootMark_Clear(); // 清除标志
|
}
|
} else {
|
BootDebug("No Update Pending.\r\n");
|
}
|
|
// 跳转到APP
|
BootDebug("Booting APP at 0x%08X...\r\n", BOOT_APP_ADDR);
|
JumpToApp(BOOT_APP_ADDR);
|
}
|
|
/**
|
* @brief 跳转到APP
|
* @param appAddr APP起始地址
|
*/
|
static void JumpToApp(uint32_t appAddr)
|
{
|
typedef void (*pFunction)(void);
|
|
uint32_t jumpAddress;
|
pFunction jumpToApp;
|
uint32_t stackPointer;
|
|
BootDebug("Preparing jump to 0x%08X...\r\n", appAddr);
|
|
// 检查APP地址有效性
|
if (appAddr != BOOT_APP_ADDR) {
|
BootDebug("ERROR: Invalid APP address!\r\n");
|
return;
|
}
|
|
// 读取栈指针(APP向量表第一个字)
|
stackPointer = *((volatile uint32_t *)appAddr);
|
BootDebug(" - Stack Pointer: 0x%08X\r\n", stackPointer);
|
|
// 检查栈指针有效性(应该在RAM范围内)
|
if ((stackPointer & 0xFF000000) != 0x20000000 &&
|
(stackPointer & 0xFF000000) != 0x24000000 &&
|
(stackPointer & 0xFF000000) != 0x30000000 &&
|
(stackPointer & 0xFF000000) != 0x38000000) {
|
BootDebug("ERROR: Invalid stack pointer (not in RAM)!\r\n");
|
BootDebug("APP may be missing or corrupt.\r\n");
|
while(1) {
|
LED_TOGGLE();
|
HAL_Delay(500);
|
}
|
}
|
|
// 读取Reset Handler地址(APP向量表第二个字)
|
jumpAddress = *((volatile uint32_t *)(appAddr + 4));
|
jumpToApp = (pFunction)jumpAddress;
|
BootDebug(" - Reset Handler: 0x%08X\r\n", jumpAddress);
|
|
// 检查Reset Handler是否合理(应该在Flash范围内)
|
if ((jumpAddress & 0xFF000000) != 0x08000000) {
|
BootDebug("ERROR: Invalid reset handler (not in Flash)!\r\n");
|
return;
|
}
|
|
BootDebug(" - Setting VTOR to 0x%08X\r\n", appAddr);
|
BootDebug(" - Disabling interrupts...\r\n");
|
BootDebug("Jumping to APP now...\r\n\r\n");
|
|
HAL_Delay(50); // 等待UART发送完成
|
|
// 关闭所有中断
|
__disable_irq();
|
|
// 关闭SysTick
|
SysTick->CTRL = 0;
|
SysTick->LOAD = 0;
|
SysTick->VAL = 0;
|
|
// 禁用所有外设中断
|
for (int i = 0; i < 8; i++) {
|
NVIC->ICER[i] = 0xFFFFFFFF;
|
NVIC->ICPR[i] = 0xFFFFFFFF;
|
}
|
|
// 设置向量表偏移到APP地址
|
SCB->VTOR = appAddr;
|
|
// 设置主堆栈指针
|
__set_MSP(stackPointer);
|
|
// 跳转到APP的Reset Handler
|
jumpToApp();
|
|
// 不应该执行到这里
|
BootDebug("ERROR: Should not reach here after jump!\r\n");
|
while (1) {
|
LED_TOGGLE();
|
HAL_Delay(50);
|
}
|
}
|
|
/* USER CODE END 4 */
|
|
/**
|
* @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.
|
* @param file: pointer to the source file name
|
* @param 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 */
|