你们好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给你们分享的是利用IAR自带CRC完整性校验功能的一次实践(为KBOOT加BCA)。javascript
痞子衡以前写过两篇关于IAR中自带CRC校验功能的文章 《在IAR开发环境下为工程开启CRC完整性校验功能的方法》、《探析开启CRC完整性校验的IAR工程生成.out和.bin文件前后顺序》,算是把这个功能细节介绍得比较清楚了,可是俗话说得好,理论懂得再多,不能用于实践那等于没学。今天痞子衡就利用这个功能来解决一个实际需求:html
提及这个需求,记得那是2014年的第一场雪,那时候痞子衡正在飞思卡尔软件组参与Kinetis Bootloader项目(简称KBOOT)的研发,痞子衡为这个项目写过一些文章,详见 《飞思卡尔Kinetis系列MCU开发那些事》 里的启动篇系列,Kinetis是飞思卡尔当时主推的Cortex-M微控制器,KBOOT就是为Kinetis设计的全功能Bootloader,这多是嵌入式世界里第一个精心设计的通用架构Bootloader。这个Bootloader包含一个用户配置功能(BCA),简单说就是在用户Application的偏移0x3c0 - 0x3ff这16个word存放一些Bootloader配置,当Bootloader运行时会先尝试从Application区域读出这16个word,获取用户配置(超时时间、外设类型、id、速度选项等),而后根据用户配置再去启动或升级用户Application。java
CRC完整性校验功能占据了BCA里的12个byte,是一个很重要的Bootloader特性,其完整功能详见 《KBOOT特性(完整性检测)》,今天痞子衡要说的需求就是直接在Application工程编译时生成包含正确CRC相关参数的BCA,而不是像之前那样在最终binary文件里二次编辑添加。算法
咱们以MK64FN1M这颗芯片为例,下载它的软件包,软件包里有KBOOT及其示例Application,找到 \SDK_2.8.2_FRDM-K64F\boards\frdmk64f\bootloader_examples\demo_apps\led_demo_freedom_a000\iar 下的Application工程,工程源文件 startup_MK64F12.s 里定义了__bootloaderConfigurationArea,可是CRC区域是全0xFF(即没有使能),编译生成的bin文件里CRC区域也是全0xFF,咱们要作的就是填入正确的CRC。数组
在KBOOT用户手册里能够找到其CRC具体算法,它使用的是比较主流的CRC32-MPEG2分支,具体参数以下表所示:微信
为了方便核对结果,痞子衡找了一个在线CRC计算的网站,利用这个网站,设置与KBOOT一致的CRC参数(下图红色框内),而后咱们选取led_demo_freedom_a000.bin的前16个字节(下图蓝色框内)做为测试数据输入,点击Calculate CRC按钮生成结果0x8D96BDF0(下图紫色框内)。架构
在线网站: http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
咱们如今回到led_demo_freedom_a000工程,在Linker/Checksum下,使能CRC功能,为了与上述测试一致,CRC计算范围设为 0xa000 - 0xa00f(由于程序起始连接地址是0xa000,因此也就是最终.bin里的前16个字节)。查阅IAR development手册,作了以下CRC算法参数设置,编译工程获得结果也是0x8D96BDF0,所以CRC设置是匹配的。app
确认了CRC设置,如今就是修改源代码了,在BCA的CRC区域里将初始的0xFF值所有更换为真实的CRC设置值__checksum、__checksum_begin、__checksum_end,代码简单修改以下。重编工程后查看.bin文件,发现起止范围两个参数是对的,可是CRC校验值并不对,填成了0x0000a7fc,查看map文件得知这是__checksum的连接地址,并非__checksum的值。想一想也是,CRC校验值是连接生成bin后才计算的,但源文件是在连接前编译的,不可能在编译时获得连接后的结果。dom
- Note: 上图中有笔误,左边汇编代码第306行应更改成(__checksum_end - __checksum_begin + 1),由于这是crcByteCount,下同。
首次尝试失败,事情远没有想象得那么简单,咱们须要在工程连接文件上动心思,要直接把__checksum连接到BCA里的具体偏移位置。所以startup_MK64F12.s 里__bootloaderConfigurationArea从crcExpectedValue及其以后所有去掉,而且__FlashConfig也实际不须要(仅对于连接在0地址才有效,这是Kinetis特性)。测试
而后咱们须要从新在main.c里定义一个bca常量数组,把除crcExpectedValue以外缺失的BCA数据所有放进去。
const uint32_t bca[16] @ ".bca_left" = {0x1388ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff};
最后咱们须要修改连接文件MK64FN1M0xxx12_application_0xA000.icf以下:
//place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec, readonly section .noinit }; //place in FLASH_region { block ApplicationFlash }; place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; place at address mem:0xa3cc { ro section .checksum }; place at address mem:0xa3d0 { ro section .bca_left }; place in FLASH_region { readonly section .noinit, block ApplicationFlash };
通过这么一番操做,让咱们从新编译工程再看bin里结果,哈哈,此次BCA果真是正确的CRC校验值了(此次值是0xf62ce2b6,发生了变化,由于源代码的改动,bin前16个字节内容也相应变化了),大功告成。底下的事情就简单了,在CRC设置界面里调整想要的CRC计算范围便可。
至此,利用IAR自带CRC完整性校验功能的一次实践(为KBOOT加BCA)痞子衡便介绍完毕了,掌声在哪里~~~
文章会同时发布到个人 博客园主页、CSDN主页、知乎主页、微信公众号 平台上。
微信搜索"痞子衡嵌入式"或者扫描下面二维码,就能够在手机上第一时间看了哦。