3、烧录协议解析:常见的串口烧录协议原理
说到串口烧录,很多人第一反应就是「把 hex 文件扔进工具,点一下下载就完事了」。但你要是真这么想,遇到某些奇葩芯片或者自己写 bootloader 的时候,就会一头雾水。
我刚开始做嵌入式那会儿,也踩过这个坑。有一次用某国产芯片,官方工具死活连不上,折腾了两天才发现——它用的不是标准 STK500,而是魔改版。从那以后,我就养成了一个习惯:不管用什么芯片,先把它的烧录协议搞清楚。
这一章,咱们就来聊聊三种最常见的串口烧录协议:STK500、ISP 和 UART Bootloader。说白了,它们都是「主机通过串口跟目标芯片的引导程序对话」的规矩。但规矩和规矩之间,差别还挺大的。
3.1 STK500 协议
STK500 是 Atmel(现在的 Microchip)最早为 AVR 系列单片机设计的烧录协议。名字来源于他们的一款开发板——STK500 开发板。后来这个协议被广泛采用,成了 AVR 芯片烧录的事实标准。
我个人觉得,STK500 最大的特点是命令-应答模式。主机发一条命令,芯片必须回一条应答。有点像两个人打电话,你说一句,对方必须回一句「收到」,才能继续往下说。
协议帧格式
STK500 的每一帧数据都很简单:
+--------+--------+--------+--------+--------+
| 0x1B | 0x0D | 命令码 | 数据段 | 校验和 |
+--------+--------+--------+--------+--------+
| 同步头 | 同步头 | 1字节 | N字节 | 1字节 |
+--------+--------+--------+--------+--------+
- 同步头:固定 0x1B 0x0D,用来告诉芯片「我要开始说话了」。
- 命令码:比如 0x41 表示「读取签名」、0x45 表示「编程页」。
- 数据段:根据命令不同,长度可变。
- 校验和:前面所有字节的异或和。
典型交互流程
一个完整的烧录过程,大概分这么几步:
- 进入编程模式:主机发送 0x50(进入编程模式命令),芯片回复 0x14 0x00(表示就绪)。
- 读取签名:主机发 0x41,芯片回复 3 字节的芯片签名(比如 0x1E 0x95 0x0F 表示 ATmega328P)。
- 擦除芯片:主机发 0x45(擦除命令),芯片擦除后回复 0x14 0x00。
- 编程页:主机把一页数据(比如 128 字节)发过去,芯片写入后回复确认。
- 校验:主机发 0x42(读取页命令),把刚写进去的数据读回来比对。
- 退出编程模式:主机发 0x51,芯片复位并退出。
核心要点:STK500 是半双工协议。主机发完一条命令后,必须等芯片回复,才能发下一条。不能像串口透传那样噼里啪啦一顿发。
3.2 ISP 协议
ISP(In-System Programming),也叫在线编程。它跟 STK500 最大的区别是:ISP 通常使用 SPI 接口,而不是 UART。但很多人在串口烧录的语境下提到 ISP,其实指的是「通过串口转 SPI 的烧录方式」。
你想想看,芯片的 SPI 引脚(MOSI、MISO、SCK、RESET)本来是用来跟外设通信的。ISP 就是利用这四根线,外加一根 RESET 线,在芯片正常运行时强行把它拽进编程模式。
ISP 的硬件连接
| 主机端 | 目标芯片端 | 说明 |
|---|---|---|
| MOSI | MOSI | 主机输出,芯片输入 |
| MISO | MISO | 芯片输出,主机输入 |
| SCK | SCK | 时钟信号,由主机提供 |
| RESET | RESET | 拉低复位,再拉高进入编程模式 |
ISP 的协议特点
ISP 协议本身比 STK500 更底层。它不关心你发的是什么命令,只负责把字节通过 SPI 总线传过去。具体的命令解析,由芯片内部的 bootloader 完成。
举个例子,AVR 的 ISP 协议里有一个「编程使能」命令:主机发 0xAC 0x53 0x00 0x00,芯片如果回复 0xAC 0x53 0x00 0x00(后两个字节回显),就说明进入编程模式成功了。
我记得第一次调 ISP 的时候,死活收不到正确的回显。后来用示波器一看,原来是 MISO 引脚虚焊了。嗯,硬件问题永远比软件问题更隐蔽。
3.3 UART Bootloader
UART Bootloader 是目前最灵活、也最常用的一种烧录方式。它不需要额外的编程器,只需要一根 USB 转串口线,就能给芯片烧程序。
它的原理其实很简单:芯片出厂时,内部有一段固化的引导程序(bootloader)。上电后,bootloader 先跑起来,通过 UART 等待主机发来的命令。如果在一定时间内收到合法的烧录命令,就进入编程模式;否则就跳转到用户程序。
典型的 UART Bootloader 流程
上电复位
│
▼
运行 Bootloader
│
├── 检测到烧录请求(如特定引脚电平或串口数据)
│ │
│ ▼
│ 进入编程模式
│ │
│ ├── 接收固件数据(通常用 YMODEM 或 XMODEM 协议)
│ ├── 写入 Flash
│ ├── 校验
│ └── 跳转到用户程序
│
└── 未检测到请求
│
▼
跳转到用户程序
关键点:UART Bootloader 的「检测窗口」通常只有几百毫秒。如果主机在这段时间内没发命令,芯片就认为「没有要烧录的程序」,直接跑用户代码了。所以很多工具在点击「下载」之前,需要先手动复位芯片。
常见的 UART Bootloader 协议
| 协议名称 | 特点 | 典型芯片 |
|---|---|---|
| ST 的 System Bootloader | 使用 USART1,支持自动波特率检测 | STM32F1/F4 系列 |
| ESP32 的 ROM Bootloader | 支持压缩传输,速度较快 | ESP32、ESP8266 |
| NXP 的 ISP Bootloader | 使用 UART0,支持 ISP 命令集 | LPC17xx、LPC11xx |
| 自定义 Bootloader | 开发者自己写的,协议可定制 | 任何带自编程能力的 MCU |
我个人比较喜欢 STM32 的 System Bootloader。它有一个很贴心的设计:自动波特率检测。主机先发一个 0x7F,bootloader 根据这个字节的脉宽自动算出波特率。这样一来,就算上位机设置的波特率跟芯片预期的不完全一致,也能正常通信。
3.4 三种协议的对比
说了这么多,咱们来做个横向对比。这样你以后选方案的时候,心里就有数了。
| 特性 | STK500 | ISP | UART Bootloader |
|---|---|---|---|
| 物理层 | UART | SPI | UART |
| 是否需要编程器 | 需要(如 USBasp) | 需要(如 USBtinyISP) | 不需要,串口线即可 |
| 协议复杂度 | 中等 | 简单 | 取决于实现 |
| 速度 | 较慢(受 UART 波特率限制) | 较快(SPI 时钟可达数 MHz) | 中等(受 UART 波特率限制) |
| 适用场景 | AVR 系列芯片 | 支持 SPI 编程的芯片 | 带 ROM Bootloader 的芯片 |
| 是否需要修改硬件 | 需要连接编程器 | 需要引出 SPI 引脚 | 只需要串口 TX/RX |
你可能会问:「那我到底该用哪个?」
我的建议是:如果芯片自带 UART Bootloader,优先用它。因为不需要额外硬件,一根串口线就能搞定。如果芯片没有,那就看有没有现成的 ISP 编程器。实在不行,再考虑自己写一个 bootloader。
3.5 本章小结
这一章咱们聊了三种常见的串口烧录协议。STK500 是 AVR 的老牌协议,命令-应答模式很清晰;ISP 用 SPI 总线,速度更快但需要额外引脚;UART Bootloader 最灵活,适合量产和调试。
理解这些协议的原理,不是为了让你去手写一个 bootloader(当然,如果你有兴趣,完全可以试试),而是为了在遇到烧录失败的时候,能快速定位问题——是时序不对?是校验出错?还是芯片根本没进入编程模式?
下一章,咱们会把这些协议的知识用起来,开始搭建数据采集的环境。到时候你会发现,今天学的这些东西,全都能派上用场。