原创 C8051单片机BootLoader心得

2009-6-26 13:00 10497 12 17 分类: MCU/ 嵌入式

C8051单片机BootLoader心得


       8051至今仍占据着MCU的大量市场,以其通用、价格低廉等众多原因而被学校和大多公司作为微控制开发的首选。随着ARM等32位控制器的出现,使得8051的追随者对于其使用编程器烧片子的方式逐渐的难以接受。不论是从易用性、以及程序的可靠性来说,都添加了诸多不便。


       此时很多人想到了ARM中常用的BootLoader得概念,其实这是一个很好的方法。要想在MCU中实现BootLoader,首先要求单片机具有IAP功能,或是可以对其自身的FLASH进行擦除、写入的功能。其次要考虑FLASH的空间,毕竟加入一个boot的代码是需要付出代价的。


       下面以C8051F340为例说明一下我的心得与体会。


1. 整体规划




分区


作用


说明


中断向量区


中断向量保存


1.1


APP区


应用程序区


1.2


BOOT区


BootLoader代码存放区


1.3


1.1中断向量区


       中断向量区提供复位以及异常中断的跳转, 鉴于51的特点,这部分必须存放在0地址开始的区域。


1.2 APP区


       应用程序区存放用户应用程序,亦即boot操作区。这部分可以存放在FLASH的任意区域。下载程序时,bootloader需要将下载的数据写入该区。正常启动时,bootloader需要让CPU跳转至此执行。


1.3 BOOT区


       BootLaoder代码存放区。这部分可以存放在FLASH的任意区域。 


2. 实现方法




地址


作用


说明


0000H -- 0002H


Boot入口地址


2.1


0003H -- D_APP_LIMIT


APP程序


2.2


D_RUN_ADDRESS


APP入口地址


2.3


D_BOOT_ADDR


Boot程序


2.4


2.1 Boot入口地址


       8051上电后执行的第一条便是0x0000—0x0002处的指令,考虑到程序的通用性,此处必须跳转到Boot 程序区,以便从boot开始引导或是装入程序。


STARTUP.A51文件中:


CSEG    AT      0


?C_STARTUP:       LJMP    STARTUP1


这两条语句便是实现了程序的跳转。


?C_STARTUP的地址是链接时确定的,但是必须要在Boot程序区。关于制定Boot区的位置请参考2.3。


2.2 APP程序


应用程序区必须放在0地址开始的分区!由于8051的局限性,他基本不能像其他系统一样可以将代码拷贝到RAM中,之后重建中断向量表执行。


为了中断向量表的跳转方便,介意将应用程序烧写到0地址开始的分区,但是要注意:应用程序的前三个字节要写到D_RUN_ADDRESS指向的APP入口地址(见2.3)。


// APP入口地址写入


       for (i=0; i<3; i++) {      


              flash_write(D_RUN_ADDRESS+i, dat);


       }


       // 程序区


       for (i=3; i<size; i++) {


              flash_write(i++, dat);


       }


2.3 APP入口地址


       Boot下载程序后,前三个字节为APP的入口地址,Boot启动时APP,就是跳转到这个地址的。


       我的实现中,将此三个字节放到了一个独立的分区,这样方便操作,但是有点浪费。呵呵!


// APP入口地址写入


       for (i=0; i<3; i++) {      


              flash_write(D_RUN_ADDRESS+i, dat);


       } 


Boot启动过程中,其实就是实现了跳转:


       Reset(0x0000) à D_BOOT_ADDR  (Boot正常启动)à D_RUN_ADDRESS (APP运行)


                                                    (Boot下载程序)à进入Loader模式


       这样在程序每次启动中,总是先执行Boot代码,是其具有通用性。


2.4 Boot程序


       此处为Boot程序区,在此我采用检测IO的方法,这样不像检测终端输入那样存在等待时间的问题。软件的下载采用串口。具体步骤如下:


第一步,MCU复位后,从0地址跳转到BOOT区。


       第二步:Boot代码检测是否存在Loader使能按键,若不存在直接跳转到第四步。


第三步:与用户进行软件握手,握手成功后按照如下步骤操作:


1.       暂存boot入口地址(第0扇区的前三哥字节),这样在擦除第0扇区后可以回写。


2.       准备扇区,擦除APP程序扇区和APP入口地址扇区。


3.       回写boot入口地址(1中读出的三个字节)。


4.       通知主机发送代码,我使用DNW发送,数据格式为:4Byte(数据长度)+数据+2Byte(校验和)


5.       读接收数据长度,4Byte。


6.       开始接收数据, 同时写入Flash APP区。此时注意FLASH写入时间和串口速度的匹配。一般来说115200的速度足够了。


这部分数据分为两部分:接收到的前三个字节为APP的入口地址,需要单独保存。


7.       读校验和,校验数据。


这样在线编程完毕。


       第四步:读取APP入口地址处是否存在有效指令(一般判断是否为0x02),不存在则等待用户复位!


3. 结语


       BootLoader作为程序的主体,需要考虑代码的链接位置以及代码量的大小,我们可以用如下方法在KEIL中控制CODE的位置,


      


       上图中,我设定Boot代码存放在0xEA00开始的Flash区。这样程序编译完后,可以发现除中断向量外,其他部分代码均在0xEA00之后。


中断向量的控制,由于8051中断向量的特殊性,不介意在BootLoader中使用中断,例如我的串口就是使用查询方式实现的。8051不支持中断向量的重映射,所以使用中断会给自己增加负担。我觉得,BootLoader稳定是最重要的!


以上是我开发C8051F340 BootLoader的一些体会,供同行参考。


【2008-10-17】

PARTNER CONTENT

文章评论5条评论)

登录后参与讨论

用户377235 2012-12-30 16:55

对我现在做的毕业设计很有指导作用,谢谢您分享到心得!!

nneverli_217963090 2009-8-3 11:25

不错

用户1156376 2009-8-1 00:18

代码我已发到: http://blog.ednchina.com/zhurunping/247804/message.aspx 请参阅!

用户1666358 2009-7-31 13:48

你好,我现在也正在用C8051F340,正发愁如何进行串口升级程序呢,所以你能不能提供给我例程源码,十分感谢.我的邮箱shuolang@126.com

用户518079 2009-7-25 09:38

谢谢分享!
相关推荐阅读
用户1156376 2014-08-18 17:23
[博客大赛]MDK下代码的分段管理 续3
继续写点分段管理的问题。 设计思想主要是设计一个通用的BSP,固化后只需要修改APP代码就可以,这适用于远程升级的系统或是进行二次开发的系统。 考虑到编译器链接的时候会把没有使用的代码段(...
用户1156376 2014-02-27 18:14
Freescale MCU SPI
Freescale S12 SPI: 0. 以下所述为查询模式使用SPI 1. SPI控制器有两个中断, 数据发送(SPTEF)和数据接收(SPIF) 2. 数据发送(SPTEF)标志...
用户1156376 2014-02-26 09:17
Freescale MCU摘记
仅用于记录Freescale的点滴记录: 1. 把AD口用作IO口的方法: 除了正常的设置外,还需要把 ATDDIEN 寄存器写为0xFF, 这样使能了数字IO。否则默认为AD输入。 ...
用户1156376 2013-12-14 11:33
[STM32]MDK下代码的分段管理 续2
前文所述的代码分段,限定比较大,对于使用 #pragma arm section code=".ARM.__at_0x8100000" 固定地址的方式,每个文件都需要指定不同的地址以区别。...
用户1156376 2013-12-09 18:12
[STM32]MDK下代码的分段管理
编译大型的程序时,可能某一段代码固定之后不再改变(比如BSP),而应用部分经常修改。在这种情况下,如果使用在线升级或是Bootloader的方式升级程序时,你就觉得每次升级的代码有一部分是重复的(...
用户1156376 2012-10-14 09:10
【uCOS-III移植笔记】OS启动过程
(1) 关闭系统中断 (2) CPU_Init(); 初始化CPU服务(时间戳、中断时间测量、CPU信息初始化等) (3) OSInit(); 初始化系统(系统变量、系统任务...
EE直播间
更多
我要评论
5
12
关闭 站长推荐上一条 /3 下一条