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 表示「编程页」。
  • 数据段:根据命令不同,长度可变。
  • 校验和:前面所有字节的异或和。
我的一点经验:写上位机的时候,校验和最容易出错。很多人只算数据段,忘了把同步头和命令码也算进去。我曾经因为这个 bug 排查了整整一个下午。

典型交互流程

一个完整的烧录过程,大概分这么几步:

  1. 进入编程模式:主机发送 0x50(进入编程模式命令),芯片回复 0x14 0x00(表示就绪)。
  2. 读取签名:主机发 0x41,芯片回复 3 字节的芯片签名(比如 0x1E 0x95 0x0F 表示 ATmega328P)。
  3. 擦除芯片:主机发 0x45(擦除命令),芯片擦除后回复 0x14 0x00。
  4. 编程页:主机把一页数据(比如 128 字节)发过去,芯片写入后回复确认。
  5. 校验:主机发 0x42(读取页命令),把刚写进去的数据读回来比对。
  6. 退出编程模式:主机发 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 的时钟频率不能太高。我见过有人把 SCK 设到 10 MHz,结果芯片根本反应不过来。一般建议不超过芯片主频的 1/4。比如 16 MHz 的 AVR,SCK 最好别超过 4 MHz。

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 根据这个字节的脉宽自动算出波特率。这样一来,就算上位机设置的波特率跟芯片预期的不完全一致,也能正常通信。

避坑指南:我曾经在 STM32F103 上遇到过一个问题——bootloader 能进,但烧录到一半就卡死。后来发现是 Flash 写入时没有关中断。bootloader 里如果开了中断,写入 Flash 的时候一定要先关掉,否则会触发异常。

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(当然,如果你有兴趣,完全可以试试),而是为了在遇到烧录失败的时候,能快速定位问题——是时序不对?是校验出错?还是芯片根本没进入编程模式?

下一章,咱们会把这些协议的知识用起来,开始搭建数据采集的环境。到时候你会发现,今天学的这些东西,全都能派上用场。

串口烧录协议对比框架图 STK500 ISP UART Bootloader 物理层:UART 物理层:SPI 物理层:UART 需编程器 需编程器 仅需串口线 速度:较慢 速度:较快 速度:中等 AVR 系列 支持 SPI 编程的芯片 带 ROM Bootloader 的芯片 选择建议:优先使用 UART Bootloader → 其次 ISP → 最后考虑 STK500