1、烧录速度瓶颈分析:为什么你的固件烧得这么慢?
大家好,我是你们的老朋友。做嵌入式这些年,我见过太多工程师在烧录器前面干等——进度条走得像蜗牛,一杯咖啡喝完了还没到 50%。
你想想看,明明芯片支持高速烧录,为什么实际速度就是上不去?
今天咱们就从三个维度来拆解:波特率、协议开销、驱动能力。这三个点,基本覆盖了 90% 的烧录慢问题。
核心观点:烧录速度不是由「理论波特率」决定的,而是由「有效数据传输率」决定的。说白了,你设了 115200,实际可能连 30% 的带宽都没用上。
1.1 波特率:你以为设了就能跑?
波特率是串口通信的「车速」。115200 bps 听起来很快,但实际能跑多少,取决于几个硬条件。
第一个坑:时钟源精度。
我遇到过好几次,工程师把波特率设到 921600,结果烧录一半就报错。为什么?因为 MCU 内部 RC 振荡器精度不够。比如某些国产 MCU,内部 RC 误差 ±3%,在 115200 以下还能忍,到了 460800 以上,误差直接导致采样点偏移,数据就全乱了。
我的经验:用外部晶振(8MHz 或 16MHz)做时钟源,波特率可以稳定跑到 921600。内部 RC 振荡器的话,建议最高只用到 115200,再高就是赌运气。
第二个坑:分频误差。
串口波特率是靠系统时钟分频得到的。举个例子,系统时钟 16MHz,要得到 115200,分频系数 = 16000000 / (16 × 115200) ≈ 8.68。取整后实际波特率是 16000000 / (16 × 9) = 111111,误差 3.5%。
这个误差在短时间通信里问题不大,但烧录固件动辄几十 KB,累积下来就会丢字节。
| 目标波特率 | 16MHz 实际波特率 | 误差 | 烧录稳定性 |
|---|---|---|---|
| 9600 | 9615 | 0.16% | ✅ 非常稳定 |
| 115200 | 111111 | 3.5% | ⚠️ 短包可用 |
| 460800 | 444444 | 3.6% | ❌ 容易丢包 |
| 921600 | 888888 | 3.6% | ❌ 基本不可用 |
避坑指南:我曾经在一个项目里,为了追求速度把波特率设到 2Mbps,结果 10 块板子有 3 块烧录失败。查了两天才发现是某批次 MCU 的 RC 振荡器偏了 5%。从那以后,我养成了习惯——量产前先测一批芯片的实际波特率误差。
1.2 协议开销:你传的 1 个字节,真的只占 1 个字节?
很多人以为串口传 1 个字节就是 8 个 bit。其实不是。
标准 UART 帧格式是:1 个起始位 + 8 个数据位 + 1 个校验位(可选)+ 1 个停止位。也就是说,传 1 个有效字节,实际要发 10 到 11 个 bit。
这还只是物理层的开销。更狠的是协议层的开销。
常见的烧录协议开销:
- 应答机制:每发一包数据,要等 MCU 回 ACK。一来一回,时间翻倍。
- 校验字段:CRC16 或 CRC32,每包多占 2~4 个字节。
- 地址/长度头:很多协议每包要带 4 字节地址 + 4 字节长度。
- 帧间隔:MCU 处理完一包需要时间,这期间总线是空闲的。
我算过一笔账:一个典型的 YModem 协议,有效数据载荷只有 128 字节,但加上头、校验、应答,实际传输量接近 200 字节。协议效率只有 64%。
关键数据:波特率 115200,理论每秒传 11520 字节。但扣除协议开销后,实际有效数据吞吐量往往只有 4000~6000 字节/秒。你想想看,一个 256KB 的固件,光传输就要 40~60 秒。
怎么优化?
- 用大包传输(比如 1KB 一包),减少头校验占比。
- 取消逐包应答,改用连续发送 + 批量校验。
- 去掉不必要的校验字段(如果物理链路可靠)。
我个人的习惯:在开发阶段用完整协议(带 CRC 和应答),方便调试。量产时切换到「快速模式」——去掉应答,只做帧尾校验。速度能提升 30%~50%。
1.3 驱动能力:信号到了,MCU 接不住
这个维度最容易被忽略。很多人觉得波特率设高了,线接好了,速度自然就快。其实不然。
线缆长度和寄生电容。
串口信号是电压型的。线缆越长,寄生电容越大,信号边沿就越缓。当波特率超过 115200 时,如果线长超过 1 米,上升沿可能已经占了一个 bit 的 30%~50%。这时候接收端采样到的电平就是错的。
我做过测试:3 米长的杜邦线,115200 波特率下,眼图已经闭合了 40%。
电平转换芯片的驱动能力。
很多开发板用 CH340G、CP2102 这类 USB 转串口芯片。它们的驱动能力有限,在 3.3V 电平下,最大只能稳定驱动 1 米左右的线缆。如果板子离烧录器远,信号质量会急剧下降。
MCU 内部 Flash 写入速度。
这是最容易被忽视的瓶颈。MCU 收到数据后,要写入 Flash。Flash 写入是有时序要求的——比如 STM32F103,单字节写入需要约 50μs,页写入(256 字节)需要约 1ms。
你算一下:如果每收到 1 个字节都要等 50μs,那 115200 波特率下,MCU 的处理速度反而成了瓶颈。因为 1 个字节的传输时间只有约 87μs,MCU 处理就要 50μs,留给协议处理的时间就很少了。
| MCU 型号 | Flash 写入方式 | 单次写入时间 | 最大吞吐量 |
|---|---|---|---|
| STM32F103 | 半页写入 (128B) | ~1ms | ~128 KB/s |
| GD32F303 | 页写入 (256B) | ~0.8ms | ~320 KB/s |
| ESP32 | 块写入 (1024B) | ~3ms | ~341 KB/s |
避坑指南:我曾经在一个项目里,把波特率从 115200 提到 460800,结果烧录时间反而变长了。查了半天才发现——MCU 的 Flash 写入速度跟不上,数据在缓冲区里堆积,导致溢出丢包。后来我把写入方式从单字节改成页写入,速度才真正提上来。
小结:三个维度,一个短板
烧录速度的瓶颈,说白了就是「木桶效应」。波特率、协议开销、驱动能力,哪个最差,哪个就是你的实际速度。
- 波特率:时钟源精度和分频误差决定了你能跑多快。
- 协议开销:帧格式、应答、校验,这些「隐形字节」吃掉了一半带宽。
- 驱动能力:线缆、电平转换、Flash 写入速度,硬件底子决定了上限。