STM32网络在线升级(OTA)完整实现指南
一、概述
STM32在线升级(OTA – Over The Air)是一种通过网络远程更新设备固件的技术。本文将详细介绍基于STM32F4系列的网络升级方案,包括Bootloader设计、Flash分区、升级流程和完整代码实现。
二、系统架构
2.1 Flash分区设计
STM32 Flash Memory Layout:
┌─────────────────────┐ 0x08000000
│ Bootloader │ (32KB)
├─────────────────────┤ 0x08008000
│ Application │ (224KB)
├─────────────────────┤ 0x08040000
│ OTA Buffer │ (224KB)
├─────────────────────┤ 0x08078000
│ Config Data │ (32KB)
└─────────────────────┘ 0x08080000
2.2 升级流程
三、Bootloader实现
3.1 Bootloader主程序
// bootloader.c
#include \”stm32f4xx_hal.h\”
#include <string.h>
// Flash分区定义
#define BOOTLOADER_BASE 0x08000000
#define APPLICATION_BASE 0x08008000
#define OTA_BUFFER_BASE 0x08040000
#define CONFIG_BASE 0x08078000
#define APPLICATION_SIZE (224 * 1024)
#define OTA_BUFFER_SIZE (224 * 1024)
#define FLASH_PAGE_SIZE 2048
// 升级标志结构
typedef struct {
uint32_t magic; // 魔术字 0xDEADBEEF
uint32_t update_flag; // 升级标志 1:需要升级
uint32_t firmware_size; // 固件大小
uint32_t crc32; // CRC32校验值
} ota_config_t;
// 函数声明
static void jump_to_application(uint32_t address);
static int check_application_valid(uint32_t address);
static HAL_StatusTypeDef flash_erase(uint32_t start_addr, uint32_t size);
static HAL_StatusTypeDef flash_write(uint32_t dest_addr, uint8_t *src, uint32_t size);
static uint32_t calculate_crc32(uint8_t *data, uint32_t size);
static int perform_firmware_update(void);
// CRC32计算
static uint32_t calculate_crc32(uint8_t *data, uint32_t size) {
CRC_HandleTypeDef hcrc;
uint32_t crc = 0;
__HAL_RCC_CRC_CLK_ENABLE();
hcrc.Instance = CRC;
HAL_CRC_Init(&hcrc);
crc = HAL_CRC_Calculate(&hcrc, (uint32_t*)data, size/4);
return crc;
}
// 检查应用程序有效性
static int check_application_valid(uint32_t address) {
uint32_t sp = *(__IO uint32_t*)address;
// 检查栈指针是否在RAM范围内
if ((sp & 0x2FFE0000) == 0x20000000) {
return 1;
}
return 0;
}
// 跳转到应用程序
static void jump_to_application(uint32_t address) {
typedef void (*pFunction)(void);
pFunction jump_to_app;
uint32_t jump_address;
// 获取复位向量
jump_address = *(__IO uint32_t*)(address + 4);
jump_to_app = (pFunction)jump_address;
// 设置主栈指针
__set_MSP(*(__IO uint32_t*)address);
// 关闭所有中断
__disable_irq();
// 复位所有外设
HAL_DeInit();
// 设置向量表
SCB->VTOR = address;
// 跳转到应用程序
jump_to_app();
}
// Flash擦除
static HAL_StatusTypeDef flash_erase(uint32_t start_addr, uint32_t size) {
FLASH_EraseInitTypeDef erase_init;
uint32_t sector_error;
uint32_t sector_start, sector_end;
// 解锁Flash
HAL_FLASH_Unlock();
// 计算起始和结束扇区
sector_start = (start_addr – FLASH_BASE) / FLASH_PAGE_SIZE;
sector_end = (start_addr + size – FLASH_BASE) / FLASH_PAGE_SIZE;
erase_init.TypeErase = FLASH_TYPEERASE_SECTORS;
erase_init.Sector = sector_start;
erase_init.NbSectors = sector_end – sector_start + 1;
erase_init.VoltageRange = FLASH_VOLTAGE_RANGE_3;
// 执行擦除
if (HAL_FLASHEx_Erase(&erase_init, §or_error) != HAL_OK) {
HAL_FLASH_Lock();
return HAL_ERROR;
}
HAL_FLASH_Lock();
return HAL_OK;
}
// Flash写入
static HAL_StatusTypeDef flash_write(uint32_t dest_addr, uint8_t *src, uint32_t size) {
uint32_t i;
HAL_FLASH_Unlock();
// 按字写入
for (i = 0; i < size; i += 4)





