之前一篇的文章中,主要介绍了STM32的启动流程和内存主要空间的分配,这篇文章将在上一篇文章的基础上,来阐述一下STM32 Bootloader的实现。
STM32的内存划分
前面文章我们说了,STM32上电后会从0x08000000地址处开始运行,因此,如果我们想要使得STM32在上电之处直接进入进Bootloader,那么其内存的起始地址必须要从0x08000000处开始。这一步是由单片机的硬件所决定的,无法通过软件干预。
因此,在我们使用Keil软件设计STM32 Bootloader的时候,一定要在Keil的工程中设置这个地址,当然,如果你不设置也没关系,因为Keil默认就是将单片机的软件编译到此地址的。如图1所示。
图1 Keil上电起始地址的设置
另外在说一点,起始地址右边的Size我们也需要关注下,因为这个参数会影响到后续的内存空间分配。
好了,接下来假设我们有一块Flash容量为64KB的芯片,我们来为其划分一下内存空间。我们来计算下它的地址范围为多少。
起始地址不需要多说,就是0x08000000。
64K的地址空间该怎么算呢?这个其实是一个进制转换的问题,我们知道,在十进制中,1KB=1024个字节,而我们计算机中的一个字节就是一个地址单元,因此只要要使用64KB*1024就可以得出有多少个(十进制)地址单元了。又由于计算机中的地址都是按照十六进制编码来排列的,所以还需要将这个十位数的地址空间转换成十六进制,这个地址空间就是0x10000。注意,以上这个0x10000指的是地址空间,指明64K Flash中有0x10000个字节的存储单元,而我们的内存地址又是从0开始计算的,因此最终的地址范围就是0x08000000~0x08010000。
计算出以上的地址范围之后,我们就需要对其来划分功能区了,首先假设我们的Bootloader不带OTA(On The Air)升级功能,因此整个内存空间至少要划分成两个部分,第一个部分是从0x08000000起始的Bootloader区域,假设长度为X,第二个部分是紧接着(当然也可以不仅接着)Bootloader区域的应用区域,其地址范围为0x08000000 + X,其长度为Y。
这个地址的划分可以现根据Bootloader最终编译的大小进行动态改变,不过需要注意的是,STM32内存划分要以半页为最小单位,因为在对Flash编程时,都是按照半页来擦除的,所以如果你的程序不按照半页来对齐,那么擦出的时候就会很尴尬,半页=32个字=128个字节。
基于上述原因,我们暂定STM32中,前10K地址存放Bootloader程序,后面的地址,存放应用,如图2所示。
图2 STM32内存划分
Bootloader代码设计
Bootloader这个东西,对于我们来说是一个特殊的程序,但是对于计算机来说,它和千千万万的普通程序没有任何差别,因此我们也需要对这个程序进行初始化,你可以设置时钟,设置串口或者CAN总线资源等。这些都是必须要进行的,我们文中就不讨论。
比较重要的需要讨论的一点是跳转程序,因为Bootloader除了完成一些额外的不适宜在应用中完成的工作之外,最重要的一点就是程序跳转,即“JampToApp()”。所谓的程序跳转,那么程序跳转该怎么实现呢?
思考下,跳转最终就是通过Bootloader跳转到APP的地址处,在C语言中和跳转直接相关的便是指针了,因此既能保证跳转到某个地址,又能保证是类似于函数能被运行的,就只有“指向函数的指针“这一项了。没错,Bootloader的“JampToApp()”操作就是一个函数指针,只需要获知APP区的地址,就可以进行跳转了。
我们在上一节中以及指定了APP的地址就是0x08002800,那么是否只要跳转到这个地址就可以了呢?答案当然是否定的,因为我们之前说过,STM32内存空间最起始的4个字节地址,存放的是栈顶指针,因此我们需要跳转到0x08002800+4的地址处。
在跳转的过程中,关闭中断等工作也是必须的,具体代码如图3所示。
图3 Bootloader中的跳转程序
上面代码中,有一个自定义的“TYP_drcPtr”类型,它起始只是一个void类型。
typedef void (*TYP_drcPtr)(void); //Define the jump pointer
跳转问题解决了,接下来的问题就是何时跳转?
这个何时跳转很重要,我建议在程序的一开始,初始化Systemclock之前就去判断和跳转,因为STM32如果你在Bootloader中初始化了Systemclock之后,再去APP区初始化,会造成硬件错误,因此我建议大家在设计Bootloader的时候,程序一开始就是去检测能否满足跳转条件,满足了立马跳,不满足再去执行硬件的初始化程序。如图4所示。
图4 STM32跳转时机
好了,最后说一句,“Talk is easy, show me your code”,我已经调试成功的bootloader请自行git。
https://gitee.com/huangqilong119/STM32_bootloader.git
关于STM32的Flash编程又是另外一个故事了,我们后续再说。