freertos.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * File Name : freertos.c
  5. * Description : Code for freertos applications
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * Copyright (c) 2025 STMicroelectronics.
  10. * All rights reserved.
  11. *
  12. * This software is licensed under terms that can be found in the LICENSE file
  13. * in the root directory of this software component.
  14. * If no LICENSE file comes with this software, it is provided AS-IS.
  15. *
  16. ******************************************************************************
  17. */
  18. /* USER CODE END Header */
  19. /* Includes ------------------------------------------------------------------*/
  20. #include "FreeRTOS.h"
  21. #include "task.h"
  22. #include "main.h"
  23. #include "cmsis_os.h"
  24. /* Private includes ----------------------------------------------------------*/
  25. /* USER CODE BEGIN Includes */
  26. #include "adc.h"
  27. #include "dma.h"
  28. #include "i2c.h"
  29. #include "tim.h"
  30. #include "queue.h"
  31. /* USER CODE END Includes */
  32. /* Private typedef -----------------------------------------------------------*/
  33. typedef StaticQueue_t osStaticMessageQDef_t;
  34. /* USER CODE BEGIN PTD */
  35. /* USER CODE END PTD */
  36. /* Private define ------------------------------------------------------------*/
  37. /* USER CODE BEGIN PD */
  38. typedef enum
  39. {
  40. Close_output,
  41. Close_input,
  42. Open1_input,
  43. Open2_input,
  44. default_Hall
  45. } hallADC;
  46. hallADC Hallmode;
  47. DeviceParams_t g_deviceParams;
  48. /* USER CODE END PD */
  49. /* Private macro -------------------------------------------------------------*/
  50. /* USER CODE BEGIN PM */
  51. //ADC变量定义
  52. uint16_t AD_Value[5] = {0};
  53. uint16_t AD1, AD2, AD3, AD4, AD5 = 0;
  54. int i,adc;
  55. float AD1_Vol,AD2_Vol,AD3_Vol,AD4_Vol,AD5_Vol,AD5_I;
  56. extern uint16_t Valve_status; // 阀状态0000关0001开
  57. float pid_output = 0.0f;
  58. extern uint16_t Running_time; // 运行时长
  59. extern uint32_t Motor_speed; // 电机转速
  60. extern uint32_t Motor_current; // 电机电流
  61. extern uint32_t Magnetic_angle; // 磁角度
  62. extern uint32_t hall_data[4]; // 霍尔1到4的数据
  63. extern uint8_t dataReceive485[BUFFER_SIZE485]; // 485串口接收缓冲区
  64. extern uint16_t uartIRQ_rx_len ; // 485串口接收数据长度
  65. float Motor_cur = 0.0f; // 电机电流
  66. float Motor_spe = 0.0f; // 电机转速
  67. extern float delta_time; // 读取角度间隔时间(毫秒)
  68. extern int32_t freq; // 定时器1频率
  69. uint32_t period_buffer[CAPTURE_DEPTH]; // PWM周期
  70. uint32_t high_buffer[CAPTURE_DEPTH]; // PWM高电平时间
  71. sysmode Systemmode;
  72. /* USER CODE END PM */
  73. /* Private variables ---------------------------------------------------------*/
  74. /* USER CODE BEGIN Variables */
  75. /* USER CODE END Variables */
  76. /* Definitions for HighestTask */
  77. osThreadId_t HighestTaskHandle;
  78. const osThreadAttr_t HighestTask_attributes = {
  79. .name = "HighestTask",
  80. .stack_size = 128 * 4,
  81. .priority = (osPriority_t) osPriorityRealtime,
  82. };
  83. /* Definitions for ReadTask */
  84. osThreadId_t ReadTaskHandle;
  85. const osThreadAttr_t ReadTask_attributes = {
  86. .name = "ReadTask",
  87. .stack_size = 128 * 4,
  88. .priority = (osPriority_t) osPriorityNormal,
  89. };
  90. /* Definitions for DealTask */
  91. osThreadId_t DealTaskHandle;
  92. const osThreadAttr_t DealTask_attributes = {
  93. .name = "DealTask",
  94. .stack_size = 512 * 4,
  95. .priority = (osPriority_t) osPriorityNormal,
  96. };
  97. /* Definitions for CommonTask */
  98. osThreadId_t CommonTaskHandle;
  99. const osThreadAttr_t CommonTask_attributes = {
  100. .name = "CommonTask",
  101. .stack_size = 128 * 4,
  102. .priority = (osPriority_t) osPriorityBelowNormal,
  103. };
  104. /* Definitions for MotorTask */
  105. osThreadId_t MotorTaskHandle;
  106. const osThreadAttr_t MotorTask_attributes = {
  107. .name = "MotorTask",
  108. .stack_size = 256 * 4,
  109. .priority = (osPriority_t) osPriorityNormal,
  110. };
  111. /* Definitions for uart485rxqueue */
  112. osMessageQueueId_t uart485rxqueueHandle;
  113. uint8_t uart485queueBuffer[ 16 * sizeof( Uart485Rx_msg ) ];
  114. osStaticMessageQDef_t uart485queueControlBlock;
  115. const osMessageQueueAttr_t uart485rxqueue_attributes = {
  116. .name = "uart485rxqueue",
  117. .cb_mem = &uart485queueControlBlock,
  118. .cb_size = sizeof(uart485queueControlBlock),
  119. .mq_mem = &uart485queueBuffer,
  120. .mq_size = sizeof(uart485queueBuffer)
  121. };
  122. /* Private function prototypes -----------------------------------------------*/
  123. /* USER CODE BEGIN FunctionPrototypes */
  124. //void uart_enable(void);
  125. //void Restart_UART1_DMA(void);
  126. float Read_MT6813_Angle(void);
  127. void pack_hall_data(void) ;
  128. void pack_Magnetic_angle(void);
  129. void pack_Motor_current(void); // 电机电流
  130. void pack_Motor_speed(void); // 电机转速
  131. /* USER CODE END FunctionPrototypes */
  132. void HighestLEDTask(void *argument);
  133. void ReaddataTask(void *argument);
  134. void DealcallbackTask(void *argument);
  135. void CommonPrintTask(void *argument);
  136. void MotorControlTask(void *argument);
  137. void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */
  138. /**
  139. * @brief FreeRTOS initialization
  140. * @param None
  141. * @retval None
  142. */
  143. void MX_FREERTOS_Init(void) {
  144. /* USER CODE BEGIN Init */
  145. printf("API2_ELE 0612\r\n");
  146. Systemmode = Debugmode; // 调试模式
  147. load_params_from_flash(); // 从内部flash读取传感器参数
  148. Set_485_Baudrate(g_deviceParams.Serial_baud_rate);
  149. Restart_UART1_DMA();
  150. /* USER CODE END Init */
  151. /* USER CODE BEGIN RTOS_MUTEX */
  152. /* add mutexes, ... */
  153. /* USER CODE END RTOS_MUTEX */
  154. /* USER CODE BEGIN RTOS_SEMAPHORES */
  155. /* add semaphores, ... */
  156. /* USER CODE END RTOS_SEMAPHORES */
  157. /* USER CODE BEGIN RTOS_TIMERS */
  158. /* start timers, add new ones, ... */
  159. /* USER CODE END RTOS_TIMERS */
  160. /* Create the queue(s) */
  161. /* creation of uart485rxqueue */
  162. uart485rxqueueHandle = osMessageQueueNew (16, sizeof(Uart485Rx_msg), &uart485rxqueue_attributes);
  163. /* USER CODE BEGIN RTOS_QUEUES */
  164. /* add queues, ... */
  165. /* USER CODE END RTOS_QUEUES */
  166. /* Create the thread(s) */
  167. /* creation of HighestTask */
  168. HighestTaskHandle = osThreadNew(HighestLEDTask, NULL, &HighestTask_attributes);
  169. /* creation of ReadTask */
  170. ReadTaskHandle = osThreadNew(ReaddataTask, NULL, &ReadTask_attributes);
  171. /* creation of DealTask */
  172. DealTaskHandle = osThreadNew(DealcallbackTask, NULL, &DealTask_attributes);
  173. /* creation of CommonTask */
  174. CommonTaskHandle = osThreadNew(CommonPrintTask, NULL, &CommonTask_attributes);
  175. /* creation of MotorTask */
  176. MotorTaskHandle = osThreadNew(MotorControlTask, NULL, &MotorTask_attributes);
  177. /* USER CODE BEGIN RTOS_THREADS */
  178. /* add threads, ... */
  179. /* USER CODE END RTOS_THREADS */
  180. /* USER CODE BEGIN RTOS_EVENTS */
  181. /* add events, ... */
  182. /* USER CODE END RTOS_EVENTS */
  183. }
  184. /* USER CODE BEGIN Header_HighestLEDTask */
  185. /**
  186. * @brief Function implementing the HighestTask thread.
  187. * @param argument: Not used
  188. * @retval None
  189. */
  190. /* USER CODE END Header_HighestLEDTask */
  191. void HighestLEDTask(void *argument)
  192. {
  193. /* USER CODE BEGIN HighestLEDTask */
  194. /* Infinite loop */
  195. LEDStatus_t current_status;
  196. uint8_t last_status = 0;
  197. uint32_t runtimecount = 0;
  198. for(;;)
  199. {
  200. if(Hallmode == Close_output)
  201. current_status = LED_WARNING_1;
  202. else if(Hallmode == Close_input)
  203. current_status = LED_WARNING_2;
  204. else if(Hallmode == Open1_input)
  205. current_status = LED_WARNING_3;
  206. else if(Hallmode == Open2_input)
  207. current_status = LED_WARNING_4;
  208. else
  209. current_status = LED_NORMAL;
  210. if(Motormode == MOTOR_OVERCURRENT)
  211. current_status = LED_WARNING_5;
  212. if(Systemmode == IAPbootloader)
  213. current_status = LED_IAP;
  214. // 只有当状态发生变化时才调用
  215. if (current_status != last_status)
  216. {
  217. last_status = current_status;
  218. UpdateLEDStatus(current_status);
  219. }
  220. LED_FlashHandler(&led_green);
  221. LED_FlashHandler(&led_red);
  222. if(runtimecount > 100)
  223. {
  224. runtimecount = 0;
  225. Running_time ++ ;
  226. if(Running_time > 65535)
  227. Running_time = 0;
  228. }
  229. runtimecount++;
  230. osDelay(10);
  231. }
  232. /* USER CODE END HighestLEDTask */
  233. }
  234. /* USER CODE BEGIN Header_ReaddataTask */
  235. /**
  236. * @brief Function implementing the ReadTask thread.
  237. * @param argument: Not used
  238. * @retval None
  239. */
  240. /* USER CODE END Header_ReaddataTask */
  241. void ReaddataTask(void *argument)
  242. {
  243. /* USER CODE BEGIN ReaddataTask */
  244. /* Infinite loop */
  245. /*角度PWM输入捕获*/
  246. // HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
  247. // HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
  248. // HAL_TIM_IC_Start(&htim1, TIM_CHANNEL_1);
  249. // HAL_TIM_IC_Start(&htim1, TIM_CHANNEL_2);
  250. HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_1, period_buffer, CAPTURE_DEPTH);
  251. HAL_TIM_IC_Start_DMA(&htim1, TIM_CHANNEL_2, high_buffer, CAPTURE_DEPTH);
  252. /*ADC多通道读取*/
  253. ADC_Enable (&hadc1);
  254. HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED); // 启动ADC校准(单端模式)消除ADC的偏移误差 ADC_DIFFERENTIAL_ENDED ADC_SINGLE_ENDED
  255. HAL_ADC_Start_DMA(&hadc1,(uint32_t *) AD_Value, 5); // 启动ADC并通过DMA搬运数据
  256. for(;;)
  257. {
  258. // Read_MT6813_Angle(); // PWM中断读取角度
  259. // read_angle(); // 硬件iic读取角度
  260. pack_Magnetic_angle(); // 组包到 Magnetic_angle 用于MODBUS发送
  261. pack_Motor_speed(); // 组包到 Motor_speed 用于MODBUS发送
  262. AD1 = AD_Value[0];
  263. AD2 = AD_Value[1];
  264. AD3 = AD_Value[2];
  265. AD4 = AD_Value[3];
  266. AD5 = AD_Value[4];
  267. AD1_Vol = (float) AD1 / 4096 * (float) 3.3;
  268. AD2_Vol = (float) AD2 / 4096 * (float) 3.3;
  269. AD3_Vol = (float) AD3 / 4096 * (float) 3.3;
  270. AD4_Vol = (float) AD4 / 4096 * (float) 3.3;
  271. AD5_Vol = (float) AD5 / 4096 * (float) 3.3;
  272. if( AD5_Vol > 3.3f )
  273. AD5_Vol = 0.0f;
  274. AD5_I = AD5_Vol / 0.5f;
  275. Motor_cur = AD5_I;
  276. pack_hall_data(); // 组包到 hall_data 用于MODBUS发送
  277. pack_Motor_current(); // 组包到 Motor_current 用于MODBUS发送
  278. if(AD1_Vol > 1.6f && AD1_Vol < 2.0f && AD2_Vol > 2.5f && AD4_Vol > 1.1f && AD4_Vol < 1.5f)
  279. {
  280. // 拉杆关 电机伸出到位
  281. Hallmode = Close_output;
  282. Valve_status = 0;
  283. }
  284. else if(AD1_Vol > 1.6f && AD1_Vol < 2.0f && AD2_Vol > 2.5f && AD4_Vol > 1.5f && AD4_Vol < 2.0f)
  285. {
  286. // 拉杆关 电机缩回到位
  287. Hallmode = Close_input;
  288. Valve_status = 1;
  289. }
  290. else if(AD1_Vol < 1.0f && AD2_Vol > 1.0f && AD2_Vol < 1.4f && AD4_Vol > 1.6f && AD4_Vol < 2.0f)
  291. {
  292. // 拉杆开 电机缩回到位
  293. Hallmode = Open1_input;
  294. Valve_status = 1;
  295. }
  296. else if(AD1_Vol > 1.2f && AD1_Vol < 1.6f && AD2_Vol > 0.9f && AD2_Vol < 1.3f && AD4_Vol > 1.6f && AD4_Vol < 2.0f)
  297. {
  298. // 拉杆开 电机缩回到位
  299. Hallmode = Open2_input;
  300. Valve_status = 1;
  301. }else{
  302. Hallmode = default_Hall;
  303. Valve_status = 1;
  304. }
  305. osDelay(5);
  306. }
  307. /* USER CODE END ReaddataTask */
  308. }
  309. /* USER CODE BEGIN Header_DealcallbackTask */
  310. /**
  311. * @brief Function implementing the DealTask thread.
  312. * @param argument: Not used
  313. * @retval None
  314. */
  315. /* USER CODE END Header_DealcallbackTask */
  316. void DealcallbackTask(void *argument)
  317. {
  318. /* USER CODE BEGIN DealcallbackTask */
  319. /* Infinite loop */
  320. for(;;)
  321. {
  322. Process_Uart485callback(); // 处理485指令应答
  323. osDelay(20);
  324. }
  325. /* USER CODE END DealcallbackTask */
  326. }
  327. /* USER CODE BEGIN Header_CommonPrintTask */
  328. /**
  329. * @brief Function implementing the CommonTask thread.
  330. * @param argument: Not used
  331. * @retval None
  332. */
  333. /* USER CODE END Header_CommonPrintTask */
  334. void CommonPrintTask(void *argument)
  335. {
  336. /* USER CODE BEGIN CommonPrintTask */
  337. /* Infinite loop */
  338. for(;;)
  339. {
  340. target_angle_deg = pidMotor1Speed.target_val;
  341. diff_Angle = pidMotor1Speed.err;
  342. // printf("target=[%.2f] cur=[%.2f] diff=[%.2f] pid_output=[%.2f] Magnet:[%s] Motor_spe[%.2f] delta_time[%.2f]\r\n",
  343. // target_angle_deg, cur_angle_deg, diff_Angle ,pid_output ,no_mag_flag ? "NO" : "YES" ,Motor_spe ,delta_time);
  344. printf("cur_angle_deg=[%.2f] Motor_spe[%.2f] Motor_cur[%.3f]\r\n", cur_angle_deg,Motor_spe,Motor_cur);
  345. osDelay(200);
  346. // printf("AD1_Vol:[%.3f], AD2_Vol:[%.3f], AD3_Vol:[%.3f], AD4_Vol[%.3f], AD5_Vol[%.3f], Motor_cur[%.3f]\r\n",
  347. // AD1_Vol, AD2_Vol, AD3_Vol, AD4_Vol, AD5_Vol, Motor_cur);
  348. if(Hallmode == Close_output)
  349. {
  350. printf("Close output \r\n"); // 拉杆关 电机伸出到位
  351. }
  352. if(Hallmode == Close_input)
  353. {
  354. printf("Close input \r\n"); // 拉杆关 电机收回到位
  355. }
  356. if(Hallmode == Open1_input)
  357. {
  358. printf("Open1 input \r\n"); // 拉杆开一档 电机收回到位
  359. }
  360. if(Hallmode == Open2_input)
  361. {
  362. printf("Open2 input \r\n"); // 拉杆开二挡 电机收回到位
  363. }
  364. if(Hallmode == default_Hall)
  365. {
  366. printf("default_Hall \r\n"); // 拉杆开 电机收回到位
  367. }
  368. }
  369. /* USER CODE END CommonPrintTask */
  370. }
  371. /* USER CODE BEGIN Header_MotorControlTask */
  372. /**
  373. * @brief Function implementing the MotorTask thread.
  374. * @param argument: Not used
  375. * @retval None
  376. */
  377. /* USER CODE END Header_MotorControlTask */
  378. void MotorControlTask(void *argument)
  379. {
  380. /* USER CODE BEGIN MotorControlTask */
  381. /* Infinite loop */
  382. HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3); // 启动电机 CH1 PWM(控制 IN1)
  383. HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4); // 启动电机 CH2 PWM(控制 IN2)
  384. uint16_t overcurrent_timer_ms = 0; // 记录过流持续时间
  385. PID_init();
  386. for(;;)
  387. {
  388. // 电机角度 cur_angle_deg(0到360度)
  389. // 电机转速 Motor_spe (-400到+400)
  390. // 电机电流 Motor_cur (正常是0.01,堵转最高是到0.035)
  391. // 目标速度 target_speed
  392. // Motor_Angle_Current_PID_Control();
  393. if(use_pid_control)
  394. {
  395. if (Motor_cur > 0.035f )
  396. {
  397. if (overcurrent_timer_ms < 1500)
  398. {
  399. overcurrent_timer_ms += 10; // 每10ms调用一次
  400. }
  401. else
  402. {
  403. // 过流超时,停转
  404. Motormode = MOTOR_OVERCURRENT;
  405. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0);
  406. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, 0);
  407. }
  408. }
  409. else
  410. {
  411. // 电流恢复正常,清零计时器
  412. overcurrent_timer_ms = 0;
  413. }
  414. // Motor_PID_Control();
  415. // Motor_Angle_Current_PID_Control();
  416. int16_t pwm_output = PID_Incremental_Calc(&pidMotor1Speed, pidMotor1Speed.target_speed, Motor_spe);
  417. // 起动门槛限制
  418. if (abs(pwm_output) < 350 && pidMotor1Speed.target_speed != 0)
  419. pwm_output = (pwm_output > 0) ? 500 : -500;
  420. if (Motormode == MOTOR_FORWARD)
  421. Motor_Forward(pwm_output);
  422. if (Motormode == MOTOR_REVERSE)
  423. Motor_Reverse(pwm_output);
  424. if (Motormode == MOTOR_STOPPED)
  425. {
  426. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0);
  427. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, 0);
  428. }
  429. }
  430. // float pwm_Speed = PID_Incremental_Calc(&pidMotor1Speed,1000,Motor_spe);
  431. // __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, pwm_Speed); //电机正转
  432. if(Hallmode != Close_output)
  433. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_4, 0);
  434. if(Hallmode != Open1_input && Hallmode != Open2_input && Hallmode != Close_input)
  435. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, 0);
  436. osDelay(10);
  437. }
  438. /* USER CODE END MotorControlTask */
  439. }
  440. /* Private application code --------------------------------------------------*/
  441. /* USER CODE BEGIN Application */
  442. float Read_MT6813_Angle(void)
  443. {
  444. uint32_t high_time = HAL_TIM_ReadCapturedValue(&htim1, TIM_CHANNEL_2); // 高电平宽度
  445. uint32_t period = HAL_TIM_ReadCapturedValue(&htim1, TIM_CHANNEL_1)+1; // 周期
  446. if (period == 0) return 0.0f;
  447. float duty = (float)high_time / period;
  448. cur_angle_deg = duty * 360.0f;
  449. return angle;
  450. }
  451. void pack_hall_data(void)
  452. {
  453. memcpy(&hall_data[0], &AD1_Vol, sizeof(float)); // float --> uint32_t(IEEE754位一致)
  454. memcpy(&hall_data[1], &AD2_Vol, sizeof(float));
  455. memcpy(&hall_data[2], &AD3_Vol, sizeof(float));
  456. memcpy(&hall_data[3], &AD4_Vol, sizeof(float));
  457. }
  458. void pack_Magnetic_angle(void)
  459. {
  460. memcpy(&Magnetic_angle, &cur_angle_deg, sizeof(float)); // float --> uint32_t
  461. }
  462. void pack_Motor_speed(void) // 电机转速
  463. {
  464. memcpy(&Motor_speed, &Motor_spe, sizeof(float)); // float --> uint32_t
  465. }
  466. void pack_Motor_current(void) // 电机电流
  467. {
  468. memcpy(&Motor_current, &Motor_cur, sizeof(float)); // float --> uint32_t
  469. }
  470. void JumpToBootloader(void)
  471. {
  472. uint32_t i;
  473. void (*SysMemBootJump)(void);
  474. uint32_t BootAddr = 0x1FFF0000; // STM32L431 系统 Bootloader 起始地址
  475. /* 关闭全局中断 */
  476. __disable_irq();
  477. /* 关闭 SysTick */
  478. SysTick->CTRL = 0;
  479. SysTick->LOAD = 0;
  480. SysTick->VAL = 0;
  481. /* 复位 RCC 时钟设置 */
  482. HAL_RCC_DeInit();
  483. /* 禁用所有 NVIC 中断 */
  484. for (i = 0; i < 8; i++) {
  485. NVIC->ICER[i] = 0xFFFFFFFF;
  486. NVIC->ICPR[i] = 0xFFFFFFFF;
  487. }
  488. /* 重新允许中断(尽管之后马上跳转) */
  489. __enable_irq();
  490. /* 重新映射系统内存到 0x00000000 */
  491. __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH();
  492. /* 设置 MSP(Main Stack Pointer) */
  493. __set_MSP(*((uint32_t *)BootAddr));
  494. /* 设置 CONTROL 寄存器,切换为特权级、使用 MSP */
  495. __set_CONTROL(0);
  496. /* 获取 Bootloader 的复位向量地址(入口地址) */
  497. SysMemBootJump = (void (*)(void)) (*((uint32_t *)(BootAddr + 4)));
  498. /* 跳转到系统 Bootloader */
  499. SysMemBootJump();
  500. /* 此处不应再返回 */
  501. while (1);
  502. }
  503. /* USER CODE END Application */