更新2026-11这篇是早期的参考例程版解决“能跑起来”。后面我把实际踩过的坑补成了另一篇三重 CRC32 校验怎么设计、Flash 分区怎么算、四道校验为什么不能换顺序——都是把设备变砖之后才想明白的。两篇配合看这篇给能跑的代码那篇讲为什么这么设计MM32 IAP 在线升级实战三重 CRC32 是怎么设计出来的附 27 型号源码与移植清单以下是关于MM32单片机IAPIn Application Programming程序升级的参考例程信息包含源码、通信协议和上位机工具的相关内容硬件与开发环境MCU型号MM32全系列如MM32F0140、MM32G0005等需确认具体型号匹配例程。开发工具Keil MDK/IAR/MM32官方IDE建议使用最新版本支持包。通信接口通常通过UART/USART/USB/I2C等实现IAP需硬件支持。IAP基本原理Bootloader设计存储在MCU起始地址如0x08000000负责接收新固件并写入应用程序区。应用程序跳转Bootloader通过判断Boot flag跳转到应用程序入口如0x08004000。参考源码结构Bootloader部分int main(void) { uint8_t flag[4]; uint16_t len; FLASH_Read(flag, BootJumpFlagAddress, 4); if ((flag[0] 0x55) (flag[1] 0xAA) (flag[2] 0xAA) (flag[3] 0x55)) // 如果用户程序有效则跳转到用户程序执行用户程序。 { // Reset_Periph();//跳转之前需要关闭boot初始化过的外设避免导致跳到APP里面后boot里面的外设仍然在工作 __disable_irq(); __set_MSP(*(u32 *)ApplicationAddress); // 设置SP.堆栈栈顶地址 ((void (*)(void)) * (u32 *)(0x04 ApplicationAddress))(); // 生成跳转函数.将复位中断向量地址做为函数指针 } PLATFORM_Init(); UART_Configure(115200); while (1) { if (USART_RX_STA 0x8000) { len USART_RX_STA 0x7FFF; boot_protocol(UART_RxBuff, len); USART_RX_STA 0; } } }Boot Jump Flag信息存储区在Flash空间定义了1K信息存储区目前例程只实现了一个Boot Jump Flag的存储当Bootloader启动后先读取这个Boot Jump Flag如果是0x55, 0xAA, 0xAA, 0x55则直接跳转到Application如果不是则运行Bootloader升级程序等待升级。后续可以对这个工程进行完善比如信息存储区间添加Bootloader程序区间校验码和Application程序区间校验码上电后两段区间校验通过程序才会继续运行保证系统的稳定性顺便多提有点如果在这个工程上修改成自己的程序如果程序跳转到APP后需要升级那需要把这1K信息存储区擦除后复位即可。if ((flag[0] 0x55) (flag[1] 0xAA) (flag[2] 0xAA) (flag[3] 0x55)) // 如果用户程序有效则跳转到用户程序执行用户程序。 { // Reset_Periph();//跳转之前需要关闭boot初始化过的外设避免导致跳到APP里面后boot里面的外设仍然在工作 __disable_irq(); __set_MSP(*(u32 *)ApplicationAddress); // 设置SP.堆栈栈顶地址 ((void (*)(void)) * (u32 *)(0x04 ApplicationAddress))(); // 生成跳转函数.将复位中断向量地址做为函数指针 }应用程序部分MM32F5270/MM32F5330 STAR-MC1内核的需修改链接脚本.sct文件将程序起始地址设置为非Bootloader区域。其他M0/M0/M3内核则可以直接修改Keil 工程Option - Target 修改Flash RAM分配跳转到Application后Coretx-M0 内核需要把中断向量表copy到RAM然后配置SYSCFG_CFGR嵌入式RAM映射到 0x0000 0000。如果是Coretx-M0/Cortex-M3/Cortex-M4/STAR-MC1 内核则可以直接配置SCB-VTOR将中断向量表直接偏移//Coretx-M0 #define APPLICATION_ADDRESS (uint32_t)(0x08001400) // APP START ADDRESS #define VECTOR_SIZE 0xC0 // M0 要把APP的向量表转移到SRAM memcpy((void *)0x20000000, (void *)APPLICATION_ADDRESS, VECTOR_SIZE); // Enable the SYSCFG Peripheral Clock RCC_APB1PeriphClockCmd(RCC_APB1ENR_SYSCFG, ENABLE); // Remap SRAM at 0x00000000 将SRAM中的向量表映射到0x0000000 SYSCFG_MemoryRemapConfig(SYSCFG_MemoryRemap_SRAM); __enable_irq(); //Coretx-M0/M3/STAR-MC1 #define APP_ADDRESS_OFFSET 0x1400 SCB-VTOR FLASH_BASE | APP_ADDRESS_OFFSET; //M0可以对中断向量进行偏移这样app的中断可以直接跳到自己的中断服务函数 __enable_irq();//跳转之后要确保打开总中断通信协议帧格式示例自定义协议链接里面带自定义通讯协议文档同时还有配套的上位机软件#define GET_VERSION 0x20#define ERASE_APP 0x21#define SYSTEM_RESET 0x22#define WRITE_APP 0x23#define VERIFY_APP 0x24#define CLEAR_FLAG 0x25#define WRITE_FLAG 0x26#define SEG_STARTADDR 0x27 // 因支持hex文件多段下载特需此指令#define MCU_INFO 0x28 // 上位机获取MCU分给APP空间大小和APP存放的起始位置void boot_protocol(u8 *buff, u16 len) { u8 cmd; memcpy(sendbuff, buff, len); buff sendbuff; if (Check_data(buff)) { memcpy(buff, USB_Return_Err, 0x40); UART_SendGroup(buff, Send_Size); return; } cmd buff[0]; switch (cmd) { case GET_VERSION: getVersion(buff); break; case ERASE_APP: eraseAppSpace(buff); break; case SYSTEM_RESET: resetMCU(buff); break; case WRITE_APP: appCodeDownload(buff); break; case VERIFY_APP: appVerify(buff); break; case CLEAR_FLAG: clearAppFlag(buff); break; case WRITE_FLAG: writeAppFlag(buff); break; case SEG_STARTADDR: segmentInfo(buff); break; case MCU_INFO: mcuInfo(buff); break; default: break; } }CMD: 升级指令Packet length:数据长度Data 通讯数据CRC: CRC16校验资源获取开源链接https://gitee.com/skydiver/mm32-iap-demo建议结合具体MM32型号的参考手册确认Flash分区大小和通信外设配置。开发时优先测试Bootloader与应用程序的独立功能再整合联调。本文基于 Gitee 开源仓库 mm32-iap-demoV2.0整理源码版权归原作者Skydiver所有。
阅读完成 · 觉得有帮助?