194 lines
5.9 KiB
C
194 lines
5.9 KiB
C
|
|
/**
|
|||
|
|
* BootLoader 程序入口
|
|||
|
|
*
|
|||
|
|
* 功能:
|
|||
|
|
* 1. 上电后最先运行,初始化硬件
|
|||
|
|
* 2. 检查 W25Q64 外部 Flash 中的 OTA 信息区
|
|||
|
|
* 3. 根据信息区状态选择:
|
|||
|
|
* - DOWNLOADED: 新固件已下载,备份当前 APP1 后写入新固件
|
|||
|
|
* - INSTALLED: 已安装新固件,等待 APP 确认;超过重试次数则回退
|
|||
|
|
* - ROLLBACK: 已回退到旧固件,直接跳转
|
|||
|
|
* - 无有效标志: 直接跳转 APP1 运行
|
|||
|
|
* 4. BootLoader 不设置 VTOR 偏移(默认0x08000000)
|
|||
|
|
*
|
|||
|
|
* Flash 布局 (STM32F103RCT6 256KB):
|
|||
|
|
* 0x08000000 ─ BootLoader (32KB)
|
|||
|
|
* 0x08008000 ─ APP1 运行区 (224KB)
|
|||
|
|
*
|
|||
|
|
* W25Q64 外部 Flash 布局:
|
|||
|
|
* 0x000000 ─ 槽 A: 旧固件备份 (256KB)
|
|||
|
|
* 0x040000 ─ 槽 B: 新固件下载 (256KB)
|
|||
|
|
* 0x080000 ─ 信息区 A (4KB)
|
|||
|
|
* 0x081000 ─ 信息区 B (4KB)
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
#include "main.h"
|
|||
|
|
#include "ota_boot.h"
|
|||
|
|
#include "../HardWare/W25Q64/w25q64.h"
|
|||
|
|
#include "../HardWare/LOG/log.h"
|
|||
|
|
|
|||
|
|
/* 串口句柄 */
|
|||
|
|
UART_HandleTypeDef huart1; /* USART1: 调试日志输出 */
|
|||
|
|
UART_HandleTypeDef huart3; /* USART3: OTA 数据通信 */
|
|||
|
|
DMA_HandleTypeDef hdma_usart3_rx; /* USART3 RX DMA */
|
|||
|
|
IWDG_HandleTypeDef hiwdg; /* 独立看门狗:防止擦写/拷贝流程卡死 */
|
|||
|
|
|
|||
|
|
/* OTA 协议接收缓冲区 */
|
|||
|
|
uint8_t Rx_Flag = 0; /* 收到一帧数据标志 */
|
|||
|
|
uint16_t Rx_Len = 0; /* 当前帧数据长度 */
|
|||
|
|
uint8_t Rx_Buf[Rx_Max] = {0}; /* DMA 接收缓冲区 */
|
|||
|
|
|
|||
|
|
void SystemClock_Config(void);
|
|||
|
|
static void MX_GPIO_Init(void);
|
|||
|
|
static void MX_DMA_Init(void);
|
|||
|
|
static void MX_USART1_UART_Init(void);
|
|||
|
|
static void MX_USART3_UART_Init(void);
|
|||
|
|
static void MX_IWDG_Init(void);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief BootLoader 主函数
|
|||
|
|
*
|
|||
|
|
* 启动流程:
|
|||
|
|
* 硬件初始化 → 启动串口DMA → 打印横幅
|
|||
|
|
* → 等待1秒OTA数据 → 读模式 → 分模式处理 → 跳转APP1
|
|||
|
|
*
|
|||
|
|
* @note BootLoader 不设置 VTOR 偏移(默认0x08000000)
|
|||
|
|
*/
|
|||
|
|
int main(void)
|
|||
|
|
{
|
|||
|
|
HAL_Init();
|
|||
|
|
SystemClock_Config();
|
|||
|
|
MX_GPIO_Init();
|
|||
|
|
MX_DMA_Init();
|
|||
|
|
MX_USART1_UART_Init();
|
|||
|
|
MX_USART3_UART_Init();
|
|||
|
|
|
|||
|
|
/* USART3: 启动 DMA + IDLE 中断接收 OTA 数据帧 */
|
|||
|
|
HAL_UART_Receive_DMA(&huart3, Rx_Buf, Rx_Max);
|
|||
|
|
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
|
|||
|
|
|
|||
|
|
/* 启动独立看门狗:跳转 APP 后由 APP 继续喂狗 */
|
|||
|
|
MX_IWDG_Init();
|
|||
|
|
|
|||
|
|
/* 核心启动逻辑 */
|
|||
|
|
if (W25Q64_Init() != 0) {
|
|||
|
|
log_error("[BL] W25Q64 初始化失败!");
|
|||
|
|
}
|
|||
|
|
Start_BootLoader();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 系统时钟配置: HSE(8MHz) → PLL×9 → 72MHz SYSCLK
|
|||
|
|
*/
|
|||
|
|
void SystemClock_Config(void)
|
|||
|
|
{
|
|||
|
|
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
|||
|
|
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
|||
|
|
|
|||
|
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
|||
|
|
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
|||
|
|
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
|
|||
|
|
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
|||
|
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
|||
|
|
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
|||
|
|
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
|
|||
|
|
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) Error_Handler();
|
|||
|
|
|
|||
|
|
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
|||
|
|
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
|||
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
|||
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
|
|||
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
|
|||
|
|
|
|||
|
|
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) Error_Handler();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief USART1 初始化: 调试日志输出, PA9(TX)/PA10(RX), 115200-8N1
|
|||
|
|
*/
|
|||
|
|
static void MX_USART1_UART_Init(void)
|
|||
|
|
{
|
|||
|
|
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;
|
|||
|
|
if (HAL_UART_Init(&huart1) != HAL_OK) Error_Handler();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief USART3 初始化: OTA 数据通信, PB10(TX)/PB11(RX), 921600-8N1, DMA+IDLE
|
|||
|
|
* @note 波特率与 APP 侧 4G 模块配置(AT+IPR=921600)保持一致
|
|||
|
|
*/
|
|||
|
|
static void MX_USART3_UART_Init(void)
|
|||
|
|
{
|
|||
|
|
huart3.Instance = USART3;
|
|||
|
|
huart3.Init.BaudRate = 921600;
|
|||
|
|
huart3.Init.WordLength = UART_WORDLENGTH_8B;
|
|||
|
|
huart3.Init.StopBits = UART_STOPBITS_1;
|
|||
|
|
huart3.Init.Parity = UART_PARITY_NONE;
|
|||
|
|
huart3.Init.Mode = UART_MODE_TX_RX;
|
|||
|
|
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
|
|||
|
|
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
|
|||
|
|
if (HAL_UART_Init(&huart3) != HAL_OK) Error_Handler();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief DMA 初始化: USART3 RX 使用 DMA1 通道3
|
|||
|
|
*/
|
|||
|
|
static void MX_DMA_Init(void)
|
|||
|
|
{
|
|||
|
|
__HAL_RCC_DMA1_CLK_ENABLE();
|
|||
|
|
HAL_NVIC_SetPriority(DMA1_Channel3_IRQn, 0, 0);
|
|||
|
|
HAL_NVIC_EnableIRQ(DMA1_Channel3_IRQn);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief GPIO 初始化: GPIOA/USART1, GPIOB/USART3 引脚, GPIOD/其他
|
|||
|
|
*/
|
|||
|
|
static void MX_GPIO_Init(void)
|
|||
|
|
{
|
|||
|
|
GPIO_InitTypeDef g = {0};
|
|||
|
|
|
|||
|
|
__HAL_RCC_GPIOD_CLK_ENABLE();
|
|||
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|||
|
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|||
|
|
__HAL_RCC_GPIOC_CLK_ENABLE();
|
|||
|
|
__HAL_RCC_AFIO_CLK_ENABLE();
|
|||
|
|
|
|||
|
|
/* 关闭 JTAG,保留 SWD,释放 PA15/PB3/PB4 给 W25Q64 */
|
|||
|
|
__HAL_AFIO_REMAP_SWJ_NOJTAG();
|
|||
|
|
|
|||
|
|
/* PC13(LED2):外部看门狗 TPL5010 的 DONE 喂狗引脚 */
|
|||
|
|
g.Pin = GPIO_PIN_13;
|
|||
|
|
g.Mode = GPIO_MODE_OUTPUT_PP;
|
|||
|
|
g.Pull = GPIO_NOPULL;
|
|||
|
|
g.Speed = GPIO_SPEED_FREQ_LOW; /* PC13 驱动能力弱,只能低速 */
|
|||
|
|
HAL_GPIO_Init(GPIOC, &g);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 独立看门狗初始化: LSI(~40kHz) / 256分频 / 重载4095 → 超时约26s
|
|||
|
|
* @note LSI 实际频率 30~60kHz 漂移,最短超时约 17s;
|
|||
|
|
* 单个最长阻塞操作(W25Q64 忙等待 5s)远小于该值
|
|||
|
|
*/
|
|||
|
|
static void MX_IWDG_Init(void)
|
|||
|
|
{
|
|||
|
|
hiwdg.Instance = IWDG;
|
|||
|
|
hiwdg.Init.Prescaler = IWDG_PRESCALER_256;
|
|||
|
|
hiwdg.Init.Reload = 4095;
|
|||
|
|
if (HAL_IWDG_Init(&hiwdg) != HAL_OK) Error_Handler();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Error_Handler(void)
|
|||
|
|
{
|
|||
|
|
/* 初始化失败:停在这里,避免带着未就绪的硬件继续运行 */
|
|||
|
|
__disable_irq();
|
|||
|
|
while (1)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
}
|