
基于串口通信的STM32F1系列MCUBootloader开发 引言 IAP(In Application Programing)是在应用编程,目的是为了在产品发布后可以方便地通过预留的通信口对产品中的固件程序进行更新升级,也就不需要像传统的单片机烧录程序一样,需要通过例如像JTAG的下载方式等将程序直接下载到单片机中,降低了开发难度。 在STM32芯片的代码区(Code区)中,一般只有一个用户程序,而IAP则是将代码区分为两个部分,一个部分用来存放user app(用户程序),另一个部分则用来存储bootloader(程序加载引导)。如果需要更新用户程序,只需要在bootloader中进行相应的操作就可以完成用户程序的更新。 1.STM32F1ZET6的bootloader和应用程序存储器地址分配 1.1 STM32F1系列MCU的FLASH分配 STM32F1系列有大、中、小容量之分,按照不同容量,存储器组织成32个1K字节/页(小容量)、128个1K字节/页(中容量)、256个2K字节/页(大容量)的主存储器块和一个信息块,见下表: ![]() ![]() ![]() STM32F1ZET6是大容量产品,因此有512KB的FLASH。FLASH的起始地址是0x08000000。 1.2 STM32F1系列MCU的SRAM分配 STM32F1系列内置64K字节的静态SRAM。它可以以字节、半字(16位)或全字(32位)访问。SRAM的起始地址是0x20000000。 1.3 STM32F1ZET6的bootloader和应用程序存储器地址分配 鉴于以上介绍,将FLASH的0x0800 0000到0x08010000 共64KB的空间分配作为bootloader的存储空间。 在KEIL中作如下设置: ![]() 留给用户程序的存储空间还有448KB的大小。同样在KEIL中做如下操作: ![]() 2.STM32F1ZET6的FLASH读写 主要参考的是《STM32F10xxx闪存编程参考手册》 STM32的FLASH读写和一般FLASH操作是一样,也是写入之前需要进行如下步骤: (1)解锁: 往FLASH密钥寄存器中FLASH_KEYR中写入KEY1=0x45670123,再往FLASH密钥寄存器中FLASH_KEYR中写入KEY1=0xCDEF89AB。 (2)擦除扇区 (3)写入数据 (4)上锁 这些操作官方都已经封装了库函数,使用的时候直接调用即可。 3.上位机及串口驱动开发 这个部分其实应该算是重点,光是上位机的制作和通信协议的编写就很有意思。不过奈何精力有限,没有着手去做这个。不过先给自己定个目标吧,争取在春节假期把这部分补上。 本次实验使用的是正点原子的XCOM串口调试助手,上位机向单片机每发送一个字节的数据,单片机进入中断接收,将收到的数据存储到指定存储区域,随后继续接收数据,直到没有新的数据接收为止。 ![]() 串口接收后的数据,会被存储到定义的数组里面。这个数组在bootloader里面定义后,默认是ZI_data,也就是说会被存储在RAM里面,而我们知道STM32F1系列的芯片RAM只有64K,所以理论上我们生成的bin文件大于64KB就无法完全下载进去,实际还会更小。当然可以将数据存储到FLASH里面,只不过是会比较繁琐一些,因为FLASH写入需要擦除,不过这样可以避免文件太大而传输失败。 4.Bootloader程序流程介绍(生成bin文件,调用FLASH编程应用程序以及跳转用户程序方法) ![]() 单片机一上电就开始运行bootloader程序,此时通过上位机可以与单片机进行交互,当等待时间超过5s过后,程序自动跳转执行上次下载的程序,如果在等待期间有程序更新要求,则通过传输bin文件至单片机进行更新并跳转执行。 Bin文件的生成: 可以使用fromelf工具生成bin文件,首先找到axf文件所在目录,这里以按键实验为例。shift加鼠标右键->在此处打开命令窗口,在命令窗口输入fromelf,再输入fromelf --bin --output KEY.bin KEY.axf。就可以在axf文件目录下得到KEY.bin文件。 ![]() 跳转用户程序方法: ![]() 注释已经很详细的说明了整个流程。这个方法也是参考CSDN上的帖子,基本看到的跳转方法都是如出一辙。图中的addr也就是跳转后的用户程序首地址,本例即为0x0801_0000,具体需要根据实际应用来更改。 向指定地址写入用户程序: ![]() 该程序有参考正点原子的IAP实验,但是个人感觉写的有点繁琐,所按照自己的理解重新写了一遍。首先是重新整理接收到的文件,因为STM32FLASH的写入只支持半字(两个字节)或者字(四个字节),而串口是以一个字节一个字节地传输,所以我们需要将得到的数据两个字节两个字节地合成。当融合了2048个字节,也就是1024个半字后,便可以开始向FLASH写入一页。程序跳转至erase_and_write()函数,开始进行擦写,也就是先解锁再擦除,再写入,上锁。重复这个过程,一直到把所有数据都写入完毕,比较简单,就不再赘述。 5.本次实验使用的Bootloader 5.1 硬件连接以及程序测试 ![]() 单片机通过JTAG下载线将bootloader程序下载至单片机,随后通过串口通信将更新程序下载至单片机。 实际运行中单片机反馈。 ![]() 总结 其实一开始并不是想要做STM32的bootloader,因为实际需要做的是MPC5744P这一款芯片的bootloader,可惜一开始对于这方面的知识不是很了解,所以只有从资料更为丰富的STM32开始练手。虽然前前后后还是花了很多时间,但是我对STM32的整个启动流程也有了更为深刻的了解。相信后面编写MPC5744P的bootloader也会相对轻松。不过其实这个东西相当于才做了最简单的一半,我个人认为上位机和通信协议才是更为关键的一点。后面会抽出时间来从头做一个上位机,并且采用CAN通信的方式下载程序,这样也更符合工程上的应用。 参考资料: 1.正点原子STM32F1开发指南(精英版)-库函数版本_V1.2.pdf 2.野火STM32F103教学视频 https://www.bilibili.com/video/BV1yW411Y7Gw?p=145 文章出处:二流硕士 |