最近在玩ESP8266,做了些东西,比如考研倒计时器、网络闹钟、网络灯(用手机控制亮度)、气象站等等。
ESP8266本身挺简单的,倒是这个自动下载电路,我还是第一次玩,以前玩51也用过串口下载,都是自己冷启动,玩STM32用的ST-LINK,直接下载。
现在才发现其实可以设计一个自动下载电路,根据不同的MCU下载的条件不同,电路设计也有区别。
这里我就简单说一下ESP8266的自动下载电路以及CH340芯片的一个坑。
原理图如下:
使用的是CH340C,实际上其他型号也差不多,CH340C相比CH340G就是少用个晶振。
可以看到相比普通的串口,此电路中将CH340的RTS(注意不是RST)和DTS引出,通过右侧电路,构成自动下载电路。
那么ESP8266如何进入下载模式呢。很简单,两句话。
1.在复位上升沿时,如果BOOT为1,则进入运行模式,此时内部程序正常运行。
2.在复位上升沿时,如果BOOT为0,则进入运行模式,此时可通过串口下载程序。
那么要想进入下载模式,一开始我的想法是应该是RST和BOOT都为0,然后RST置为1,这样RST就有一个上升沿,且BOOT为0。这句话先放这,我们再来看。
那么现在分析一下右侧电路逻辑。
DTR = 0,RTS = 0,此时Q1截止,Q2截止,RST= 1,BOOT= 1;
DTR = 0,RTS = 1,此时Q1截止,Q2导通,RST= 1,BOOT= DTR = 0;
DTR = 1,RTS = 0,此时Q1导通,Q2截止,RST= RTS = 0,BOOT= 1;
DTR = 1,RTS = 1,此时Q1截止,Q2截止,RST= 1,BOOT= 1;
你会发现无法出现RST= 0,BOOT= 0。但是我们上面分析中需要RST= 0,BOOT= 0,好像无解啊。那么这个电路怎么实现ESP8266自动下载呢。
在官方的 SDK 中的下载脚本源码中有如下代码:
def _connect_attempt(self, mode='default_reset', esp32r0_delay=False):
""" A single connection attempt, with esp32r0 workaround options """
# esp32r0_delay is a workaround for bugs with the most common auto reset
# circuit and Windows, if the EN pin on the dev board does not have
# enough capacitance.
#
# Newer dev boards shouldn't have this problem (higher value capacitor
# on the EN pin), and ESP32 revision 1 can't use this workaround as it
# relies on a silicon bug.
#
# Details: https://github.com/espressif/esptool/issues/136
last_error = None
# If we're doing no_sync, we're likely communicating as a pass through
# with an intermediate device to the ESP32
if mode == "no_reset_no_sync":
return last_error
# issue reset-to-bootloader:
# RTS = either CH_PD/EN or nRESET (both active low = chip in reset
# DTR = GPIO0 (active low = boot to flasher)
#
# DTR & RTS are active low signals,
# ie True = pin @ 0V, False = pin @ VCC.
if mode != 'no_reset':
self._setDTR(False) # IO0=HIGH
self._setRTS(True) # EN=LOW, chip in reset
time.sleep(0.1)
if esp32r0_delay:
# Some chips are more likely to trigger the esp32r0
# watchdog reset silicon bug if they're held with EN=LOW
# for a longer period
time.sleep(1.2)
self._setDTR(True) # IO0=LOW
self._setRTS(False) # EN=HIGH, chip out of reset
if esp32r0_delay:
# Sleep longer after reset.
# This workaround only works on revision 0 ESP32 chips,
# it exploits a silicon bug spurious watchdog reset.
time.sleep(0.4) # allow watchdog reset to occur
time.sleep(0.05)
self._setDTR(False) # IO0=HIGH, done
for _ in range(5):
try:
self.flush_input()
self._port.flushOutput()
self.sync()
return None
except FatalError as e:
if esp32r0_delay:
print('_', end='')
else:
print('.', end='')
sys.stdout.flush()
time.sleep(0.05)
last_error = e
return last_error
代码很明了了。也就是两个过程:
1.设置 DTR = 1,RTS = 0,此时 Q1 导通,Q2 截止,RST= RTS = 0,BOOT= 1,芯片掉电复位;
2.设置 DTR = 0,RTS = 1,此时 Q1 截止,Q2 导通,RST= 1,BOOT= 0,芯片重新上电;
当时我就懵了,因为按照代码,逻辑图如下
在RST上升沿时BOOT才刚下降,这是不是有点太冒险了、后来我想了想,考虑到RST有电容的存在,有充放电的过程,BOOT是没有电容的,所以下图才是正确的。
可以看到,在RST判定为1时,BOOT为0。此时就进入下载模式了。
OK,到这里ESP8266和ESP32的自动下载电路就分析完了,其实设计其他MCU的串口自动下载电路思路大抵相同,需要补充的是,CH340的辅助引脚是由上位机控制的,所以设计电路就需要了解上位机控制逻辑。
最后还有个CH340的坑。我在做好我的小设计后,本来以为能愉快的玩耍了,直到今天我做了个带电池的闹钟,才发现一个问题。
前几个小作品没有用到电池,闹钟用到了。没有电池的作品直接用USB供电,同时USB也是CH340串口。而带电池的闹钟,USB可以供电,也是CH340串口,同时也能使用电池供电。
区别就在于没有电池时,直接插上USB后,供电和通信同时进行,有电池时,插上USB后,只增加了通信。坑来了,后者由于有电池已经开始运行了,插上USB后,CH340会通过自动下载电路给ESP8266一个复位。
这时就很难瘦了,假如我代码都写好了,平时电池供电正常用着呢,这时我要电池充电了,于是插上USB,结果CH340直接给我复位了,虽然说复位并不会影响闹钟的时间、设置什么的(因为关键数据我保存到FLASH了),但是插上USB充电就复位也太坑了吧。
而且我的闹钟在响铃时,只要插上USB,立马复位,于是闹钟不响了。
说这么多,归根结底就是插上USB后,CH340和电脑连接正常,于是给RTS#一个低电平,通过下载电路,RST为0,于是芯片复位。
解决办法很简单(但我百度找了很长时间,终于找到问题所在),那就是。。。。。。。更新CH340驱动。。。。。。
噗,哈哈,没错,就是驱动问题,必须要2019年的驱动(截止2021/5/13,WCH官网最新的驱动是2019年的),所以这个问题属于WCH公司自己的锅。
我反复安装2014年版本(就是以前买各种板子淘宝卖家送的资料包里的)以及我在WCH官网下载的最新2019版,反复测试后,确定就是驱动问题。
为了避免其他问题,哪怕你没有我上面说的这个困扰,也把CH340驱动更新一下吧,说不定还有其他的坑。
贴一下下载地址,我知道你懒得找:http://www.wch.cn/downloads/CH341SER_ZIP.html
点进去就是最新驱动下载页面。
哦对了,实测CP210x系列没有这个问题,CP210x还是稳啊,目前我的CP210x驱动是2016年的。