在手机上使用 esptool 为乐鑫 ESP 系列 MCU 刷写固件
需求
有时候人在外面,手里只有一个 OTG 头和一根数据线,想要用手机为 ESP32/ESP8266 等 MCU 刷入固件。
第一次尝试
一开始我的想法很简单:既然乐鑫官方的刷写工具esptool
是 Python 开发的,那就直接在手机上装个 Python 之后使用其进行刷入就行了。于是便下载termux
并且安装了 Python:
apt update
apt install python python-pip
随后用pip3
,安装esptool
:
pip3 install esptool
但是由于 termux 源的软件版本问题,在编译cryptography
库的过程中,rust 爆红。由于我并不熟悉 rust,所以选择安装 termux 源内预先编译好的 cryptography 库:
apt install python-cryptography
安装完成后,再次尝试安装 esptool,显示安装成功。
将 ESP32-S3 开发板用 OTG 线连接至手机,随后发现:我的手机没有 root 权限,无法访问/dev 目录。随后查阅相关资料发现shell
用户可以访问/dev 目录,于是便启动无线调试后连接到本地终端,但发现/dev/下没有生成ttyUSBx
设备。
原因分析
Android 对 USB 设备的访问权限控制较为严格,APP 只能通过 Java API 访问 USB 设备,且只能获取到/dev/bus/usb/xxx/xxx
这样的字符设备(character device)
的文件描述符(file descriptor)
。再者,Android 内核一般都没有加入 USB 转串口设备支持,所以无法生成对应的设备节点。
第二次尝试
经过搜索后,发现可以使用termux-api
来实现访问 USB 设备,于是下载安装之。随后在 termux 中,使用命令:
termux-usb -l
能够成功地枚举到 USB 设备。
二次分析
esptool 依赖pyserial
库实现对串口设备节点的访问,而 pyserial 并没有内置串口驱动程序。这里举一个例子:使用/dev/ttyUSB0 设备来向 RX 方发送一个字节的数据,可能只需要一个简单的write()
,但如果使用/dev/bus/usb
字符设备,可能就需要先获取那个设备的通讯端点,然后向端点写入数据,而且不同厂商对写入数据的格式,大小等等都有不同的标准。
第三次尝试
我原本的想法是,使用libusb
库,将串口读写数据、设置波特率、流控等封装为函数,再交给 pyserial 进行调用,随后发现在 esptool 的源代码中,对流控(CTS,DTR)的控制方法被写死为ioctl
操作,所以在不修改 esptool 的情况下实现自动下载的话应该是不行了(主要是太懒)。
最终解决方案
最后在某个笨蛋的帮助下,找到了一款串口 TCP/IP 透传软件:TCPUART。使用方法也很简单:设置波特率,点击 Connect,然后点击 Start 启动服务,启动完毕之后在 esptool 那边就可以用socket://
协议来访问串口并且刷入固件了:
#读取芯片ID
esptool.py --before no_reset --after no_reset --port socket://localhost:8080 chip_id
#刷入固件
esptool.py --before no_reset --after no_reset --port socket://localhost:8080 write_flash -e -fs detect -fm keep 0x0 <文件名>
不足之处
- 无法自动复位进入下载模式,烧录之前必须手动进入下载模式
- 连接不是很稳定
- TCPUART 支持的串口芯片较少(不支持 CH343P,只能通过 ESP32S3 的原生 USB 口下载)