/****************************************************************************** * @file app_boot.c * @brief APP 启动流程(Bootloader 交接、时钟、IWDG、OTA 确认) * @author cyWu <1917507415@qq.com> * @date 2026.08.18 * @version V1.0.0 * @history * - V1.0.0, 2026.08.18, cyWu, 从 main.c 拆出启动逻辑 ******************************************************************************/ #include "app_boot.h" #include "application.h" #include "iwdg.h" #include "ota_ab.h" #include "main.h" /** * @brief 从 Bootloader 跳转过来后,重新打开全局中断 * * Bootloader 跳转 APP 前会 __disable_irq(),且函数跳转不会复位芯片, * 因此 PRIMASK 仍为 1(中断关)。APP 第一件事须 __enable_irq(), * 否则 SysTick / TIM6 / UART 等中断进不来,HAL_Delay、协议超时都会失效。 */ static void app_boot_early_handover(void) { __enable_irq(); } /** * @brief 配置 APP 系统时钟(HSI → PLL → SYSCLK) * * 与官网例程的差异:OscillatorType 故意不含 LSI。 * Bootloader 跳转前已启动 IWDG,IWDG 运行期间 LSI 被硬件锁定关不掉; * 若在此配置 LSI OFF,HAL_RCC_OscConfig 会卡死等待 LSIRDY 变 0。 * LSI 由 IWDG 维持即可,APP 只配置 HSI/PLL 主时钟树。 */ static void app_system_clock_config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /* 主时钟:HSI 24MHz → PLL,不含 LSI(见上方说明) */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE | RCC_OSCILLATORTYPE_HSI | RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_24MHz; RCC_OscInitStruct.HSEState = RCC_HSE_OFF; RCC_OscInitStruct.LSEState = RCC_LSE_OFF; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) { Error_Handler(__FILE__, __LINE__); } } /** * @brief 双备份 OTA:新固件启动确认后,上报一次升级完成(0x34) * * 须在 app_Init() 之后调用(依赖 uartInit / jbInit)。 * ota_boot_check_confirm() 已将 Flash 置为 IDLE,0x34 仅为尽力通知云端; * 发一次即可,丢帧由 jbSendOtaResult 内 SEND_MAX_NUM 重传兜底。 */ static void app_boot_ota_report(void) { uint8_t ver[3]; if (!ota_boot_check_confirm()) { return; } ver[0] = JB_MCU_SW_VERSION_MAJOR; ver[1] = JB_MCU_SW_VERSION_MINOR; ver[2] = JB_MCU_SW_VERSION_PATCH; (void)jbSendOtaResult(JB_OK, ver); appPrintf(LOG_NOTIC, "OTA upgrade complete reported\r\n"); } void app_startup(void) { app_boot_early_handover(); HAL_Init(); iwdg_init(); app_system_clock_config(); app_Init(); app_boot_ota_report(); }