LV16-27-内部Flash-04-IAP编程实现
本文主要是STM32开发——IAP编程实现的一些相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows | windows11 |
Ubuntu | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
SecureCRT | Version 8.7.2 (x64 build 2214) - 正式版-2020年5月14日 |
开发板 | 正点原子 i.MX6ULL Linux阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
STM32开发板 | 正点原子战舰V3(STM32F103ZET6) |
点击查看本文参考资料
- 通用
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.st.com/content/st_com/zh.html | ST官方网站,在这里我们可以找到STM32的相关文档 | |
https://www.stmcu.com.cn/ | 意法半导体ST中文官方网站,在这里我们可以找到STM32的相关中文参考文档 | |
http://elm-chan.org/fsw/ff/00index_e.html | FatFs文件系统官网 | |
教程书籍 | 《ARM Cortex-M3权威指南》 | ARM公司专家Joseph Yiu(姚文祥)的力作,中文翻译是NXP的宋岩 |
《ARM Cortex-M0权威指南》 | ||
《ARM Cortex-M3与Cortex-M4权威指南》 | ||
开发论坛 | http://47.111.11.73/forum.php | 开源电子网,正点原子的资料下载及问题讨论论坛 |
https://www.firebbs.cn/forum.php | 国内Kinetis开发板-野火/秉火(刘火良)主持的论坛,现也做STM32和i.MX RT | |
https://www.amobbs.com/index.php | 阿莫(莫进明)主持的论坛,号称国内最早最火的电子论坛,以交流Atmel AVR系列单片机起家,现已拓展到嵌入式全平台,其STM32系列帖子有70W+。 | |
http://download.100ask.net/index.html | 韦东山嵌入式资料中心,有些STM32和linux的相关资料也可以来这里找。 | |
博客参考 | http://www.openedv.com/ | 开源网-原子哥个人博客 |
http://blog.chinaaet.com/jihceng0622 | 博主是原Freescale现NXP的现场应用工程师 | |
cortex-m-resources | 这其实并不算是一个博客,这是ARM公司专家Joseph Yiu收集整理的所有对开发者有用的官方Cortex-M资料链接(也包含极少数外部资源链接) |
- STM32
STM32 | STM32 HAL库开发实战指南——基于F103系列开发板 | 野火STM32开发教程在线文档 |
STM32库开发实战指南——基于野火霸道开发板 | 野火STM32开发教程在线文档 |
- SD卡
SD Association | 提供了SD存储卡和SDIO卡系统规范 |
点击查看相关文件下载
STM32F103xx英文数据手册 | STM32F103xC/D/E系列的英文数据手册 |
STM32F103xx中文数据手册 | STM32F103xC/D/E系列的中文数据手册 |
STM32F10xxx英文参考手册(RM0008) | STM32F10xxx系列的英文参考手册 |
STM32F10xxx中文参考手册(RM0008) | STM32F10xxx系列的中文参考手册 |
Arm Cortex-M3 处理器技术参考手册-英文版 | Cortex-M3技术参考手册-英文版 |
STM32F10xxx Cortex-M3编程手册-英文版(PM0056) | STM32F10xxx/20xxx/21xxx/L1xxxx系列Cortex-M3编程手册-英文版 |
SD卡相关资料——最新版本 | 有关SD卡的一些资料可以从这里下载 |
SD卡相关资料——历史版本 | 有关SD卡的一些历史版本资料可以从这里下载,比如后边看的SD卡2.0协议 |
SD 2.0 协议标准完整版 | 这是一篇关于SD卡2.0协议的中文文档,还是比较有参考价值的,可以一看 |
一、APP应用程序制作
STM32 的 APP 程序不仅可以放到 FLASH 里面运行,也可以放到 SRAM 里面运行, 我们使用的STM32F103ZET6有512KB的FLASH和64KB的SRAM,FLASH的地址为 0x0800 0000 ~ 0x0807 FFFF,内部SRAM的地址为 0x2000 0000 ~ 0x2000 FFFF。
1.APP起始地址设置
1.1 FLASH中运行
- 【Options for Target】→【Target】
默认的条件下,图中 IROM1 的起始地址(Start)一般为 0x0800 0000,大小(Size)为 0x80000,即从 0x08000000 开始的 512K 空间为我们的程序存储(因为我们的 STM32F103ZET6 的 FLASH大小是 512K)。
而当前图中,我们设置IROM1的起始地址(Start)为 0X0801 0000,即偏移量为 0X10000(64K 字节)。因而,留给 APP用的 FLASH 空间(Size)为0x80000 - 0x10000= 0x70000(448K字节)。
设置好 Start 和 Szie,就完成 APP 程序的起始地址设置。这里的 64K 字节,需要我们根据 Bootloader 程序大小进行选择,理论上我们只需要确保 APP 起始地址在 Bootloader 程序之后,并且偏移量为 0x200 的倍数即可(为什么是0x200的倍数?NVIC的向量表偏移寄存器设置问题(已解决)-OpenEdv-开源电子网)。这里我们选择 64K(0x10000)字节,留了一些余量,可以方便 Bootloader 以后的升级修改。 我们编译完成后,可以看一下它的sct文件:
1 | ; ************************************************************* |
1.2 SRAM中运行
若APP在SRAM中运行的话,我们设置的方式也类似:
这里我们将 IROM1 的起始地址(Start)定义为: 0x20001000,大小为 0xC000(48K 字节),即从地址 0x20000000 偏移 0x1000 开始,存放 APP 代码。因为整个 STM32F103ZET6 的 SRAM大小为64K字节,所以 IRAM1( SRAM )的起始地址变为 0x2000D000( 0x20001000 + 0xC000=0x2000D000 ),大小只有 0x3000 ( 12K字节 )。
这样,整个STM32F103ZET6 的 SRAM 分配情况为:最开始的 4K 给 Bootloader 程序使用,随后的 48K 存放 APP 程序,最后12K,用作 APP 程序的内存。这个分配关系我们可以根据自己的实际情况修改,不一定和这里的设置一模一样,不过也需要注意,保证偏移量为 0X200 的倍数(我们这里为 0X1000)。我们看一下它的sct文件:
1 | ; ************************************************************* |
1.3 设置成功判定
那怎么知道设置后是否成功呢?我们可以看存储器映像中的信息,就是前边学习FLASH时说过的 .map 文件中的 Memory Map of the image 部分:
1 | Image Entry point : 0x08000131 |
需要注意的是,有时候我们更改了 IROM1 后,这里并没有任何变化,此时我们需要修改这里:
重新设定之后,重新编译查看即可。
2. 中断向量表偏移
在系统启动的时候,会首先调用 SystemInit() 函数初始化时钟系统,同时SystemInit() 还完成了中断向量表的设置,我们可以打开 SystemInit() 函数,看看函数体的结尾处有这样几行代码
1 | /** |
从这里可以看出VTOR寄存器存放的是中断向量表的起始地址。默认的情况 VECT_TAB_SRAM 是没有定义,所以执行:
1 | SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; |
另外,SystemInit()函数的执行是在启动文件的复位中断中:
1 | ; Reset handler |
【注意】
(1)这里只是举一个例子,看一下中断向量表怎么设置,后边直接设置这个 SCB->VTOR 即可。
(2)FLASH中APP和SRAM中APP的中断向量表地址设置与前边APP偏移地址相关联,注意要跟前边对应。
2.1 FLASH 中运行
对于 FLASH中的APP,我们设置为 FLASH_BASE+偏移量 0x10000,所以我们可以在 FLASH中APP 的 main 函数最开头处添加如下代码实现中断向量表的起始地址的重设:
1 | SCB->VTOR = FLASH_BASE | 0x10000; |
2.2 SRAM中运行
当使用 SRAM APP 的时候, 我们设置起始地址为:SRAM_BASE + 0x1000,同样的方法,我们在 SRAM APP 的 main 函数最开始处,添加下面代码:
1 | SCB->VTOR = SRAM_BASE | 0x1000; |
这样,我们就完成了中断向量表偏移量的设置。
3. bin文件的生成
3.1 生成工具
我们使用的 MDK 默认生成的文件是 .hex 文件,并不方便我们用作 IAP更新,我们希望生成的文件是 .bin 文件,这样可以方便进行 IAP 升级。MDK 自带的格式转换工具 fromelf.exe,可以实现 .axf 文件到 .bin 文件的转换。该工具在 MDK 的安装目录的这个文件夹下:
1 | windows 下的路径格式 |
fromelf.exe 转换工具的语法格式为:
1 | fromelf [options] input_file |
其中 options 有很多选项可以设置 ,其他的没有研究过,这里就直接用下边的命令格式即可(这是我当时安装MDK的路径):
1 | C:\LenovoSoft\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin -o ..\OBJ_dir\xxx.bin ..\OBJ_dir\xxx.axf |
3.2 MDK配置
- (1)确认生成的可执行文件名和输出文件的文件夹路径
- (2)添加命令
1 | C:\LenovoSoft\Keil_v5\ARM\ARMCC\bin\fromelf.exe --bin -o ..\OBJ\TOUCH.bin ..\OBJ\TOUCH.axf |
- (3)编译工程
编译整个工程,编译结束后,我们会看到如下提示:
然后我们就可以看到生成的 .bin 文件啦。
4. APP生成总结
(1)设置 APP 程序的起始地址和存储空间大小。对于在 FLASH 里面运行的 APP 程序和 SRAM 里面运行的 APP 程序,他们的设置类似,但是要注意各个地址。
(2)设置中断向量表偏移量。主要就是APP的main函数中设置 SCB->VTOR 的值 。
(3)设置编译后运行 fromelf.exe,生成 .bin 文件。通过在 User 选项卡,设置编译后调用 fromelf.exe,根据.axf 文件生成.bin 文件,用于IAP 更新。
二、Bootloader编写
前边我们已经完成了APP的制作,那么现在要做的就是通过Bootloader程序将APP程序写入到相应的地址,并跳转执行。
1. APP程序跳转
1.1 函数指针
1 | typedef void (*pIAPFunc)(void); //定义一个函数类型的参数. |
jump2app是一个函数指针变量,可以指向一个不含参数,且无返回值的函数。
1.2 重设栈顶指针
重新设置栈顶指针,因为STM32启动的时候就需要获取栈顶指针,防止堆栈溢出,设置栈顶指针的话需要使用汇编,我们可以自己实现:
1 | /** |
后来发现,其实STM32的核心标准文件中已经为我们实现了相关的设置栈顶指针的函数,它在 cmsis_armcc.h 文件中,函数实现如下:
1 | /** |
注意,这个函数在 cmsis_gcc.h 文件中也有一个,注意不要包含错头文件了。
1.3 跳转实现
1 | /** |
第9行:校验一下即将运行的APP的栈顶指针是否位于内部SRAM区域。
第11行:将函数指针指向应用程序的起始起始地址,这里的起始地址应该是app应用程序的基地址再加4个字节,加上四个字节后,这个函数指针就指向了app应用程序的复位中断向量子程序。
第12行:设置栈顶的地址,为C语言运行提供环境,app的基地址存储的就是栈顶地址。
第13行:就相当于执行函数,执行了复位中断子程序,之后便会进入应用app的main死循环中。
2. APP程序接收
我们这里通过串口来接收APP应用程序(.bin)文件。这里只列出部分关键代码。
1 | //注意,读取USARTx->SR能避免莫名其妙的错误 |
我们指定 USART_RX_BUF 的地址是从 0X20001000 开始,该地址也就是 SRAM中APP程序的起始地址。 然后串口1的中断服务程序(USART1_IRQHandler() 函数)里面,将串口发送过来的数据,全部接收到 USART_RX_BUF,并通过 USART_RX_CNT 计数,这样接收数据的同时,还可以获取整个文件的大小。不过这里这个55KB太大了,很有可能造成我们的代码内存不够用,编译都通不过,所以Bootloader的代码也不能做太多的功能,只要能完成基本的程序的接收和写入还有跳转就可以了。
3. APP程序写入
3.1 APP写入内部FLASH
若是这是一个FALSH中的APP,我们就还需要将该 .bin 文件写入到FLASH相应的地址中去。
1 | uint16_t iapbuf[1024]; |
该函数用于将FLASH APP写入到FLASH中指定的区域中。internalFLASH_Write()函数需要自己实现,具体可以看Hardware/internalFlash.c · sumumm/STM32F103-Prj - 码云 - 开源中国 (gitee.com)
3.2 APP写入内部SRAM
由于我们通过串口直接将接收到的数据写入了内部SRAM中,且SRAM中运行的APP我们在设置地址的时候,跟串口接收写入的地址是一致的,所以这里并不需要将 .bin 文件再写入到SRAM,我们可以直接跳转运行。
4. APP执行实例
4.1 执行FLASH中的APP
1 | //执行FLASH APP |
4.2 执行SRAM中的APP
1 | // 执行SRAM APP |