基于STM32F103RBT6和V3.5固件库的Boot升级与APP回跳 总结心得 这是我第一次写Bootloader,之前也只听说过这个,一直没有去做过。由于在网上看到的都是千篇一律的手册介绍,很少有干粮。为了后人少走弯路,故写下这篇文章,还望多指教。整个学习与编写分为三个过程:理论学习、学习例程以及动手编写代码; 学习期间主要看了原子哥的串口IAP程序以及ST官方例程。由于STM32F103RBT6的SRAM只有20K,因此无法通过数组接收数据。我们采用的方案是串口中断接收,每满一页数据就写入一页,这样对SRAM的要求比较低。 首先,明确要实现的功能: 1) Bootloader中升级APP; 2) APP运行过程中回跳到Bootloader; 3) 我们系统的升级框架如下: 一、Boot升级1. 为什么要用Bootloader? 我认为,在一定程度上选用Bootloader能够方便我们产品在量产后方便升级更新。当然还有就是觉得比较高大上吧~ 2. 为什么要用hex文件升级,而不用bin文件? 很多人采用的是bin文件升级,而我们采用的是hex文件。之所以要选用hex文件升级的原因有很多,最重要的是hex的文件格式的特点。Hex文件是一行一行的,便于接收,而bin文件是二进制数据流。 详细的格式可以直接找度娘。我这仅简述一下我们用到的一些特点: 1) hex文件是一行一行的数据;可以用记事本或者UE打开看; 2) 每行数据组成为:’:’(行首)+Byte0(本行数据长度) + Byte1(本行数据起始地址MSB) + Byte2(本行数据起始地址LSB)+ Byte3(数据类型)+…(数据内容)+ Bytex(本行数据校验和) 3) 数据类型为0x01即表示此行代码为hex文件的最后一行。(文件结束) 3. hex校验和怎么计算? Hex文件行尾为本行的校验和,校验和=0x100-累加和;累加和为从Byte0到校验和前一个字节数据的累加值(此处应注意,我们只取低16位) 4. 需要哪些基础知识? 基础知识主要还是参考CM3的手册 1) Bootloader简单的说就是接收升级文件,然后把升级文件写进Flash中,最后程序跳转到APP; 2) STM32中小容量是1K为1页,而大容量则是以2K为1页;同时,STM32的写保护的基本单位是4K。官方手册上说的是“对于小容量和中容量的产品为4页;对于大容量的产品为2页。” 3) 其他的有关中断向量之类的理论请查阅手册。我就不在此赘述了。 5. 对Flash怎么操作? 通过Boot升级,对Flash的操作主要包括四部分: 1) 解锁Flash 通常情况下,我们为了防止程序被修改,会将Flash上锁;通过Boot升级时需要往Flash中写入数据,因此我们需要解锁Flash。通过调用库函数中的FLASH_Unlock()对Flash解锁。FLASH_Unlock()中主要是打开FPEC模块。FLASH_KEYR寄存器中写入的KEY1=0x45670123,KEY2 = 0xCDEF89AB。错误的操作序列都会在下次复位前锁死FPEC模块和FLASH_CR寄存器。 2) 擦除Flash 由于我们参考了ST官方给出的例程,可以调用ymodem.c文件中的Erase_DataFlash()实现擦除Flash数据。 3) 写Flash 通过调用ymodem.c文件中的write_one_page来实现一页数据的写入。 4) 上锁Flash 在操作完Flash后,需要对Flash上锁,同时在跳转前,需要关闭所有中断。 6. 如何实现? 通过上面讲述基本上对Bootloader会有一个较为清晰的认识;下面讲述其详细实现过程: 1) 在IAR环境下,设置产生HEX文件,OptionàOutput ConverteràOutput format选择Intel extended,详细过程请百度IAR环境下如何生成hex文件; 2) 设置Flash写入首地址,改地址就是APP的起始地址,在BOOT跟APP程序中一定要对应起来,我们选用的APP地址为0x8002000开始。 3) 设置一页数据的大小,我们设置的为1024。 4) 解析图像发送过来的数据;图像发送给我的数据为“命令头+长度+设备号+内容+命令尾” 5) 当接收到得命令尾“K”则跳出循环,直接跳转到APP运行;若接收到的数据为“I”,则给图像发送“I”,表示我已经收到“I”,可以升级; 6) 当收到“I”后,发送“C”,让图像板发送hex文件头; 7) 解析文件头,看文件头是否跟我匹配,匹配则正式进入升级,若不匹配,则返回“E”,退出升级; 8) 解锁Flash,擦除Flash数据,随后发送“C”让图像发送下一行数据给我; 9) 将接收到得数据合并、重排,并进行校验和,若校验正确,则保存数据,发送“C”;若错误,则让图像重发,发送“E”; 10) 一边接收一遍判断数据类型,若为0x01,则把当前已经缓存的数据写入Flash,跳转到12)步骤;若不是,跳转到11)步骤; 11) 判断当前接收数据是否满一页,若满一页则将缓存的数据写入Flash,跳转到9)步骤;若没满一页,则将接收到的数据缓存下来,跳转到9)步骤; 12) Flash上锁,关中断,跳转到APP 二、APP回跳到Boot在APP程序中,当接收到指令‘B’,我们需要跳转到Boot程序中进行升级;在此,提出两种方案,一是与boot类似的回跳,二是软件复位; 两种方法我都试了,但是,通过回跳方式跳过去以后MCU卡死,这个不知道怎么解决;因此最后选用软件复位方式,实现的; void SoftReset(void) { __set_FAULTMASK(1); // 关闭所有中端 NVIC_SystemReset();// 复位 } 该函数调用的两个子函数都为ST提供的(V3.5固件库)
|