STM32F407学习IAP时的笔记

前言

最近学习IAP,出现诸多问题,这是当时最初了解的基础知识,抱着学习的心态,有错的大佬请指正。勿喷

一.启动模式

在中文参考手册中被称为自举模式,也称为boot模式。
芯片复位后在一定数量的时钟后,通过锁存BOOT1和BOOT0引脚的电平,根据不同的电平组合选择不同的启动方式。
STM32F407有三种启动方式:
STM32F407学习IAP时的笔记_第1张图片
1.主FLASH启动,最常用的一个启动方式,也是平常采用烧录器烧录程序,将程序烧录到主FLASH中。主FLASH属于内置的一个FLASH,一般都是将程序存储在FLASH某个地址中,由默认启动地址启动。
2.系统存储器,系统存储器属于芯片内部的特定区域。由厂家在特定的区域放置了程序,相当于BOOTLOADER,由于该段程序具备串口固件,一般可用于串口下载,但无法通过串口进行调试。
使用该方式需要注意BOOT1和BOOT0电平,下载好程序后,需要重新设置BOOT引脚为主FLASH启动,这样就能运行下载的程序了。
注意:该方式可用于芯片无法下载,比如由于时钟设置错误将芯片上锁了。
3.SRAM启动,RAM不具备存储功能,掉电丢失,该方式用于将程序下载到SRAM上,直接运行,在调试程序时速度较快,因为省去了下载到FLASH时,FLASH需要擦除的时间。

一般而言,使用MCU都是将程序烧录到内置的FLASH中,因此选用的是主FLASH启动。
问题:主FLASH也是一块内存,也有地址,那么烧录时是烧录到哪里?
答 :烧录到固定地址上,对于STM32F407而言是0X08000000(由参考手册可找到)

二.FLASH

STM32F407学习IAP时的笔记_第2张图片
图2.1 内部地址存储空间

可由图的地址映射看出,内部的存储空间实际是一片连续地址的存储器。根据不同地址分为CODE区等。

作业:查看任意外设(如GPIO的某寄存器)的地址,看是否属于其中的一部分,可以得出什么结论?

结论:将MCU的外设和外设寄存器可以看出其地址都属于映射图存储区域的一部分,因此MCU的外设和外设寄存器实际上也是一个存储空间,也有地址。因此在根据手册上看如何操作寄存器时,可根据地址来推算寄存器的名字等。

STM32F407学习IAP时的笔记_第3张图片

2.1 内置FLASH

407的内置FLASH说明在参考手册中能找到,可看出主FLASH分为12个扇区,各有各大小,总共1M,也就是说,烧录到主存储器的程序不能大于1M,或者Bootloader+APP不能超过1M。
系统存储器:上面已有介绍
OTP区域:一次性编程,不可再修改
选项字节:作用类似于寄存器,配置MCU的一些相关功能。
STM32F407学习IAP时的笔记_第4张图片

2.2 操作

操作非常简单,根据手册上的步骤走即可。由于内置FLASH,因此同样需要擦除工作再编程。
STM32F407学习IAP时的笔记_第5张图片
STM32F407学习IAP时的笔记_第6张图片

STM32F407学习IAP时的笔记_第7张图片

注意:在调试时,对FLASH->KEY写入解锁的两个数后,没有上锁继续再写入这两个数,当时进入HARDFAULT。未找出原因。

三.启动流程

3.1启动代码

STM32F407学习IAP时的笔记_第8张图片
Stack_Size EQU 0X00000400 类似于 #define Stack_Size 0X00000400,表示定义栈空间大小为0X400,真正起作用在下面语句。
AREA STACK,NOINIT,READWRITE,ALIGN=3
表示分配一个段(区域),该区域名字STACK,不进行初始化,可读可写,2^3 = 8字节对齐
Stack_Mem SPACE Stack_size;表示分配Stack_size大小的空间,其栈顶为__initial_sp

STM32F407学习IAP时的笔记_第9张图片
类似于栈的定义,分配一个堆空间大小为0X200,堆起始地址__heap_base,结束地址__heap_limit。
PRESERVER8 8字节对齐,使用THUMB指令(目前无需了解,如果要了解请参考Cortex-M3权威手册)。

STM32F407学习IAP时的笔记_第10张图片
定义一个字段,并且声明3个标号__vectors,__vectors_end,__vectors_size。

STM32F407学习IAP时的笔记_第11张图片
定义中断表的开始和结束,可以看出中断向量表的首地址是栈的__sp
在这里插入图片描述
为中断向量表分配一个段空间,大小是 End标号-起始标号

STM32F407学习IAP时的笔记_第12张图片

复位中断的服务函数
IMPORT表示外部定义,如同C语言的extern,因此进入复位后进入复位中断,找到SystemInit函数后将该地址装进R0,跳转进去执行;再获取main函数进入main函数。

3.2启动和执行流程

A.启动时,MCU锁存BOOT0和BOOT1引脚,找到相应的启动地址。如使用主FLASH启动,那么启动地址是0X08000000,而0X08000000刚好是栈顶地址,中断向量表前的sp指针。因此主FLASH启动时先找到0X08000000的SP指针。
B.中断向量表的偏移SP是4,因此地址是0X08000004,找到该中断向量表的0X08000004地址,是复位中断。
C.从复位中断表地址中找到复位中断服务函数的入口。
D.在入口中,执行以下内容。因此能跳转到我们的main函数。

STM32F407学习IAP时的笔记_第13张图片

执行代码流程如图
STM32F407学习IAP时的笔记_第14张图片
通过启动流程后进入Main函数,
正常执行代码时,在main函数while死循环中执行
当发生中断时,MCU会保存现场断点,然后跳转到0X08000004中断向量表处(第三步)
根据中断向量表的偏移量找出相应中断服务函数的入口(第四步)
当执行完中断后返回到断点处恢复现场继续执行(第五步).

四.程序升级

在研发阶段,可以通过烧录器下载程序调试。
但是在产品阶段,为了避免产品更新程序时需要打开外壳等用烧录器进行烧录,为了更方便更新用户程序,需要了解IAP。
IAP,在线编程,即可通过通信的方式来对FLASH进行写入,一般是写入APP程序,因此衍生出很多更新程序的方式,如开放SPI接口/IIC接口/UART接口/蓝牙/WIFI/射频/SD卡/U盘/网口等等。

4.1 程序升级的必要

需要两个程序:一个bootloader启动程序,一个APP用户程序。
bootloader启动程序:一般用来检测硬件/检测是否有APP/搬运代码等
APP用户程序:执行产品的功能

4.2 程序升级的FLASH分区

以STM32F407为例,主FLASH有1M。
需要注意且明白的一点是,我们需要的两个程序,bl和app程序。需要烧录在不同的FLASH区域,否则就代码数据覆盖了。因此需要进行分区。

STM32F407学习IAP时的笔记_第15张图片
既然STM32的启动从0X08000000启动,因此这段分区的Bootloader必须放在0X08000000起始地址上。
并且:既然我们分区,需要明确知道Bootloader占多大空间,APP占多大空间。

4.3 程序升级的流程

STM32F407学习IAP时的笔记_第16张图片
当采用BOOTLOADER+APP的形式,那么BOOTLOADER和APP势必被放到不同的区域。
那么上电时执行Bootloader后,如果有APP存在,就要实现跳转到APP区域。执行APP的代码.

正常流程:
1.从0X0800 0004地址上取出内容,内容就是复位中断程序入口。
2.MCU跳转执行复位中断程序。执行复位中断程序代码,跳转到main函数里面。
3.Main函数死循环执行代码,当发生某个中断时,找到中断向量表,继续从0X0800 0004+中断偏移量,从中断向量表某中断地址上取出复位中断程序入口
4.跳转到复位中断程序执行代码
5.执行完某个中断后,回到main函数
STM32F407学习IAP时的笔记_第17张图片
图. 正常流程

STM32F407学习IAP时的笔记_第18张图片
图.iap流程

IAP流程:
1.上电后,从0X0800 0004地址上取出内容,内容就是复位中断程序入口。
2.复位中断程序执行代码,跳转到bootloader的main中,执行IAP过程(此过程做什么内容由软件编写者决定,如判断是否存储区域有APP代码等,但势必包含跳转)
3.IAP过程跳转到APP的代码区域中,取出APP的中断向量表的复位中断入口,执行完复位中断跳转到APP的main函数中。
4.APP的Main函数死循环执行,当发生中断请求时,依然跳到0X0800 0004
5.依然从0X0800 0004+偏移量取出某中断程序入口,但是需要注意的是,APP和BOOTLOADER的存放区域不同,因此APP的中断向量表也不同,在APP会设置偏移量,因此从0X0800 0004 + 偏移量 + APP偏移量,取出某中断程序入口,执行某中断服务程序
6.中断服务程序执行完跳会APP的main函数。

4.4 常用做法

4.4.1 问题
由于一个产品要求稳定性好,那么升级程序必定需要考虑得很全面。
可以确定的是无论是否升级,BOOTLOADER都将执行,那么
如何确定APP存储区域有APP代码?
如何保证APP代码是准确的?
当升级时出错怎么办?

4.4.2
通常,会使用一个存储区域(外扩的存储芯片,MCU内部FLASH的一小块区域等等),使用字节空间,Bootloader根据这个空间的数据,比如我们规定0XAABBCCDD在地址0X08080000上,如果该地址空间读出来不是0XAABBCCDD,那么可以表示APP区域没有APP程序。

通常,会使用一个外扩的存储芯片,在APP运行过程中接收升级数据(串口/蓝牙等接收),APP将升级数据写入到外扩存储芯片上,然后写入一个标志,表示APP区域需要更新。

通常,Bootloader只做:识别APP区域有无APP程序,识别APP区域是否需要更新,跳转,升级。
进入Bootloader,识别APP区域是否需要更新的标志位,如果需要,则从外扩存储芯片拷贝数据;如果不需要,判断是否有APP程序,如果有则跳转到APP;如果没有,此时只有Bootloader区域,APP区域无代码,那么可以考虑在Bootloader加入升级功能,在没有APP区域时,Bootloader可以始终等待升级数据。

4.4.3 例子
STM32F407学习IAP时的笔记_第19张图片
假设现在有两个射频模块(主模块/从模块),主模块对从模块进行软件升级。
需要注意,射频通信进行数据传输受限于很多因素,如频率,带宽,外部环境,距离,天线强度等,那么通信的数据可能存在不稳定或者传输出错。
当升级数据很大的时候,传输升级数据如何保证无线模块升级的成功率在百分之99.9%呢?
肯定要对传输数据进行校验。(无论上位机传输数据还是无线传输数据,都要求加上校验保证成功率),加入校验最好的方式是:制定升级的协议(传输数据的格式 + 校验数据的算法)。

前面说过,当数据很大时,射频又容易受干扰。
采用:
1.制定通信协议:从机都赋予一个地址,主机对固定射频地址发送一个升级命令,其他从机收到该命令判断地址,不符合则进入休眠;符合则唤醒后回复一个响应并一直处于接收数据的状态,等待主机发送数据。
2.加入数据校验算法
3.分包传输:比如100K的升级数据,分成4K一包的数据(最后一包数据小于等于4K)。将这4K的数据加入到通信协议中,并对4K数据进行算法校验,将校验结果也传输给从机。

STM32F407学习IAP时的笔记_第20张图片
从机的处理方式:
从机开放内部FLASH 4个区域
STM32F407学习IAP时的笔记_第21张图片
Bootloader,app区域不解释
标志区域:存放是否需要更新程序的标志位以及是否有APP的标志位。
App备份区域:在APP运行时,如果需要升级,将接收的升级数据放到APP备份区域中,相当于一个缓冲区。

1.接收到升级命令,回复一个响应,并处于接收状态
2.当有数据时,对数据进行判断,是否符合制定的协议,如果不符合则退出升级;如果符合就对数据进行校验,如果校验成功就写到APP备份区中,当升级数据接收完毕,对标志区域写一个需要升级的标志。
3.复位,进入Bootloader,启动代码中对标志区域进行判断,判断到如果需要升级,则从APP备份区域拷贝升级数据到APP区域中并进行校验等。
4.跳转到APP

4.4.4 注意事项
A. 由于BOOTLOADER和APP放在同一块FLASH上的不同内存,假设将FLASH分成两部分,那么BOOTLOADER越精简,APP占空间越大,用户程序就可以占用更多空间。

B.既然放在不同区域,那么两者之间要有一个桥梁搭建联通起来,这个桥梁一般称为跳转。

C.如果Bootloader有开了一些外设和中断,在Bootloader跳转到APP,实际上没有发生复位,此时外设和中断仍然开启。因此在Bootloader跳转前关闭所有外设和中断。

D.。。。。。。

你可能感兴趣的:(STM32)