打印
[应用相关]

基于TCP的STM32 IAP bootloader初步设计

[复制链接]
1018|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
跟屁虫|  楼主 | 2015-9-30 09:21 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
好久没有写东西,前段时间发生了不少事情,现在终于能静下心来。停下脚步望望曾经的自己,一路走来,对技术的**是多么的可贵。人的时间是有限的,作为一个嵌入式工程师,对新技术的热爱和好奇心将产生前进的驱动力。至于可以达到怎样的高度,全看个人的执行力和自我约束,兴趣常常是最好的导向。        最近研究了下IAP bootloader的实现方法,这在产品设计中是非常有用的。所谓IAP就是在线应用编程,可以用于远程程序升级。比如我们设计了一个产品,使用较为复杂的工艺被封装在精美的外壳中,或者被用于偏远的场景,如果在使用过程中需要修改程序,使用烧写器烧写是非常麻烦的,费时费力。真正的工业产品几乎都会有自己的bootloader。
       其实,实现自己的bootloader在原理上并不复杂,就是通过MCU的接口把外部新的程序文件烧写到其内部的flash中,然后去运行新程序。以前怎么也没想过如何在同一个flash里面运行毫无关系的两个程序,bootloader就可以实现。其核心跳转代码就只有三行:
app_program = (void(*)())((*(__IO uint32_t*)(ApplicationAddress+4)));

     __set_MSP(*(__IO uint32_t*) ApplicationAddress);//初始化堆栈指针

     app_program();//跳转到app程序去执行
其中ApplicationAddress,是应用程序在flash中存储的地址,ApplicationAddress+4就是复位中断向量地址,因为程序最开始都是去执行复位中断函数的。在这之前,先用一张图说明下stm32的正常启动过程。下图很好的说明了arm的启动过程,以及程序在flash中的存储方式:


沙发
跟屁虫|  楼主 | 2015-9-30 09:21 | 只看该作者
对于这个启动过程,我相信图上画的已经很明白了,也可以在很多文档中看到,我就不再赘述了。当然这个是bootloader的运行方式,现在我们还有一个app程序,放在了flash的另外一个区域。使用上述三行代码可以实现跳转,如下图所示:
     其中下面的那部分就是APP的存储结构以及运行过程。其过程也不再赘述。有了这个思路作为指导,就可以完成我自己的bootloader了。
     之所以选择TCP的升级方式,我觉得一是升级速度快,二是利用了原设备现有的网口,比较方便,在现有uIP协议栈的基础上实现一个TCP Server,用于接收上位机发来的二进制文件。涉及到数据交互,就要选择相应的交互协议,用的比较多的是1K—Xmodem协议。由于这是一个初级版本,以简单起见先用分包发送的方式实现,稍后在使用1K—Xmodem协议,再做诸多改进。这个简单的思路是,在点击下载程序后,先于bootloader进行握手,成功后使用上网机软件将APP BIN文件读入,然后分成1024大小的数据包发送给bootloader,每发完一个包,bootloader就写入flash,这样只占用1K的内存,即使对一个小型stm32芯片也可以实现,而不是一次性读到内部的ram后再编程flash。
     基于这个思路我做了一些实验,出现了一些问题。
     问题1,arm收到上位机下发一个数据包后马上写入flash,再返回ack,读写flash会占用较长的时间,造成上位机发送超时,引起重发。
     其实,完全可以arm收到一个数据包后立即应答,之后在下个数据包发来之前写入flash中去。
     问题二、把一包1024字节的数据写入flash后,我定义的很多全局变量被莫名奇妙的编程了FF,导致了程序运行错误。
     我想了两个晚上都不知原因。后来看flash函数才发现,原来flash是按块进行读写的,写入数据前先要整个数据块读出来,而这个函数声明了一个一块大小的局部数组,居然有2048这么大!大家都知道局部数组是放在内存的栈上的,而stm32在启动文件中定义的栈只有1K大小!在存储一包1024大小的数据到flash时栈过小,造成泄露,覆盖了分配在堆上的全局变量!把启动文件中栈大小改为Stack_Size      EQU     0x00002000,一共为8192字节,可以解决上述问题。

使用特权

评论回复
板凳
跟屁虫|  楼主 | 2015-9-30 09:22 | 只看该作者
这样,我的BIN文件就可以存入flash中去了,我定义的首地址为0x08010000,也就是给bootloader留出了64KBytes的空间,我的bootloader编译完一共26K,足够了。     可以我又遇到了第三个问题:写完后居然不能执行!我通过jlink把flash中0x08010000地址上的数据读出与BIN文件对比,发现有些数据是错的!
   
                                       通过jlink烧写的app程序        通过上位机少进去的程序
     原来,是上位机打开BIN文件的方式不对。上位机软件使用C#编写,打开BIN文件起先使用的是StreamReader,后来查到应该使用BinaryReader。原来StreamReader是按照asc码的定义来解析,如果没有对应的asc码,就会出现乱码,而造成了某些字节的错位。读取文件改为BinaryReader方法就可以了,看看这几天的成果吧。

      下一步计划:使用X-Modem协议实现数据的交互,添加异常处理机制,保证数据传输的可靠性,以及bootloader的稳定性。

使用特权

评论回复
地板
mmuuss586| | 2015-9-30 09:37 | 只看该作者

谢谢分享

使用特权

评论回复
5
BitFu| | 2015-9-30 14:55 | 只看该作者
STM32F103C8T6+ENC28J60+UIP 做过BOOTLOADER的路过
http://www.chipart.cn/projects/casboot.asp

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

245

帖子

2

粉丝