STM32 IAP串口固件升级方案及上位机调试助手提供
·
stm32 iap串口升级固件方案,提供上位机调试助手
最近在玩STM32远程升级功能的时候,发现用串口实现IAP(应用内编程)真是个经济实惠的方案。今天咱们就手把手搞个能实战的升级系统,配合自己写的上位机工具,直接撸代码说重点。
先甩个Bootloader的核心跳转代码:
void jump_to_app(uint32_t app_addr)
{
typedef void (*pFunction)(void);
pFunction Jump_To_Application;
__disable_irq(); //关闭全局中断
HAL_DeInit(); //复位外设
uint32_t stack_pointer = *(volatile uint32_t*)app_addr;
__set_MSP(stack_pointer); //设置主堆栈指针
Jump_To_Application = (pFunction)(*(volatile uint32_t*)(app_addr + 4));
__enable_irq(); //打开中断
Jump_To_Application();
}
这段代码的关键在于操作MSP指针和PC指针。注意在跳转前必须复位所有外设,否则残留的中断标志可能导致程序跑飞。实际项目中建议在跳转前关闭所有开启的外设时钟。
stm32 iap串口升级固件方案,提供上位机调试助手
上位机这边用C#写个带进度条的串口助手,核心发送逻辑:
private void SendFirmware(byte[] binData)
{
int packetSize = 256;
byte[] packet = new byte[packetSize + 5];
for(int i=0; i<binData.Length; i+=packetSize)
{
packet[0] = 0xAA; //帧头
packet[1] = (byte)(i >> 24);
packet[2] = (byte)(i >> 16);
packet[3] = (byte)(i >> 8);
packet[4] = (byte)i;
int len = Math.Min(packetSize, binData.Length - i);
Buffer.BlockCopy(binData, i, packet, 5, len);
byte crc = CalcCRC8(packet, 5 + len);
serialPort.Write(packet, 0, 5 + len);
serialPort.Write(new byte[]{crc}, 0, 1);
UpdateProgress(i * 100 / binData.Length); //更新进度条
}
}
协议里加了位置索引和CRC校验,防止传输错位。实际测试发现,波特率115200时每包256字节比较稳定,上位机记得要加50ms的发送间隔。
应用工程要做两个关键设置:
- 修改ld文件把起始地址后移
MEMORY
{
FLASH (rx) : ORIGIN = 0x08004000, LENGTH = 224K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 40K
}
- 在main函数开头重设中断向量表
SCB->VTOR = FLASH_BASE | 0x4000; //与ld文件中的偏移量一致
踩过几个坑值得注意:
- 升级完成后必须软复位而不是直接跳转,否则RCC寄存器可能残留错误配置
- 建议在Flash末尾保留2KB空间存储升级标志位
- 遇到跳转失败时,检查是不是开了看门狗没喂狗
- 用STM32CubeProgrammer提取的hex文件需要转成纯bin文件
最后整个流程跑起来是这样的:
- 设备收到升级指令,写入标志位后重启
- Bootloader检测到标志位,进入等待升级模式
- 上位机发送带校验的固件包
- 完成写入后校验整个固件CRC32
- 跳转前擦除标志位,确保升级成功可回退
实测用F103C8T6芯片,升级128KB固件约35秒完成。想要更快速度可以试试DMA接收,不过对资源有限的芯片来说,普通中断接收模式已经够用。代码仓库里已经放了配套的工程文件,需要的老铁自取。

更多推荐


所有评论(0)