0 引言
对于一个项目而言,往往将远程升级作为程序的最后一步(基本所有功能都开发完成之后再考虑)。但是在我看来,我们在写单片机的程序之前,就要规划好FLASH的使用情况,因为code、全局变量等重要信息都是放在FLASH(常说的闪存)中的,SRAM是程序运行时的存放位置。
- 关于OTA部分已经有很多前辈分享过经验了,这篇博客我只是从我个人的角度以及做过的实验出发,将自己学到的一些经验和收获做一下分享。
- 后面我也想把 STM32CubeMX + KEIL + 常见外设使用 总结成一个专栏,记录下自己踩的坑,帮助大家少走点弯路。
关于OTA参考的博客、视频如下(感谢前辈们):
- STM32CubeMx开发之路—在线升级OTA
- STM32F103的存储器映射&寄存器映射
- 正点原子-第197讲 提高篇 IAP
- 本篇博客采用的单片机型号为:STM32F103ZET6;软件IDE: keil + STM32CubeMX
1 预备知识
在讲述OTA之前,我们必须要知道STM32存储器映射、程序是怎样开始运行的、串口的IAP是如何实现的,下面我们开始解释(有些借鉴了正点原子网课老师的):
1.1 STM32存储器映射:
此知识点可参考下面的网站(写的都非常好):
- STM32单片机不同boot模式的本质
- STM32F1(Cortex M3内核)存储器映射
对于内核为ARM Cortex-M3的单片机,其存储器映射如下图所示:
M3内核是上述的那样,供给不同厂家进行开发,比如以ST公司的STM32F1系统为例,其规定的存储器映射关系为:
我们的代码以及全局变量的一些值就是放在FLASH中最下面的那部分,
另外需要注意的一些点:
(1)32为单片机可以有32根地址线(每根导线:0 or 1), 所以内存2^32 = 4GB,故寻址范围是0x0000 0000 - 0xFFFF FFFF;
(2)单片机内存访问的地址是按字节编址的(而不是bit);
1.2 程序是如何开始执行?
1、问题1:我们在看程序的时候是从main函数开始看起的,但是单片机是如何从main开始运行的呢?
答:STM32的分为3种启动模式:
我们需要把这两个图对照着看:
- 根据硬件所接的电平确定启动模式(我们平时的boot1和boot0在硬件中都是接地的):
- 主闪存存储器启动:从内置的FLASH中启动,我们平时通过JLink或者SWD下载程序时就是现在到这里面 (直接在Keil IDE里面下载);
- 系统存储器启动:从系统存储器(0x1FFF F000 ~ 0x1FFF F7FF,就是那个2K的厂家的bootloader程序),ST自带的这个bootloader引导程序可以帮助用户通过串口下载到系统的FLASH中;
- 片上SRAM启动:因为本身它是没有存储能力的,所以一般用于程序调试。
2、问题2:说到这个地方大家可能还会有一些疑问:对于Block 0 中的FLASH或系统存储器别名区这个是啥,怎么给他分配那么大的内存?
参考: 基于STM32从零写操作系统系列—bootloader
- 这段区域在ST提供的数据手册中表示Boot MemorySpace(Aliased to Flash or systen memory depending onBOOT pins),注意这块区域是预留的,不存数据,在不同的启动模式下,这块区域会被映射到其他区域:
- 只有SRAM、主闪存存储器、系统存储器是真实存在的实体,而Aliased memory并不是存储器,它只是一个地址空间,根据不同的BOOT启动方式,系统将另外三个映射过来。
- 例如,如果BOOT方式是从【Main Flash memory】启动,则CPU访问0x0000 0000处的一个字就等于访问0x0800 0000处的一个字,访问0x0000 0004处的一个字节就等于访问0x0800 0004处的一个字。。。所以从本质上来说,无论哪种启动模式,CPU总是在0x00000000处找到中断向量表,取出向量表的第一元素(32bits)作为MSP(main stack pointer)的值, 取出第二个元素(32bits)作为PC(程序计数器)寄存器的值,而中断向量表的第二个元素总是复位(Reset)异常的中断处理函数,因此CM3单片机上电后总是会先执行Reset_Handler函数。三种启动模式只是将各自存储空间映射到地址 0x0000 0000 。也并不是将实际存储器的内容拷贝到【Aliasd memory】,而是【Aliasd memory】是对应存储器的一个别名,访问【Aliasd memory】就等价于访问他们。(https://blog.csdn.net/luliplus/article/details/124392543)
- 中断向量表到底在哪里,你说在0x00000000处绝对没问题,而当BOOT方式选择从Main Flash memory启动时,你说在0x08000000也是没问题的。
在实际运行过程中,程序在偏移到main函数之前做了很多操作,所以我们需要了解STM32的启动过程:
3、问题3:那能不能用程序说明,系统就是这样运行的呢?
答:其启动的流程如下图所示:
如何会到达main函数那里?
中断服务函数定义:
堆栈定义:
- 堆(Heap):程序员分配和释放,如malloc、calloc、realloc等;
- 栈(Stack):编译器自动分配和释放,存放函数参数和局部变量等;
故整体的步骤如下所示:
单片机复位后,初始化堆栈指针MSP = _initial_sp, PC = Reset_Handler; 然后执行Reset_Handler函数,在这个函数中配置系统时钟,最后调用C库函数__main(main函数并不是main函数)初始化堆栈,从而最终调用用户编写的main函数
1.3 什么是IAP(In Application Programming, 在应用编程)
使用用户的应用程序(自定义bootloader程序)对FLASH进行烧录。该应用程序需要通过某种通信接口对闪存进行烧录,通常用于远程升级等。在无IAP程序升级时,STM32程序启动过程如下图所示:
有了IAP部分后,STM32启动过程如下图所示,一开始系统还是会执行到main函数上面,其中IAP的部分是指 :在main函数中开始接收新文件,并把新的文件存到FLASH的其他位置。新程序的复位中断向量需要进行偏移中断向量表的起始地址,从而重新执行上图中的过程。但是这是需要注意的是如果发生了中断请求还是跳转到原来为偏移的中断向量表中,然后再根据我们设定的中断向量表的偏移实现中断。
就是需要自己写bootlaoder程序,然后还有app1程序。
- bootloader程序中:跳转代码
- app1程序中:中断向量表偏移
1.4 OTA升级
对于OTA起始就是IAP的升级版,思路基本相同,下面这位前辈已经讲的非常清楚了,请参考:
- STM32CubeMx开发之路—在线升级OTA
他是采用了Ymodem串口传输协议实现升级,当然我们可以采用Wi-Fi,蓝牙等各种协议,只要能收到文件并将其写道FLASH中即可。文章来源:https://www.toymoban.com/news/detail-763998.html
推荐给大家的学习方法是:先去上面这个博客里面看懂OTA的原理,然后跟着我下面的博客去做实验验证即可。文章来源地址https://www.toymoban.com/news/detail-763998.html
2 后续
- 小张也快到找工作的时间,前面断更时间太久了(
后台有些私信因为太忙忘记回了),从今天开始认真整理,希望和明年秋招有意向嵌入式软开的小伙伴们一起努力,小张也申请了一个博客网站:格子格鸽的个人博客,后面再CSDN和博客网站上会同步更新的。 -
在这个网站我会分享的技术栈知识(嵌入式软件开发岗位):
- C语言基础(小张还没考计算机二级,今年9月份必拿下);
- C++基础(后面的算法选的语言);
- 408: 计算机网络(结合LWIP来学习);操作系统(结合freeRTOS、MIT 6.S081课程);数据结构与算法(看B站视频和刷题);计算机组成原理(ARM Cortex-M3、ARM Cortex-M4内核相关)
- STM32外设和Cortex内核相关的东西,结合小张看到的面经;
- 项目相关(最近对很想玩墨水瓶等东西,会分享做一些好玩的小东西),做一些电子人专属浪漫的事情。
- 个人的技术周总结、月总结等。
- 现在整体形势确实不好,我非常理解大家的焦虑因为很多时候我也是这种状态,认识我觉着我们还是要把心沉下来,脚踏实地,当我们把一个一个小的点做好,结果不会差的。我老师经常告诫我的一句话分享给大家“不要太看重一天内做的事情,但也不要忽略1个月能做的事”。小张希望自己和小伙伴们一起坚持、一起成长,不断成长为一个技术更好、视野更广阔的嵌入式软件开发工程师。
- 我的博客是:
[格子格鸽的个人博客](https://xichenzhang.com/)
到了这里,关于STM32-OTA升级-基于STM32CubeMX+STM32F103(一)基础知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!