【STM32】启动配置和自动串口下载
文章目录
- 0 前言
- 1 启动配置
- 2 自动下载电路
- 3 一键下载电路只能是这样吗?
- 4 深度思考
- 5 总结
0 前言
最近在研究STM32时,在下载程序时遇到了一些问题,在查找相关资料并结合自己的实践后,突然发现自己之前对STM32程序下载和启动配置等理解存在较大的误区,特写篇文章记录一下。
1 启动配置
相信很多人学习STM32都会接触这张启动配置的图:
从画红线的部分可以了解到,当芯片复位之后,系统时钟(SYSCLK)起振,程序从地址0x0000 0000开始运行,在SYSCLK第四个上升沿锁存BOOT的引脚电平,然后决定接下来是从主闪存运行还是系统存储器中运行,也就是PC指针接下来跳转到哪个位置执行程序,0x8000 0000对应主闪存;0x1FFF F000对应系统存储器。
于是就出现了第一个疑点。网上有很多博客在介绍stm32的启动配置时,都提到stm32内部存储的结构,低地址主要是系统存储区,高地址是主闪存,如下图所示
图片来源:我之前的一篇博客
但是很显然, 主闪存的起点(0x8000 0000)其实在系统存储区起点(0x1FFF F000)的前面。
为什么要强调这一点呢?因为上面那张图给人的感觉就像是 “芯片运行过程中,先执行系统存储区,判断有没有下载的请求,如果有则进行下载操作;否则,执行后面的主闪存部分,也就是用户编写的程序。” 但是很显然, 实际情况并不是这样的 。这两部分的程序实际上是单独存在的,都是死循环的结构,也就是进入到其中一个执行之后,无法自动跳出到另外一个部分去执行,除非更换启动配置然后复位或者是输入一些特定的指令。
所以很显然,最直白的方式就是使用外部编程器/仿真器进行下载,速度快的同时还能进行仿真,此外,不用来回切换启动配置。
试想一下,如果你使用串口下载,需要哪些步骤,假定起点是芯片正在正常执行程序,然后现在需要更新程序,需要:
- 首先是将启动配置切换到系统存储运行(即BOOT0接1,BOOT1接0),
- 然后复位,
- 再使用串口下载,
- 下载完毕之后,又要把启动配置切换到运行状态,即BOOT0接0(BOOT1可以不动),
- 然后再按下复位键,实现新下载代码的正常运行。
前后对比,优劣十分明显,但是使用stlink或者jlink还需要再买一个设备,而串口下载仅需一根usb线,那有没有什么办法能够实现串口一键下载,不用那么多复杂的操作,最好还能兼容仿真器下载 ? ,而这就是自动下载电路的魅力所在。
2 自动下载电路
经过查找资料,找到一张比较靠谱的电路图,如下所示
图片来源链接
由于此前有研究过ESP32的自动下载电路,这个电路十分相似,简单介绍一下其原理。
在介绍电路原理之前,首先简单了解一下串口的流控信号。
一般来说,在我们使用串口时,只使用到了两根线,即TX和RX(当然,要共地),发送和接收,但如果一端发送太快,另一端处理不过来,就会出现数据丢失的问题,于是就需要有流控信号,告知双方对方的状态,比如是否可以接收/发送,数据是否准备好/处理完毕等。常用的信号有四个
- RTS,Request To Send,即请求发送。是一个状态输出信号,告知对方可以我准备好了,可以发送数据,一般是低有效。
- CTS,Clear To Send,清除发送。是一个读取对方状态的引脚,看看对方能不能接收数据,如果可以,接下来就要发送数据了,一般是低有效。
- DTR,Data Terminal Ready,数据终端准备。是一个状态输出信号,告知对方我的数据准备好了,接下来可以准备发送,一般是低有效。
- DSR,Data Set Ready,数据准备好,是一个状态读取信号,查看对方数据有没有准备好,一般是低有效。
可以发现,以上信号一般是成对出现的,毕竟串口是半双工协议,支持两端发送和接收,但不能同时进行,两端实际上是等价的。因此有一种简化的流控接线方式如下图所示。
另外,还需要强调一点,这些流控信号全部都是软件控制的,且没有严格的先后关系,可以想象成串口芯片提供的额外的IO口,如果有使用过编程语言去实现串口收发可能对此会有更好的理解。因此这也就意味着,当我们不需要流控时,这些信号其实可以用来控制芯片某些引脚的电平,而这就是以上电路的实现原理。
参考链接
了解流控信号的原理之后,再来看看电路(重新放一次,方便看)。
- BOOT0默认为0(其他地方有下拉,阻值一般为10k,图中未画出),是运行模式。
- 当RTS为低时,Q4导通,BOOT0由于上拉电阻小于下拉电阻,表现为高电平;当RTS为高时,Q4截止,BOOT0由于下拉电阻的存在,表现为低电平。
- RTS为低,且DTR为高时,Q3导通,RESET引脚被拉低,芯片复位;DTR为低时,不过RTS啥状态,Q3截止,RESET上拉,芯片进入运行状态。
- 因此,如果要写代码来控制,那就是先让RTS为高,把BOOT0拉高,再把DTR拉高,RESET为低,芯片复位,再把DTR拉低,复位结束,延时一小段时间(因为是在复位之后的SYSCLK第四个上升沿锁存boot引脚值),下载完程序之后,DTR拉低,由于RESET芯片内部有上拉,变为高电平,取消复位;然后再把RTS拉高,使BOOT0为低,芯片进入运行模式。【这里可能会存在一定的竞争冒险,但考虑到复位引脚一般会接电容,所以问题不大】
最后再来看看串口烧录软件,常用的主要是flymcu这个软件,界面如下所示。
如果是通过调整BOOT引脚电平来进入BootLoader,这样下载程序不需要任何的流控信号,所以左下角的任何设置都不影响,但如果想实现自动下载,即下载完程序自动运行,就需要根据电路设计来选择模式了。
以上面放的电路图为例,分析的结果应该是 “RTS低电平进BootLoader,DTR高电平复位”, 但这里应该选择的模式是 DTR低电平复位,RTS高电平进BootLoader ,因为这里有一个很重要的点,就是这个高低电平是RS-232电平,其逻辑和TTL电平是相反的。
让我们实践验证一下!
正好手边有一个带一键下载电路的开发板,如下图所示
其原理图和上面所附图基本一致。
实践测试发现确实得选 DTR低电平复位,RTS高电平进BootLoader模式才能下载程序,其他模式都不行。
3 一键下载电路只能是这样吗?
不知道有没有人考虑过,如果只是设置电平,而且软件可自定义,为什么要整这么复杂?还要加三极管来控制?不能引脚直连吗?
说干就干,就拿这块小绿板了,调整一下外围电路,总不至于芯片损坏。先拿出电路原理图:
为了保险起见(怕图不对板),还拿电表依次测了通断,发现只是元器件位号不同,型号是一致的。OK,开始飞线!
既然要直连,那就将RTS直连BOOT0,DTR直连NRST(中间的二极管保留)接线如下图所示。
为了避免干扰,实际还将R6和R7暂时摘掉,最后飞线完的样子如下图所示。
接下来,我们再来分析一下电路,因为是直连,结果很清晰:当RTS为高电平时,进BootLoader;当DTR为低电平时,芯片复位,然后再翻转电平,所以要选择的模式是 DTR高电平复位,RTS低电平进BootLoader :
OK!下载成功!
4 深度思考
明明直连就能实现自动下载,为什么要加三极管呢?目前我在网上看到好几种说法:
-
说法一:直连会锁定引脚电平。在不下载程序时,这个引脚的电平是被锁定的,即要么是高电平要么是低电平。但是运行过程中复位引脚就应该保持高电平,BOOT0引脚就应该保持低电平呀?是的,至少STM32是这样的,但其他芯片这些模式配置的引脚是有可能复用的。比如esp32芯片的IO0引脚,在很多应用场景都是特定需要使用的引脚,这也是为什么官方的板子上的下载电路都是这样的。
关于ESP32和ESP8266自动下载电路有一篇深入挖掘内部原理的文章,感觉还是很有意思的:传送门。
-
说法二:引脚直连之后打开串口会导致复位。参考这个链接,因为早期很多串口默认开启流控。但现在很多串口调试助手都可以选择是否启用流控信号,所以这其实不是原因。
有兴趣的可以研究一下论坛的这个帖子以及issue
这些确实有可能有问题,但是我实测发现一个更大的问题,那就是下载程序之后,复位,芯片会进入bootloader,不运行。猜测应该是直连的电平钳位(始终是高电平)导致BOOT0一直拉高。那之所以程序下载之后可以运行,实际上是勾选了“编程后执行”的选项。
这里值得一提的是,即使直接使用USB转串口模块对芯片下载程序,其实也能达到下载完不调整BOOT模式就能运行的效果,因为flymcu有一个编程后执行的选项:
这个的原理应该是芯片支持通过软件的方式跳出bootloader,但是这样有一个问题,那就是复位之后,由于BOOT模式未切换成运行模式,芯片还是会进入BootLoader,所以这个运行只是这一次有效,下次上电或复位即失效。
这样看来,使用串口芯片引脚直连BOOT0和nRST的结果和不带一键下载电路是一样的。也就没有坚持的意义了。
5 总结
本文研究了STM32芯片的启动配置和自动下载电路,试图简化自动下载电路,但实测发现当前流行的自动下载电路确实是最优解。虽然没有创新电路,但理清楚了电路设计的原理,对芯片的理解也更加深入。
值得一提的是,GD32的启动模式和STM32是一致的,所以如果有串口下载的需求,可以直接复制本文贴出来的电路。