使用stm32f105rct6的can通信做IAP,实现固件的远程更新功能。IAP的实现包括两个程序:BootLoader和应用程序。启动过程先启动BootLoader,等待1s,若接收到烧写指令则开始更新程序,若无指令则启动应用程序。应用程序接收到更新指令后,切换到BootLoader。
实现IAP流程,需要的工作包括:
1、规划单片机存储区,设置中断向量位置,生成应用程序bin文件
2、编写BootLoader,实现应用程序切换
3、编写远程更新上位机,实现通信协议
1、规划单片机存储区,设置中断向量位置,生成应用程序bin文件
stm32f105rct6的flash共256KB,规划flash空间:
0x08000000~0x08004000 共16KB空间,给BootLoader
0x08004000~0x08010000 共48KB空间,给应用程序
0x08010000~0x08014000 共16KB空间,保留
0x08014000~0x08018000 共16KB空间,给配置
单片机应用程序在起始地址中的结构,首先是中断向量,然后是代码。
中断向量的结构:开头4字节堆栈指针,接下来是4字节reset函数地址,之后是其他中断函数的地址。
单片机开机后,从0x08000000处取得SP,然后从0x08000004处取得reset地址作为PC,在reset函数中调用main函数,进入C语言控制的程序中。
在keil中的options -> target -> IROM 填写应用程序的起始和长度,并在linker -> use memory layout from target dialog中打钩
在应用程序中,调用NVIC函数,设置中断向量位置为0x08004000
生成应用程序的bin文件:
keil中,在options -> user -> after build -> run 中输入指令
fromelf.exe --bin -o ..\w01sim\bin\mcubin\canext.bin .\obj\test.axf
2、编写BootLoader,实现应用程序切换
建立一个普通的stm32工程,实现can通信和数据协议、flash烧写等功能,当超时无指令,或烧写成功后,需要进行程序切换。
程序切换时,首先应关闭设备时钟、关闭中断,避免应用程序中未对设备进行初始化,导致boot方式启动与冷启动有功能差别。
切换原理:模拟单片机上电过程,人工设置堆栈指针,调用应用程序入口函数。
切换代码如下:
1 void switch_2_addr(u32 *pc) //切换到指定的程序指针 2 { 3 u32 i = 0; 4 RCC->APB1RSTR = 0x00000000;//复位结束 5 RCC->APB2RSTR = 0x00000000; 6 7 RCC->AHBENR = 0x00000014; //睡眠模式闪存和SRAM时钟使能.其他关闭. 8 RCC->APB2ENR = 0x00000000; //外设时钟关闭. 9 RCC->APB1ENR = 0x00000000; 10 RCC->CR |= 0x00000001; //使能内部高速时钟HSION 11 RCC->CFGR &= 0xF8FF0000; //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0] 12 RCC->CR &= 0xFEF6FFFF; //复位HSEON,CSSON,PLLON 13 RCC->CR &= 0xFFFBFFFF; //复位HSEBYP 14 RCC->CFGR &= 0xFF80FFFF; //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE 15 RCC->CIR = 0x00000000; //关闭所有中断 16 17 NVIC->ICER[0] = 0xFFFFFFFF; 18 NVIC->ICER[1] = 0x000007FF; 19 NVIC->ICPR[0] = 0xFFFFFFFF; 20 NVIC->ICPR[1] = 0x000007FF; 21 for(i = 0; i < 0x0B; i++) 22 { 23 NVIC->IP[i] = 0x00000000; 24 } 25 __ASM volatile("cpsid i"); //关闭所有中断 26 27 MSR_MSP(*pc); //堆栈指针是应用程序起始的第一个u32 28 ((void (*)(void))*(pc+1))();//入口函数是应用程序起始的第二个u32 29 }
其中MSR_MSP函数如下:
1 __asm void MSR_MSP(u32 addr) 2 { 3 MSR MSP, r0 //set Main Stack value 4 BX r14 5 }
3、编写远程更新上位机,实现通信协议
上位机实现通信协议:
每个程序具有自己的version,16bit,高1字节为程序代号,低1字节为程序发布版本
通信的过程:
1. 控制方发送查询指令,应用程序或BootLoader收到后发送自身version
2. 控制方发送起始指令,指令中带有长度和crc,应用程序收到后,若不准许,则发不准更新包,若准许,则不响应,直接切入BootLoader
3. 控制方持续发送起始指令,BootLoader收到后,回复相同canid的包,准许更新
4. 控制方得到准许后,发送id递增的can包,将bin文件下载到MCU
5. 发送完成后,控制方额外发送一个can id低16bit为0xffff的包,内容为0,表示结束。BootLoader收到后开始计算crc,若失败,则发失败包。若成功,则开始烧写flash,若烧写失败,发送烧写失败包。
6. 烧写成功,BootLoader切换到应用程序,此时控制方一直发查询指令,直到应用程序回复版本号正确。