STM32固件升级详解(BootLoader)

版权声明:本文为博主 Osprey 原创文章,转载请联系博主! https://blog.csdn.net/weixin_42876465/article/details/84728248

基础知识

这里以KEIL开发环境和STM32F103RET6为例。
上电时单片机首先进入复位中断Reset_Handler,即汇编文件的复位中断处理函数。
在这里插入图片描述
并且有一个中断向量表默认存在于flash地址开始处。
在这里插入图片描述
为什么说是默认呢?这是因为如果没有特殊要求的话很少会去改中断向量表。实际上这个中断向量表是可以更改的。但是在更改向量表之前必须在地址开始处建立一个向量表,因为在复位后,程序默认(硬件决定的)从flash开始的第一个字读取栈指针,第二字就是复位中断的入口,并根据该指针最终进入复位处理函数中执行相应的函数。如果没有这个中断向量表程序是无法启动的。
那么既然前面说可以重新设定中断向量表的位置,那必然有一个寄存器记录着这张表的位置,这就是VTOR寄存器。从《Cortex-M3权威指南》可以看该寄存器的介绍:
在这里插入图片描述
并且向量表的偏移量有如下要求:
在这里插入图片描述

64*4是因为一个表项为4字节。
更具体的关于更改向量表的信息查看《Cortex-M3权威指南》。
在复位处理函数中有进入SystemInit函数执行,在函数里有一个设置中断向量表的位置的语句。
在这里插入图片描述
VECT_TAB_OFFSET默认情况下就是0。
因为这是官方库函数,并且上电之后必定进入复位中断函数处理,因此必定会执行重新定位向量表的操作。因此只要修改宏定义就可以重新定位向量表。
先准备两个程序,一个为bootloader,用于更新程序,一个为APP,即固件程序。
首先确定BootLoader为上电最先执行的函数,需要通过下载器下载,而APP则可以通过有线(spi、i2c、usart、usb)、无线(Bluetooth、WiFi)等各种方式下载,只要能够正确传输数据即可。
在这里插入图片描述
因为两个程序中只能有一个程序正在运行,所以可以共用RAM。所以这个时候对一些变量就有必要进行初始化,以防APP程序使用的RAM空间存在之前的数据。
上电之后,因为硬件问题(可能是VTOR寄存器断电不保存数据吧),导致单片机自动从中断向量表1中寻找复位中断处理函数,此时必然最终会进入BootLoader程序中执行。因为向量表第一个字(32字节)存放的地址就是BootLoader程序编译出来的中断处理函数地址。所以在这个程序一般就是初始化传输方式,然后在一定时间里判断是否需要更新固件,需要则将更新固件并跳转到第二个复位中断函数中执行,而如果超时则自动跳转到第二个复位中断函数中执行。
一般更新固件的文件类型为bin文件,文件可以直接拷贝到flash中并且执行。那么bin文件应该是怎样的呢?下面的就是通过KEIL生成的bin文件所含有的信息。(有关如何生成bin文件查看前面章节)
在这里插入图片描述
和普通程序的生成没多大区别,都是编译器编译得到的目标的程序。但是我们要如何让编译将程序放在该放的地址呢,即在得到这个bin文件之后,当从向量表的第二字获取的地址刚好指向了Reset_Handler函数呢?即这里面存放的地址应该是绝对地址。
通过设置KEIL即可:
在这里插入图片描述
上面设置为0x8001000,这样在编译过程中就会将整个程序的开始放在0x8001000,并且其他函数地址也会根据该地址自动确定地址,而变量和栈等数据则存放在0x20000000开始处(和BootLoader一样,所以它们其实是共用RAM),这样程序才能正确执行。但是BootLoader怎么找到APP的第一个函数的地址并进入执行呢?就是从接收到的bin文件里找。之前说过程序的开始处就是一张向量表(编译器自动处理的),也就是这个程序的向量表开始就在0x8001000,而bin文件可以直接看成一个flash空间,程序应该放在0x8001000,在bin文件就是在文件的开始处,这样就能找到栈顶指针和复位中断处理函数了。有点绕,看示意图(数字无意义):
在这里插入图片描述
但是BootLoader虽然找到了APP程序的复位向量地址,并且整个APP程序拷贝到0x08001000开始处了,BootLoader程序可以通过跳转语句调到复位中断处理函数执行,并且能从向量表出得到栈顶位置,并且其他函数地址也由编译器确定了,执行应该是没问题的。但是一旦中断来了,根据stm32的中断机制,肯定会从中断向量表中找地址,而找中断向量表是通过VTOR来定位的,而在跳转后虽然进入了复位中断处理函数,并进入了SystemInit()中执行,也执行了重新设置VTOR寄存器的操作,但是你的VECT_TAB_OFFSET还是 0……这样一旦中断发生,通过VTOR定位又跑到BootLoader的向量表去执行处理程序了。所以在进入APP函数后,需要重新定位我们新的向量表,只需要修改VECT_TAB_OFFSET即可,而这个偏移量有限制……,而且这个偏移量其实也就是给BootLoader程序预留的空间,所以在这里VECT_TAB_OFFSET设置为0x1000,符合限制条件,并且这个偏移量应该大于BootLoader程序的总大小,这样就OK了。
跳转到复位中断处理函数之前,必须重新设置栈顶位置,虽然是共用RAM,但毕竟BootLoader程序编译下的RAM分配和APP程序编译下的RAM分配可能是不同的,需要重新确定栈顶位置。
在这里插入图片描述
总结:
1、BootLoader两个功能,一个是一定时间内判断是否需要更新APP,如果需要则接收并将其烧写到指定地址的flash空间中,并从该地址中获取栈顶指针和Reset_Handler指针,并跳转到该函数执行;另一个就是超时直接在该地址直接获取之前的栈顶指针和Reset_Handler指针并跳转执行。
2、APP程序需要让编译器将程序存放在指定地址空间里,并重新定位中断向量表的位置。
3、每次上电复位之后程序都会直接从BootLoader的Reset_Handler函数执行,而不是从APP中执行。
4、这个地址有两个限制:BootLoader程序大小和向量表地址限制,必须两者都符合要求。
-------------------------------------------------------------------------2018/7/25 Osprey

Ymodem协议

了解了基础知识之后就可以使用某种传输方式进行bin文件的传输,这里介绍YModem协议,当然也可以使用Modbus等其他协议进行传输。YModem协议是从XModem协议演变而来的,每包数据最多可以达到1024字节,是一个非常高效的文件传输协议。
下面是传输过程:
首先接收方发送字符‘C’,等待发送方接收,如果接收方没有准备好,则接收方持续发送‘C’。
接收方收到C后,开始发送第一帧数据:
在这里插入图片描述
字符:字符为ASCII码,指定的几个特定字符。比如SOH,查询ASCII码可以知道是0x01,它代表该帧有128byte数据。如果是STX则有1024byte。
在这里插入图片描述
在这里插入图片描述
编号:编号从0开始,根据帧数增加,达到0xFF从0开始继续递增。比如第一帧发送文件名时的编号为0x00。程序处理的时候在一开始设置一个变量为0,每接收一帧数据递增,并且和接收的编号进行对比,如果接收的编号和程序的变量不一致,说明接收错误。编号的反码是对编号进行校验使用的,以确定编号的正确性。比如编号为0x00,反码为0xFF。
数据区:固定长度,不足的填充0x00。可以是128字节也可以是1024字节,根据帧头字符确定。传输文件名时是完整的文件名,如 “helloword.bin”,后面填充0。有的传输软件在传输完文件名这一帧数据后可能会再传输一帧含有文件大小的数据帧(数据区不足还是填充0),可以根据实际情况测试。
CRC16:只对数据区进行校验,不对前三个字节校验。高字节在前,低字节在后。
接收方接收到第一帧含有文件名的数据帧之后,开始发送ACK进行确认应答,并发送字符‘C’,发送方收到‘C’后开始接收第二帧数据,这里包含文件内容的一部分。接收方接收到这帧数据后,发送ACK应答,等待第三帧数据,继续ACK应答,继续接收……知道接收方接收到所有数据。
当发送方发送完最后一帧数据并接收到ACK后,发送EOT,接收方接收到之后,接收方发送NAK,发送方继续发送EOT,这一次接收方发送ACK。然后接收方再发送‘C’,如果发送方没有下一个文件需要传输,就会发送如下帧:
SOH 00 FF 00~00(共128个) CRCH CRCL
接收方接收到后,正式结束此次传输。
ACK、NAK、EOT 的ASCII码如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面为传输具体过程,以文件大小不足三帧数据为例,黄色为接收方发送的数据。
在这里插入图片描述
以下为CRC校验代码:
在这里插入图片描述
-------------------------------------------------------------------------2018/7/26 Osprey

SecureCRT使用

以下操作方法是为公司的一个项目写的操作流程。

  1. 安装SecureCRT软件
    在这里插入图片描述

  2. 使用串口连接电脑和目标板。
    在这里插入图片描述

  3. 打开SecureCRT软件,可以从左边找到Session Manager窗口,如果没有,可以从 View -> Session Manager 打开。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  4. 选择加号,添加串口。注意必须先连接串口才能进行该步骤。
    在这里插入图片描述

  5. 然后设置串口参数,最后点击OK即可
    在这里插入图片描述

  6. 之后可以从左边窗口看到新添加的串口。双击该串口,即可进入串口数据传输界面。
    在这里插入图片描述
    在这里插入图片描述

  7. 给目标板上电或者按复位键,然后在英文状态下马上发送字符‘c’,就可以看到目标板回复信息如下:
    在这里插入图片描述

  8. 然后输入英文字符‘1’,等待目标板发送‘c’。如下
    在这里插入图片描述
    注意:用户发送的数据不会在界面上显示出来(如果需要回显,需要进行设置Session Options—>Advanced—>Localecho)。如果不能接收到目标板的信息,请重复上述操作。

  9. 从Transfer中选择Send Ymodem
    在这里插入图片描述

  10. 进入如下界面,选择你需要下载的bin文件添加,最后OK即可。
    在这里插入图片描述

  11. 此时可以看到正在传输bin文件,传输到100%时,传输完成,并且进入更新好的程序中执行。
    在这里插入图片描述
    ----------------------------------------------------------------------------------------2018/8/23 Ospery

欢迎关注我的微信公众号,方便手机阅读
鱼鹰谈单片机

没有更多推荐了,返回首页