bootloader 使用注意事项

发布于 2020-12-18 12:19:19 字数 2469 浏览 1492 评论 0

keil 链接选项

// 全局设置
#define D_FLAGADDR      0xFFF0							// 存储全局升级标志(可选)
#define D_MCU           D_V98XX							// MCU类型
#define D_FRAMELEN  	16							    // 每帧的数据长度
#define D_ADRESSMODE    D_ABSOLUTE					    // 寻址模式
#define D_READCHECK		D_FALSE						    // 读出比对
#define D_TIMETH        (30)                            // *50ms
// note* bootloader位于flash中的最后10k_(10或20页)(0xD800-0xFFFF),其中0xFE00页用于保存用户程序的入口地址
#if (D_MCU == D_V98XX)
    #define D_SECTORSUM		0x6c						// 128-20页
    #define D_SECTORSIZE	0x200 						// 每页大小,V98xx是512个字节 中颖7012是1024个字节
#endif
#if (D_MCU == D_SH7012)
    #define D_SECTORSUM		0x36 						// 64-10页
    #define D_SECTORSIZE/	0x400 						// 每页大小,V98xx是512个字节 中颖7012是1024个字节
#endif

#define D_FRAMENUM		(D_SECTORSIZE/D_FRAMELEN)	    // 传输一页数据需要的总帧数

其中 D_FLAGADDR 是作为升级标志的全局标志位,位于 xdata 区,在用户程序接受到升级指令后需要将该位置写入数据 0x55。后续增加对IO口的支持。

关于中断处理

由于 IAP 的机制要求中断进行响应,而C51程序中的代码首页放置的就是 STARTUP 与各个中断入口的地址,一旦对首页 0000-0200 的 512 字节进行擦除或者写操作,就会导致IAP中断无法响应MCU一直处于挂起状态,所以为了避免这种情况必须保证首页不被擦除或改写,因此提前将中断入口地址固定,保证后面升级的程序中断入口地址不变。否则中断程序的跳转将指向错误的地址,同时为每个中断函数预留了一定的空间,方便用户添加简单的中断处理代码。

为了实现这点,必须将 IAP 所在的中断进行中断跳转处理,这会导致中断在响应的时候会慢至少一个 LJMP 指令,但是对于目前主频达到十几兆的增强型 51 来说是可以忽略不计的。

如何实现

因为 IAP 中断不可擦出,中断服务函数同样应该位于不可擦出段,因此可将该段代码定位在 bootloader 代码的开始。在IAP中断服务函数中跳转至中断映射代码,同样中断映射代码的函数地址同样需要固定,但是是可擦出的。

  • 0x0000-0x03FF: 中断向量表
  • 0x0400-0x05FF: 512 字节的出厂参数,单片机正常工作所必须的参数,不用于用户代码。
  • 0x0600-0xD4FF: 用户代码
  • 0xD500-0xD6FF: 中断映射代码
  • 0xD700-0xD7FF: 启动代码
  • 0xD800-0xFFFF: bootloader 代码

中断服务函数绝对定位地址

     EXINT0SEG    =0xC500-0xC5FF
     TIMER0SEG    =0xC600-0xCBFF
     EXINT1SEG    =0xCC00-0xCCFF
     TIMER1SEG    =0xCD00-0xCDFF
     TIMER2SEG    =0xCE00-0xCEFF
     UART1SEG     =0xCF00-0xD1FF
    *UARTCFSEG    =0xD200-0xD3FF
     UARTRTCSEG   =0xD400-0xD4FF
     PLLEXINT3SEG =0xD500-0xD5FF
     TIMERASEG    =0xD600-0xD6FF
     POWERSEG     =0xD700-0xD7FF

其中,UARTCFSEG 实际并不是由中断向量直接指向,而是中断服务函数的一个子函数,因为 UARTCF 中断包含 IAP 中断,所以这部分的代码处在不可擦除区

非常重要的一点

因为bootloader是和用户代码放在同一个工程下,对于常量尤其是函数内部的字符串常量,编译器在编译的时候可能会把这部分常量放进用户代码区,导致升级之后这部分变量会被更改。解决方法:

  • 尽量少使用常量尤其是字符串常量
  • bootloader 代码中使用的所有变量,不要使用默认初始值也不要使用声明的同时赋值的用法;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

已经忘了多久

文章 0 评论 0

15867725375

文章 0 评论 0

LonelySnow

文章 0 评论 0

走过海棠暮

文章 0 评论 0

轻许诺言

文章 0 评论 0

信馬由缰

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文