以下是一个基于STM32H523/H563的串口IAP程序框架,采用USART1作为升级接口。这个程序实现了基本的Flash擦写、应用程序跳转和数据接收验证功能,请根据实际硬件调整引脚和Flash参数。
#include "stm32h5xx.h"
#define APP_ADDR 0x08010000 // 应用程序起始地址
#define FLASH_PAGE_SIZE 2048 // H5系列Flash页大小(2KB)
void SystemClock_Config(void);
void USART1_Init(void);
void FLASH_ErasePage(uint32_t addr);
int main(void) {
// 初始化
HAL_Init();
SystemClock_Config();
USART1_Init();
// 检查是否跳转到APP
if((*(volatile uint32_t*)APP_ADDR & 0x2FFE0000) == 0x20000000) {
// 设置向量表
SCB->VTOR = APP_ADDR;
// 跳转到应用程序
void (*app_entry)(void) = (void (*)(void)) * (volatile uint32_t*)(APP_ADDR + 4);
app_entry();
}
// IAP主循环
uint8_t rx_buffer[256];
while(1) {
uint8_t cmd = USART_ReceiveByte(); // 自定义接收函数
if(cmd == 0xC0) { // 开始传输指令
uint32_t file_size;
USART_ReceiveData((uint8_t*)&file_size, 4);
// 计算需要擦除的页数
uint32_t pages = (file_size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
// 擦除Flash
FLASH_ErasePage(APP_ADDR);
// 接收并写入数据
uint32_t addr = APP_ADDR;
for(uint32_t i = 0; i < file_size; i += sizeof(rx_buffer)) {
uint16_t chunk = (file_size - i) < sizeof(rx_buffer) ?
(file_size - i) : sizeof(rx_buffer);
USART_ReceiveData(rx_buffer, chunk);
FLASH_Program(addr, rx_buffer, chunk);
addr += chunk;
}
// 发送成功响应
USART_SendByte(0xA0);
}
}
}
// Flash页擦除
void FLASH_ErasePage(uint32_t addr) {
HAL_FLASH_Unlock();
FLASH_EraseInitTypeDef erase = {
.TypeErase = FLASH_TYPEERASE_PAGES,
.Page = (addr - FLASH_BASE) / FLASH_PAGE_SIZE,
.NbPages = 1
};
uint32_t fault;
HAL_FLASHEx_Erase(&erase, &fault);
HAL_FLASH_Lock();
}
// Flash编程
void FLASH_Program(uint32_t addr, uint8_t *data, uint32_t len) {
HAL_FLASH_Unlock();
for(uint32_t i = 0; i < len; i += 8) {
uint64_t word = *(uint64_t*)&data[i];
HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, addr + i, word);
}
HAL_FLASH_Lock();
}修改链接脚本(.ld文件):
MEMORY {
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 192K /* 前64KB留给IAP */
}main函数开头添加向量表重定位:
int main(void) {
// 中断向量表重定位
SCB->VTOR = 0x08010000;
// ...其他初始化
}| 指令 | 方向 | 说明 |
|---|---|---|
| 0xC0 | PC→MCU | 开始升级 |
| [4字节] | PC→MCU | 固件大小(小端格式) |
| [固件数据] | PC→MCU | 二进制文件内容 |
| 0xA0 | MCU→PC | 升级成功响应 |
| 0xE1 | MCU→PC | 擦除失败 |
| 0xE2 | MCU→PC | 编程失败 |
时钟配置:
RCC_OscInitTypeDef osc = {
.OscillatorType = RCC_OSCILLATORTYPE_HSE,
.HSEState = RCC_HSE_ON
};
HAL_RCC_OscConfig(&osc);串口配置(USART1):
void USART1_Init(void) {
__HAL_RCC_USART1_CLK_ENABLE();
USART1->BRR = HAL_RCC_GetHCLKFreq() / 115200; // 波特率
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE;
}Flash保护配置:
HAL_FLASH_Unlock();
HAL_FLASH_OB_Unlock();Flash安全:
防变砖措施:
// 在APP中设计返回Bootloader的入口
void Enter_Bootloader(void) {
__disable_irq();
*((volatile uint32_t*)0x2000FFF0) = 0xDEADBEEF; // 标记内存
NVIC_SystemReset();
}
// IAP启动时检查标记
if(*((volatile uint32_t*)0x2000FFF0) == 0xDEADBEEF) {
*((volatile uint32_t*)0x2000FFF0) = 0; // 清除标记
// 留在IAP模式
}固件校验:
// 接收完成后添加CRC校验
if(Calculate_CRC(APP_ADDR, file_size) != expected_crc) {
USART_SendByte(0xE3); // CRC错误
}
注意:实际使用时需要根据开发板调整以下内容:
- USART引脚配置(PA9/PA10等)
- 系统时钟配置
- Flash大小和页地址
- 协议细节(超时处理、分包大小等)
建议参考STM32CubeH5官方库中的IAP示例工程,路径:
STM32Cube_FW_H5_Vx.x.x/Projects/STM32H5xx-Nucleo/Applications/IAP
举报
更多回帖