4、固件升级协议基础:UART、SPI、I2C、CAN等物理层协议对比

做固件升级,说白了就是在跟物理层打交道。你选什么协议,直接决定了升级速度、可靠性,甚至能不能升级成功。我这些年经手过不少项目,从简单的传感器升级到复杂的工业网关,每种协议都踩过坑。今天咱们就把UART、SPI、I2C、CAN这四种最常见的协议掰开揉碎了聊一聊。

4.1 UART:最通用的“老黄牛”

UART,也就是串口。这玩意儿几乎每个MCU都有,两根线(TX、RX)就能干活。我个人习惯把它当作固件升级的“保底方案”——不管多老的芯片,只要留了串口,升级就不成问题。

优点很明显:

  • 硬件简单,成本低
  • 全双工,收发互不干扰
  • 协议栈轻量,适合Bootloader

缺点也扎心:

  • 速度慢,典型波特率115200bps,实际有效数据率也就10KB/s左右
  • 没有时钟同步,双方波特率必须严格匹配
  • 抗干扰能力一般,长距离传输容易丢包

升级场景建议:适合小固件(< 100KB)、调试阶段、或者对成本极度敏感的产品。

我的经验:我曾经在一个项目中用UART升级128KB的固件,波特率设到921600,结果发现线缆稍微长一点就疯狂出错。后来老老实实降到115200,加了个简单的CRC校验,反而更稳定。别盲目追求高速,稳定才是第一位的。

4.2 SPI:速度之王,但线多

SPI,四根线(MOSI、MISO、SCLK、CS),全双工,速度轻松上MHz。如果你要升级几百KB甚至几MB的固件,SPI是首选。

为什么快?

  • 独立的时钟线,主从同步,没有波特率误差
  • 全双工,收发可以同时进行
  • 没有起始位、停止位,有效数据率极高

但要注意:

  • 线多,占用IO口多
  • 没有内置的应答机制,需要应用层自己处理
  • 从机不能主动发起通信,只能被动响应

避坑指南:我曾经在SPI升级时遇到过一个问题——从机的MISO引脚在空闲时没有拉高,导致主机误判数据。后来我强制在每次通信前先发一个0xFF来同步,问题才解决。记住:SPI的时序容错性不如UART,硬件设计一定要规范。

4.3 I2C:两线制,但慢

I2C,两根线(SCL、SDA),半双工。它的优势在于接线少,而且支持多主机、多从机。但说实话,做固件升级,I2C有点尴尬。

优点:

  • 只需要两根线,还能挂多个设备
  • 有内置的应答机制(ACK/NACK)
  • 支持多主机仲裁

缺点:

  • 速度慢,标准模式100kHz,快速模式400kHz
  • 半双工,收发不能同时进行
  • 每个字节后面都要跟一个ACK位,有效数据率进一步降低
  • 从机地址冲突问题

升级场景建议:I2C适合小数据量升级(比如配置参数、校准数据),或者当你的MCU只有I2C接口可用时。别用它升级大固件,你会等到怀疑人生。

你想想看,用I2C升级一个512KB的固件,400kHz速率下,理论时间都要十几秒,实际加上协议开销,半分钟都算快的。而SPI可能几秒就搞定了。

4.4 CAN:工业级的可靠之选

CAN总线,两根差分线(CAN_H、CAN_L),半双工。这玩意儿在工业、汽车领域是标配。做固件升级,CAN的可靠性是其他协议比不了的。

核心优势:

  • 差分信号,抗干扰能力极强
  • 内置错误检测和重发机制
  • 多主机,任意节点都可以发起通信
  • 支持优先级仲裁,重要数据优先发送

代价:

  • 硬件成本高,需要CAN收发器
  • 协议复杂,数据帧最大只有8字节(CAN 2.0)
  • 速度上限1Mbps,实际常用250kbps或500kbps

我的经验:我在一个工业网关项目中用CAN升级固件,距离超过100米,现场还有变频器干扰。UART和SPI根本扛不住,但CAN稳如老狗。不过要注意,CAN的数据帧只有8字节,分包和重组逻辑要写得很严谨。我曾经因为一个序号溢出bug,导致升级到一半数据错乱,整批设备都变砖了。从那以后,我强制要求序号用16位,并且每次升级前先擦除整个Flash。

4.5 四种协议对比一览

特性 UART SPI I2C CAN
线数 2(TX/RX) 4(MOSI/MISO/SCLK/CS) 2(SCL/SDA) 2(CAN_H/CAN_L)
通信方式 全双工 全双工 半双工 半双工
典型速率 115200bps ~ 921600bps 1MHz ~ 50MHz 100kHz ~ 400kHz 125kbps ~ 1Mbps
有效数据率 低(有起始/停止位) 高(无协议开销) 中(有ACK位) 低(帧开销大)
抗干扰
硬件成本
协议复杂度 简单 简单 中等 复杂
升级适用场景 小固件、调试 大固件、高速 小数据、配置 工业、长距离

4.6 如何选择?我的建议

没有最好的协议,只有最合适的。我一般按这个思路选:

  1. 先看硬件资源:MCU有什么接口就用什么,别为了升级专门加硬件
  2. 再看固件大小:小于64KB,UART够用;大于256KB,上SPI
  3. 环境因素:有强干扰、长距离,直接上CAN,别犹豫
  4. 成本敏感:UART或I2C,两根线搞定

重要提醒:不管你选哪种协议,升级协议一定要包含以下三个要素:

  • 帧头帧尾:用于数据包同步
  • 序号:防止丢包和乱序
  • 校验:CRC16起步,别用简单的累加和

我曾经见过一个产品用UART升级,只做了简单的和校验,结果现场干扰导致数据错误,升级后设备直接变砖。后来返厂拆机才发现是校验太弱了。

嗯,物理层协议就聊到这儿。下一章咱们会深入讲如何在Bootloader中实现这些协议的驱动,以及怎么处理升级过程中的异常情况。到时候我会拿实际代码出来,咱们一行一行地过。