完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1、前言
上一篇 单片机 IAP 功能基础开发篇之APP升级(一)讲到了单片机 IAP 功能给 APP 程序升级的设计思路,这篇介绍的是具体实现方式。 下一篇 单片机 IAP 功能基础开发篇之APP升级(三) 1.1、目的 本文所写的是如何不通过下载器的方式实现单片机中的程序更新,目前介绍的是 STM32 的 BootLoader 简易设计方案(便于初步理解)。 2、设计方案 2.1、升级方式 在开发单片机的 bootloader 功能时,首先需要选择通过什么样的方式进行升级,在单片机 IAP 功能基础开发篇之APP升级(一)介绍了三种升级方式,该篇先介绍串口通信升级方式。 选定升级方式后,就需要选择串口通信协议,这里我们可以选择 Modbus通讯协议(当然,可以自己定义协议,这样更快,但是需要对应的上位机也支持该协议)。 选择Modbus通讯协议的原因:2.2、分区划分 升级方式选定后,则需要划分 Bootloader 和 app 的 Flash 空间,分别用来存放 bootloader 和 app 的程序,在没有开发 bootloader 之前,整个 Flash 都可以是 app 的程序空间。 以 STM32F103ZET6 为例,STM32 的 flash启动地址为 0x0800 0000,则根据下表进行划分(分区大小可根据芯片内存大小自行决定): [tr] MCU分区 描述 起始地址 大小备注[/tr]
首先了解 STM32 芯片上电的时候,首先会从内存地址位 0x0800 0000(由启动模式决定)的地方加载栈顶地址(4字节),从 0x0800 0004 的地方加载程序复位地址(4字节),然后跳转到对应的复位地址去执行。2.2.1、编译器设置 Bootloader 和 app 属于两个独立的工程,不是一个工程!!! 独立的工程意味着程序可以独立运行(将两个工程的起始地址设置 0x0800 0000),不受另一个工程影响,只是程序的功能不一样。
2.2.1、APP 程序有效标志 程序启动后,首先进入 bootloader 程序中,再跳入APP 程序中,如果APP 程序不存在,则一直在bootloader 中等待升级;那么,如何识别 APP 程序是否存在或者有效呢? 通常升级 APP 程序后,即通过 bootloader 烧录 APP 程序后,会在 APP 中的指定位置设置标志,然后 bootloader 去检查该标志是否有效。为确保该标志不影响 APP 可执行程序,一般放在 APP可执行程序之后。 可执行程序包括:代码、初始化数据段和未初始化数据段等不仅仅只是代码目前不清楚APP可执行程序的结束地址怎么办? 可以在 APP 程序预留分区的最后地址预留 4 个字节的标志位,标志可设置为 0x5a5a(该方式每次擦除 APP 程序时必须将 APP 分区全部擦除,否则该标志就没有意义)。2.3、流程图 2.4、Bootloader 设计 2.4.1、初始化 初始化和正常没有bootloader 的程序一下,该咋样就咋样,为了避免无效功耗损失,一般是需要什么就初始化什么。
2.4.2、检查APP 程序是否存在 初始化完成后,首先检测 APP 分区中最后地址的标志位是否符合(如是否等于0x5a5a),如果符合,启动倒计时(时间大约几百毫秒就行,根据实际情况决定),等待进入 APP 程序,在此期间,也会等待接收升级的指令;否则,则一直等待接收升级的指令。 2.4.3、升级 接收到升级指令后,则启动升级流程,升级期间不允许进入 APP 程序。升级流程如上流程图 2.4.3、跳转APP程序 升级完成后,需要跳转到 APP 程序(可以自动跳转,也可以增加跳转指令手动跳转),跳转前的准备:
当然,也能直接跳转到 APP 程序的 main 函数,但在跳转前需要重新初始化堆栈等内容,所以最好还是交给启动文件处理2.5、App 设计 2.5.1、初始化 APP 程序初始化之前,需要重定向中断向量表。 重定向中断向量表的原因:由于 bootloader 占用了原来的芯片中断向量表地址,为了防止进入 APP 程序区后产生的中断进入 bootloader 的中断处理程序,所以需要重新定向到 APP 程序的中断向量表。重新定向中断向量表后,重新清除所有中断标志为,接着就可以正常初始化,正常执行了。 2.5.1、热启动升级 什么?APP 程序还能跳转 bootloader? 是的,当然可以,有两种方式:跳转的目的是?都执行 APP 程序了,还跳转回去干嘛,闲的? 目的是为了下发升级固件时不需要冷启动(单片机重新上电),即在 APP 程序中需要实现接收升级准备指令(避免误触发,通常时一定时间接收到多少升级准备指令),然后通过上述的方式进入 bootloader 执行升级,不需要再像 51 单片机一样下载程序还需要重新上电才能下载。3、代码片段 3.1、APP 跳转代码片段 #define APP_FLASH_CODE_BASE 0x08008000 #define APP_FLASH_CODE_SIZE 0x78000 int CheckIfAPPCanJump(void) { uint32_t *pFlag = (uint32_t *)(APP_FLASH_CODE_BASE + APP_FLASH_CODE_SIZE - 4); if (*pFlag == 0x5A5A) { return 1; } return 0; } void JumpJumpApplication(void) { typedef void (*iapfun)(void); /* 定义一个函数类型的参数 */ iapfun jump2app; if (CheckIfAPPCanJump()) /* 检测APP应用程序段是否可正常跳转 */ { __disable_irq(); /* 全局中断关闭 */ jump2app = (iapfun)*(vu32*)(APP_FLASH_CODE_BASE + 4);/* 用户代码区第二个字为程序开始地址(复位地址) */ MSR_MSP(*(vu32*)APP_FLASH_CODE_BASE);/* 初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址) */ jump2app(); /* 跳转到APP */ } } 3.2、重定向中断向量表 void SetVectorTable(void) { uint8_t i; SCB->VTOR = APP_FLASH_CODE_BASE; /* 清除所有中断标志 */ for(i= 0; i < CRS_IRQn; i++) { NVIC_ClearPendingIRQ((IRQn_Type)i); } /* 在BOOT中跳转之前关闭了全局中断, 因此需要重新打开 */ __enable_irq(); } |
||||
|
||||
只有小组成员才能发言,加入小组>>
3209 浏览 9 评论
2896 浏览 16 评论
3402 浏览 1 评论
8844 浏览 16 评论
3997 浏览 18 评论
9627浏览 3评论
1004浏览 3评论
520浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
523浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2247浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-9-29 23:49 , Processed in 0.990895 second(s), Total 82, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号