手上的 ESP8266 WiFi 模块跑的还是几年前刷进去的老固件,最近想接一个本地 MQTT 环境做联动,结果AT+CIPSTART一发就返回ERROR,AT+CWLAP扫出来的列表也是空的。折腾半天才反应过来:这不是代码写错了,是模块里的 AT 固件版本太老,压根不支持那几个指令。于是就有了这次完整的固件更新过程——把一块 32Mbit 的模组刷成 DOUT 模式的 4MB 布局固件。这篇文章就把"DOUT_32M"这个看起来像乱码的命名拆开揉碎讲清楚:它到底是哪几个参数、为什么这两个参数凑在一起最容易出问题、怎么烧、烧完怎么验证、出问题按什么顺序排查。
如果你手上正好有一块 ESP8266 模组,容量是 4MB、型号后缀带 12F/12E 之类,或者是那种引脚焊得密密麻麻、不敢乱碰的小板子,这篇内容基本可以直接照着做。哪怕你是第一次碰烧录工具,只要把地址表抄对、三个下拉框选对,成功率会比你想象的高。
1. 先把"32M"和"DOUT"这两个词翻译成人话
很多人第一次看到"DOUT_32M版本固件"会懵:32M 是 32 兆吗?我手机存储都 256G 了,32 兆能干啥?DOUT 又是什么缩写?这两个词其实是两个完全不相干的参数被塞进了同一个文件名里,一个管容量,一个管读取方式,搞混任何一个都会导致刷完之后板子变砖或者反复重启。
1.1 32M 是 32Mbit,换算成我们熟悉的单位只有 4MB
这是新手最容易栽的第一个跟头。芯片行业报 flash 容量习惯用 bit,而操作系统和文件系统习惯用 Byte,两者差 8 倍。所以:
| 标称容量 | 实际字节 | 常见用途 |
|---|---|---|
| 8Mbit | 1MB | 早期 ESP-01 一类小模组 |
| 16Mbit | 2MB | 老款模组,勉强够 AT 固件 |
| 32Mbit | 4MB | 目前主流,能跑 AT 固件 + 双区 OTA |
| 64Mbit | 8MB | 少数大容量模组,可挂更多资源 |
所以"32M 版本固件"的意思是:这块固件是按照 4MB 的 flash 空间来排布分区和参数区的,不是 32MB。你如果在烧录工具的下拉框里看到"32Mbit"和"4MB"两个选项,别犹豫,它们是同一个东西的两种叫法;但如果看到"32MB",那是另一个量级,选错了固件会写到不存在的地址上去。
为什么这个换算这么重要?因为 flash 的参数区和分区表是按绝对地址硬编码的。SDK 约定射频初始化参数放在 0x3FC000,这个地址是按 4MB 空间倒推出来的倒数第二个 4KB 扇区。如果你实际是 2MB 的片子却按 4MB 的地址表刷,写 0x3FC000 这个动作本身就会失败或者回绕,表现就是烧录工具报错,或者更阴险——烧录显示成功,但模块一上电就卡在启动日志里。
我见过有人图省事,拿一块 2MB 的旧模组硬刷 4MB 的固件包,烧录软件一路绿灯,结果模块每次上电打印几行日志就没声了。查了两天才发现是容量不匹配——因为分区表里文件系统的起始地址已经超出物理 flash 范围,SDK 初始化文件系统时直接挂死。
动手之前,先花十秒钟读一下芯片 ID 和容量,命令是
esptool.py --port COM3 flash_id,输出里Detected flash size: 4MB这一行才是唯一可信的依据,别信卖家描述,也别信板子丝印。
1.2 DOUT 省下来的不是线,是两个被占用的引脚
ESP8266 本身没有片内 flash,程序和数据都存在外面那颗 SPI flash 里,靠一组 SPI 引脚去读。这组引脚在芯片内部对应 GPIO6 到 GPIO11,分别叫 SD_CLK、SD_D0、SD_D1、SD_D2、SD_D3、SD_CMD。问题在于,SPI 读取模式有四种,用几根线、怎么复用,会直接决定剩下几个 GPIO 能不能拿去干别的。
- QIO(Quad IO):四根数据线全用上,读写都是四线并行,速度最快,但 GPIO9 和 GPIO10 被彻底占用。
- QOUT(Quad Output):四根线只用于输出,输入还是单线,速度介于中间。
- DIO(Dual IO):两根数据线双向复用,读写都走这两根。
- DOUT(Dual Output):两根数据线分工,一根专门输出(DO),一根专门输入(DI),不做方向切换。
对,DOUT 的引脚数量和 DIO 是一样的,都是两根。真正的区别在引脚占用:DOUT 模式下,只有 SD_D0 和 SD_D1 参与数据搬运,SD_D2(GPIO9)和 SD_D3(GPIO10)完全空闲,可以当普通 IO 用。
这听起来像个无关紧要的细节,但对模组厂来说是天大的事。很多模组为了多引出两个可用引脚,或者板子上本来就把 GPIO9、GPIO10 接到了别的地方(比如指示灯、按键、外部上拉),上电瞬间这两个引脚的电平是不受控的。这时候如果固件头里写的是 QIO,芯片会尝试用四线模式去读 flash,读回来的数据里混进了被外部电路干扰的位,结果就是校验失败、启动不了、或者跑着跑着随机重启。
打个比方:QIO 是四车道高速,跑得爽,但要求四条车道都畅通无阻;DOUT 是双车道,速度慢一点,但只要这两条道没被占,就一定能通。模组硬件一旦动过手脚,你就只能老老实实走双车道。
1.3 什么情况下必须锁死 DOUT,什么情况下可以放开用 QIO
判断标准其实不复杂,我一般按下面这个顺序确认:
- 看模组是否把 GPIO9、GPIO10 引到了排针上。引出来了,基本就告别 QIO 了,因为你没法保证外部不会在这两个脚上挂东西。
- 看板子上 SD_D2、SD_D3 有没有接上拉电阻或其它器件。有,就走 DOUT。
- 看历史固件。如果原厂固件读出来头部是 DOUT,别自作聪明改成 QIO,直接沿用。
- 什么都不确定的时候,选 DOUT。这是兼容性最好的选项,代价只是读取带宽低一些。
代价到底有多大?ESP8266 跑代码用的是 XIP 加指令缓存,绝大部分时间 CPU 都在缓存里取指令,真正频繁读 flash 的是加载常量、网页资源、字库这类操作。日常做 WiFi 透传、传感器上报、简单网页服务,DOUT 和 QIO 的体感差异几乎为零。只有在频繁读大文件(比如每秒吐几十 KB 的网页资源)的场景下,才能测出吞吐量的差距。
所以我的默认策略很明确:能跑 DOUT 就跑 DOUT,别为了那点理论带宽去赌硬件兼容性。稳定比快重要,尤其是设备要放在角落里连续跑几个月的时候。
2. 拿到固件包先别急着点烧录:文件与地址的对应关系
固件包解开之后通常是一堆 bin 文件,名字还都挺像,boot_v1.7.bin、user1.4096.new.6.bin、esp_init_data_default_v08.bin、blank.bin。新手最常见的错误是把它们一股脑全选上,然后指望烧录工具自动分配地址——大部分工具并不会,它会让你一个个手填,填错一个就是白忙活。
2.1 一个完整的 32Mbit 固件包里都有什么
每个文件都有明确分工,缺一个都可能出问题:
- boot_v1.x.bin:二级引导程序。芯片上电后先跑 ROM 里的固件,ROM 再去 flash 起始地址加载这个 boot,由它完成时钟初始化、把应用固件搬到 RAM 或者配置好 XIP 映射,最后跳转过去。不同大版本的 boot 不能混用,AT 固件一般配套 v1.6 或 v1.7。
- user1.xxxx.new.x.bin:应用固件本体,也就是 AT 指令集那一套逻辑,文件体积通常几百 KB。文件名里的数字一般表示适配的 flash 容量(4096 就是 4MB)和编译批次。
- esp_init_data_default_v0x.bin:射频初始化参数,体积很小,一般 128 字节。它里面存的是晶体校准值、发射功率、频偏补偿之类的数据,位置固定,不能乱放。
- blank.bin:全 0xFF 的空文件,用来擦除指定的参数扇区。它本身没内容,作用是"把这块区域清干净",让 SDK 下次启动时重新生成默认值。
这里要特别强调一句:boot 和 user 的版本必须匹配。我遇到过有人从旧包里拿了 boot_v1.5,又从新包里拿了 user1,结果模块能启动、串口也有输出,但一执行联网指令就复位。这种"半新半旧"的组合是最难查的,因为日志看起来一切正常。
2.2 4MB flash 的地址表,抄下来贴在显示器边上
下面这张表是 4MB(32Mbit)AT 固件最常见的烧录组合,我把每个地址为什么是这个值也标出来了:
| 文件 | 起始地址 | 为什么是这个地址 |
|---|---|---|
| boot_v1.7.bin | 0x00000 | 芯片 ROM 固定从 0x0 开始加载引导程序 |
| user1.4096.new.6.bin | 0x01000 | 紧跟 boot 之后,4KB 对齐留出 boot 空间 |
| blank.bin | 0x3FB000 | 清空用户参数区(保存 WiFi 配置、AT 状态等) |
| esp_init_data_default_v08.bin | 0x3FC000 | SDK 约定的射频参数区,倒数第二个 4KB 扇区 |
| blank.bin | 0x3FE000 | 清空 RF 校准缓存,强制下次上电重新校准 |
0x3FC000 这个地址怎么来的?4MB 空间是 0x000000 到 0x3FFFFF,最后一个 4KB 扇区是 0x3FF000,倒数第二个是 0x3FE000,倒数第三个就是 0x3FC000。SDK 把这几个扇区留作特殊用途,不会分配给程序或文件系统。所以只要你的片子是 4MB,这个地址就是死的,不存在"因地制宜"的空间。
顺便说一下 OTA 的布局。如果固件支持空中升级,那 user1 和 user2 要各占一块。常见的做法是 user1 在 0x01000,user2 在 0x101000,正好相差 1MB,两个区各留 1MB 的空间,剩下的 2MB 左右给文件系统和参数区。这种布局刷的时候两个 user 区都要写,只写 user1 的话,第一次 OTA 升级会失败,因为目标区是空的,校验通不过。
各家发布固件时给的地址表可能略有出入,动手前先翻一遍包里自带的说明文件,以它为准。我上面这张表是最常见的一套,但不是唯一的一套。
2.3 射频参数文件丢了,会出现"能启动但连不上网"的怪病
esp_init_data_default.bin这个文件体积最小,最容易被忽略,但它出问题时的症状特别迷惑人:模块能正常上电、串口日志一切正常、发 AT 指令也有 OK 回应,唯独AT+CWLAP扫不到任何热点,或者勉强扫到几个但信号强度全是 -90 多,连上去几秒钟就掉线。
原因在于,ESP8266 的射频部分需要一组校准数据才能正常工作,这组数据在出厂时由产线烧进 flash 的固定地址。SDK 启动时会去读,读不到就退回到一组内部默认值。内部默认值能保证芯片不死,但校准精度很差,接收灵敏度会掉一大截,表现就是"看着活着,实际残废"。
修复方法很简单:把esp_init_data_default.bin补烧到 0x3FC000,再把blank.bin烧到 0x3FE000,让模块下次上电时重新走一遍校准流程。校准大概需要几百毫秒,期间电流会有一个小尖峰,所以供电一定要足——这也是为什么很多人补烧完参数后,模块反而开始反复重启,其实是电源带不动校准时的电流。
有些 AT 固件提供了AT+RESTORE指令,效果相当于恢复出厂设置,会重新生成参数区。但注意它不会帮你把esp_init_data写回去,如果这个扇区本身被擦成了 0xFF,还是得手动烧。
3. 串口烧录的完整操作链路
工具和参数都清楚了,接下来是动手环节。这一节我按实际操作顺序走一遍,把每一步容易翻车的地方都标出来。整个流程大概五分钟,但如果你跳过前面的确认动作,可能会花掉一整个下午。
3.1 硬件接线:两个比接线本身更容易被忽略的细节
先列一下标准接线(以常见的 USB 转 TTL 小板子为例):
| 模块引脚 | 接到哪里 | 说明 |
|---|---|---|
| VCC | 3.3V 独立电源 | 千万别接 5V,也别指望 TTL 板子上的 3.3V 引脚 |
| GND | 电源地 + TTL 地 | 必须共地,否则通信全是乱码 |
| TX | TTL 的 RX | 交叉接 |
| RX | TTL 的 TX | 交叉接 |
| CH_PD (EN) | 3.3V,加 10K 上拉 | 悬空会一直复位 |
| GPIO0 | 烧录时拉低,运行时要高 | 决定进下载模式还是启动模式 |
| GPIO15 | 10K 下拉到地 | 悬空会启动失败 |
| GPIO2 | 悬空或上拉 | 不要拉低 |
第一个细节是供电。ESP8266 在发射瞬间的峰值电流能到 300mA 以上,而大多数 USB 转 TTL 小板子上的 3.3V 引脚是从 USB 的 5V 经过一颗小封装 LDO 降下来的,持续输出能力也就 100mA 出头。平时跑着看不出问题,一到烧录或者联网瞬间就掉压,表现为烧录到 60% 突然断开、或者模块不停重启。我的做法是单独用一个 3.3V 的 LDO 供电,输出端并一颗 100μF 的电解加一颗 0.1μF 的陶瓷电容,成本几块钱,能省掉一大半诡异问题。
第二个细节是GPIO0 的时序。手动烧录时,正确顺序是:先把 GPIO0 拉低,再上电或者复位,等芯片进入下载模式后再松开。顺序反了,芯片已经正常启动了,这时候再拉低 GPIO0 是不起作用的,你得重新复位一次。带自动下载电路的板子(用 DTR 和 RTS 两个信号通过三极管控制 EN 和 GPIO0)就没这个烦恼,但前提是电路设计正确。如果 esptool 一直报 "Failed to connect",先试试加--before no_reset参数,然后手动按一下复位键。
3.2 esptool 命令逐项拆解,每个参数都有它的道理
完整命令长这样:
esptool.py --port /dev/ttyUSB0 --baud 460800 \ write_flash \ --flash_mode dout \ --flash_freq 40m \ --flash_size 4MB \ 0x00000 boot_v1.7.bin \ 0x01000 user1.4096.new.6.bin \ 0x3FB000 blank.bin \ 0x3FC000 esp_init_data_default_v08.bin \ 0x3FE000 blank.bin逐项说一下:
--baud 460800:传输波特率。理论上可以拉到 921600,但那对线材和 TTL 芯片要求很高,劣质板子会丢包。460800 是个比较稳的折中,如果你的板子连这个都跑不了,直接降到 115200,只是慢一点。--flash_mode dout:这是写进 bin 文件头部的一个标志位,芯片 ROM 启动时会读它来决定用哪种 SPI 模式去加载固件。这个参数一旦写错,固件本身再对也启动不了,因为 ROM 根本读不出正确的数据。--flash_freq 40m:SPI 时钟频率。4MB 的片子大多支持 40MHz,部分支持 80MHz。除非你的固件明确要求 80M,否则老老实实 40M,稳定第一。--flash_size 4MB:告诉 SDK 实际容量,影响分区表计算。有些老版本工具里这个值显示成"32Mbit",是同一个意思。- 地址和文件成对出现,顺序不能乱。写反了,固件就跑到别的地址上去了。
还有一个可选参数--erase_all。加上它会先全片擦除再写,速度慢一些(4MB 全擦大概几十秒),但能彻底清掉旧固件残留的参数和配置。我第一次刷一块来源不明的模组时,一定会加这个参数,因为你永远不知道上一任主人往里写了什么。
3.3 图形化工具的五个下拉框,三个是重灾区
不习惯命令行的朋友大多会用图形化的烧录工具,界面挺友好,但有几个下拉框一旦选错,同样是白忙活。我把它们列出来:
| 选项 | 正确值 | 选错的后果 |
|---|---|---|
| CrystalFreq | 26M | 选成 40M,串口日志全变乱码,看着像模块坏了 |
| SPI SPEED | 40MHz | 选 80MHz 可能烧完启动不了 |
| SPI MODE | DOUT | 选 QIO 会导致启动时 flash 读取失败 |
| FLASH SIZE | 32Mbit | 选 16Mbit 会截断分区,文件系统挂载失败 |
| DoNotChgBin | 不勾选 | 勾选后工具不重写文件头,上面前三项设置基本失效 |
最后一项特别坑。有些工具默认勾选了"不修改 bin 文件",意思是它不会把你在界面上选的 flash 参数写进文件头,而是沿用 bin 里自带的参数。这时候你在界面上选 DOUT 其实没用,实际生效的还是 bin 里的原始值。如果不是有特殊需求,这个勾一定要去掉。
另外,用图形化工具时文件地址是手填的,很多人填完第一个就顺手复制粘贴,结果五个文件全填成 0x00000,最后只有一个生效,其它全被覆盖。填完地址后花十秒钟扫一眼,比烧完再排查省事得多。
3.4 烧完之后必须做的三个校验动作
烧录工具最后打印 "Hash of data verified" 只代表数据写进去了、读回来对得上,不代表能正常运行。我一般会再做三件事:
第一,读回比对。把整片 flash 读出来存成文件,跟原始 bin 做哈希比对:
esptool.py --port /dev/ttyUSB0 read_flash 0x0 0x400000 dump_check.bin md5sum dump_check.bin这一步能发现"工具说成功、实际某些扇区写失败"的情况。尤其是用劣质 USB 线的时候,这种静默失败并不罕见。
第二,看启动日志。关键点来了:ESP8266 上电时 ROM 打印的启动信息固定是 74880 波特率,不是 115200。很多人烧完打开串口助手,看到一堆乱码就以为刷坏了,其实是波特率不对。把串口切到 74880,你应该能看到类似这样的内容:
ets Jan 8 2013,rst cause:2, boot mode:(3,6) load 0x4010f000, len 3456, room 16 tail 0 chksum 0x84 csum 0x84boot mode:(3,6)里的第一位是 3,表示从 flash 启动;如果是 1,说明 GPIO0 还处于低电平,芯片停在下载模式没出来。
第三,切回 115200 发 AT。启动日志走完之后,应用固件的串口就切到 115200 了。发一条AT,正常会回OK。如果没反应,先检查串口助手有没有勾"发送新行"——AT 指令必须以回车换行结尾,这是个经典到不能再经典的坑。
4. 烧录之后启动异常,按这个顺序排查
即使前面每一步都做对了,也还是有可能出问题。这一节我把遇到过的几种典型症状按"排查成本从低到高"排个序,你照着走一遍,八成能定位到原因。
4.1 启动日志打印到一半卡住,先看 boot mode 第二位
典型症状是串口输出:
ets Jan 8 2013,rst cause:2, boot mode:(3,6) load 0x4010f000, len 3456, room 16 tail 0 chksum 0x84 csum 0x84然后就没了,正常情况下这后面应该紧跟着打印当前固件的版本信息、flash map 之类的内容。
这种情况九成是 SPI 模式不匹配。ROM 能用默认方式把 boot 加载起来一小段,但真正开始大量读取 flash 的时候就崩了。解决方法是重新烧一遍,把--flash_mode从 qio 改成 dout(或者反过来试)。判据很简单:原厂固件读出来的头部是什么模式,你就用什么模式。
第二种可能是--flash_freq太高。把 80m 降到 40m 再试一次,有的模组标称支持 80M,实际走线质量差,跑高频就出错。
第三种可能是供电问题。启动瞬间的电流尖峰把电压拉垮,芯片复位。判断方法是拿万用表盯着 3.3V 引脚,看启动瞬间有没有明显跌落。有,就换供电。
4.2 启动正常但发 AT 不回 OK,别急着怀疑固件
先说结论:大部分"AT 不回"都不是固件的问题,是串口配置的问题。按这个顺序查:
- 波特率对不对。AT 固件默认 115200,但有些定制版本改成过 9600。慢动作试一遍 9600、57600、115200 三个值。
- 发送新行勾没勾。AT 指令必须以
\r\n结尾,光发一个 "AT" 不带换行,模块是收不到的。这是新手第一大坑。 - 是不是烧错了固件。如果你的包里 user1 那个文件是某个 SDK 的示例程序而不是 AT 固件,它当然不会响应 AT 指令。看文件名,AT 固件一般带 "AT" 字样或者发布说明里会写明。
- 模块是不是在反复重启。把串口助手一直开着,如果每隔一两秒就刷一遍启动日志,说明供电或者 flash 有问题,压根没走到应用层。
还有一种情况:模块确实在跑,但串口被别的程序占用了。Windows 上这种情况很常见,打开设备管理器看一眼 COM 口是不是灰色的,或者干脆重启一下串口助手。
4.3 能连上热点但 OTA 升级失败,问题多半在 flash_size 上
这个坑比较隐蔽。表现是:模块工作正常,能连 WiFi,能收发数据,唯独一执行 OTA 升级就报错,或者升级过程中断,重启后回到旧固件。
根因通常是烧录时--flash_size填的值和固件编译时假设的容量不一致。比如固件是按 4MB 布局编译的,OTA 升级时它打算往 0x101000 写新固件,但你烧录时--flash_size填的是 2MB,芯片会认为 0x101000 已经在边界之外,写入直接失败。
排查方法:先flash_id确认物理容量,再翻一遍固件发布说明里写的适配容量,两个必须对上。如果对不上,要么换固件,要么换模组,没有第三条路。
还有一个容易忽略的点:OTA 需要两个 user 区都是有效的。有些人只烧了 user1,user2 区域是空的。第一次 OTA 的时候,bootloader 会去校验目标区,发现是空的就拒绝切换。所以烧 OTA 版本的固件时,如果包里给了 user2 文件,记得一起烧上,地址一般是 user1 加 1MB。
5. 32Mbit 布局下要不要开 OTA,这是个空间账
4MB 听起来不少,但真要开双区 OTA,一半空间就没了。这块账得提前算清楚,因为一旦烧录布局定下来,后面改起来很麻烦。
5.1 OTA 对 flash 空间的硬性要求
OTA 的基本原理是:当前运行的固件在 user1 区,新固件下载到 user2 区,校验通过后修改启动标志,下次重启就从 user2 启动。这样即使升级失败,还能回滚到 user1。代价是两个区必须一样大,且都要能装下固件。
4MB 空间里,boot 占 4KB,两个 user 区各 1MB,参数区和射频区占掉最后 20KB 左右,剩下大约 1.9MB 给文件系统。这个配置下,应用固件最大不能超过 1MB——AT 固件通常只有 600KB 左右,够用;但如果你自己写了带网页资源、字库的程序,很容易超。
如果不开 OTA,可以把 user2 那 1MB 让出来给文件系统,文件系统能到接近 3MB。这个差异在存网页、存配置、存日志的场景下非常明显。我一般这么决策:
| 使用场景 | 建议布局 | 理由 |
|---|---|---|
| 只做串口透传、AT 指令 | 不开 OTA,文件系统最大化 | 固件很少更新,空间给数据更划算 |
| 需要远程升级的设备 | 开 OTA,双 1MB | 现场设备没法拆,必须留后路 |
| 固件接近 1MB | 不开 OTA | 开了也装不下,不如老实走串口 |
| 频繁迭代的开发阶段 | 开 OTA | 省掉反复插线的麻烦 |
5.2 编译选项和烧录参数必须保持一致
这里有个特别容易忽略的一致性要求:编译时选的分区方案,必须和烧录时写的 flash_size 一致。
以常见的开发环境为例,4MB 的板子通常提供好几个选项,什么"4MB (FS:1MB OTA:~2MB)"、"4MB (FS:3MB OTA:~512KB)"、"4MB (FS:none OTA:~4MB)"。这些选项本质上就是不同的分区表,编译出来的固件里已经写死了各个区的起始地址。
如果你编译时选了"FS:3MB"的方案,烧录时却按"FS:1MB"的地址表去写,参数区的地址就对不上,表现是文件系统挂载失败、或者保存的配置重启就丢。这种问题的排查成本极高,因为日志里只会打印一句"mount failed",看不出所以然。
我的习惯是:在项目目录里放一个 README,把编译选项、烧录命令、地址表一次性写清楚,换电脑或者过几个月再回来,照着抄一遍就行,不用重新回忆。
6. 几个我踩出来的习惯,能省不少时间
折腾的次数多了,慢慢形成了一套固定的动作,写出来供参考。
6.1 拆封第一件事:把原厂固件完整备份下来
拿到任何一块来源不明的模组,在动它之前先读一遍全片:
esptool.py --port /dev/ttyUSB0 --baud 460800 read_flash 0x0 0x400000 backup_original.bin这个备份的价值在于:万一刷废了,或者发现新固件不如旧的好用,还能原样刷回去。尤其是那些带定制参数的模组,射频校准数据是产线逐台烧的,丢了就再也找不回来,只能重新校准,而个人玩家根本没有校准设备。
我吃过这个亏。有一块模组刷完之后信号一直很差,怀疑是射频参数被覆盖了,想把原厂固件读回来对比,结果发现压根没备份。最后只能拿另一块同型号的模组读出来救急,但那个校准值毕竟是另一台机器的,效果打了折扣。
6.2 供电和线材的投入,永远是最划算的
前面提过供电,这里再说一次,因为它实在太重要了。烧录失败的原因里,供电问题能占一半以上。一个稳定输出的 LDO、两颗滤波电容、一根短一点的优质 USB 线,加起来不到二十块钱,能帮你排除掉大量"看起来像固件问题其实是硬件问题"的故障。
判断供电是否够用的土办法:让模块持续发送数据(比如开个 TCP 连接一直发包),同时用万用表量 3.3V 引脚,如果电压在 3.2V 到 3.4V 之间小幅波动,说明还行;如果掉到 3.0V 以下,或者波动幅度超过 0.2V,赶紧换供电方案。
6.3 文件命名带上这四个字段,一年后还能看懂
固件文件多了之后,光看文件名根本分不清哪个是哪个。我现在的命名规则是:
ESP8266_4MB_DOUT_ATv1.7_20240315.bin芯片型号、容量、SPI 模式、固件版本、日期,五个字段一目了然。配合一个简单的文本记录,写上每个版本的烧录地址表和验证结果,基本上不会出现"翻遍硬盘找不到能用那个版本"的窘境。
另外,我给每块模组贴一个小标签,写上烧录日期和固件版本。模组外形都一样,堆在一起根本认不出谁是谁,标签能省掉大量重复劳动。
最后分享一个小技巧:如果你的模组刷完之后一切正常,但偶尔(比如几天一次)会自己重启,先别怀疑固件。把串口日志留着,看上电日志里的rst cause,如果是 2(外部复位)或 4(看门狗),多半是供电波动或者程序里有死循环;如果是 1(上电复位),那基本可以确定是电源问题了。日志里这一行信息,比任何猜测都值钱。