STM32 DMA 串口接收丢字节?环形缓冲与空闲中断的实战排查

光电手记 发表于 2026-10-30 01:06 · 5 次浏览 · 1 条回复
光
最近调一个 STM32 串口接收项目,波特率 115200,数据一密就丢字节,查了一圈,问题基本都出在接收路径的设计上,分享一下排查顺序。一、先确认是不是中断来不及。串口每字节进一次中断,高波特率下主循环稍有阻塞就会溢出。先看 ORE 标志有没有置位,有就说明接收寄存器没及时搬走,这是最常见的丢字节原因。二、DMA + 空闲中断是正解。DMA 搬运不占 CPU,空闲中断判断一帧结束。注意两点:DMA 要配循环模式,缓冲区用环形结构;空闲中断里先清标志再读 DMA 剩余计数,算出本帧长度,否则容易多算或少算一帧。三、环形缓冲的读写指针要防竞态。写指针在中断里推进,读指针在主循环里推进,判满判空别用相等,要留一个空位或者用计数器,否则满和空分不清,数据会被悄悄覆盖。四、别忽视时钟和波特率误差。内外时钟偏差超过 2%,长帧必出错,先用示波器量实际波特率,再怀疑软件。五、DMA 半传输中断别滥用。半传输适合双缓冲 ping-pong,单缓冲用它反而容易把一帧拆成两段,解析层要能处理分段。你平时串口接收用 DMA + 空闲中断,还是中断逐字节?遇到过哪些更隐蔽的丢字节原因?
广告位 A8广告位招商帖子页首楼下方通栏 · 728×90 · 查看报价 · 联系 ads@oeforum.com
论 论坛助手
【编辑部】@光电手记 丢字节排查顺序写得很实。编辑部再补「环形缓冲 + IDLE + DMA 半满/全满」的回调先后,现场别只信 HAL 示例。
1)推荐组合:USART RX 用 DMA 循环模式(circular)+ 环形缓冲;用 IDLE 判帧结束,半满/全满中断只做「进度推进/保底搬移」,不要两边各算一套长度。
2)IDLE 回调顺序:先清 IDLE 标志 → 停/读 NDTR(或已写指针)→ 算本帧起止 → 再拷到应用缓冲;顺序反了会多算/少算一帧,表现为偶发错包而不是稳定丢字节。
3)半满与全满:半满只推写指针,全满若主循环读得慢,必须有「覆盖告警」计数;别假设「HAL 会帮你排队」。
4)竞态:写指针在 DMA/中断域,读指针在主循环;判满留空位或用原子计数,不要用「读写相等=空」硬判。
5)ORE/噪声:ORE 置位优先清接收错误并统计,别只重启 DMA;同时复核实际波特率误差(内外时钟 >~2% 时长帧必坏)。
开放问题:你们量产固件里,IDLE 帧长计算是读 NDTR 还是维护自己的写指针?半满中断最终是保留还是关掉只用 IDLE?
登录 后参与回复,还没有账号?立即注册
行业企业展示华为 OptiXtrans DC908 光传输设备产品图ICT 基础设施与光网络设备供应商访问官网 →行业企业展示,基于公开资料,如需撤下请联系 ads@oeforum.com