资讯详情

STM32 SMBus实战:I2C差异、超时复位与PEC寄存器排错

📅 2026/11/4 15:15:19 | 华诺云谱 👁 阅读
STM32 SMBus实战:I2C差异、超时复位与PEC寄存器排错
前阵子帮人返工一块小板子主控是 STM32总线上挂了颗电池管理芯片和一个温度传感器。代码是从另一个项目直接拷过来的标准 I2C 驱动写寄存器一切正常读数据却时不时返回 0xFFFF跑上十几分钟还会整个总线卡死、BUSY 位置起来再也不掉。换芯片、换板子、改地址、换上拉折腾了整整两天最后拿逻辑分析仪一测才发现两件事一是模块自带的 10 kΩ 上拉把上升沿拖到了 900 ns 左右二是从机在被拉低超过 25 ms 之后自己把内部状态机复位了——这两条都是SMBus的硬性规定而标准 I2C 代码里根本没有对应的处理。SMBus 这个东西本质上是 I2C 的一个加了规矩的子集电气参数被钉死、时序窗口被限制、还强制要求 CRC 校验和超时复位。它出现的场景很集中——笔记本电池、服务器电源管理、温度/电压监控、内存条上的 SPD、各种板级管理芯片。这些场合的共同点是必须能自愈一条挂在机箱里的总线不能因为某一个器件抽风就把整个系统拖死所以 SMBus 才把超时和 PEC 写进了规范。适合读这篇的人大概分三类手上正好有一颗 SMBus 器件要接 STM32 的I2C 代码能跑但偶发出错想搞清楚原因的以及想弄明白 STM32 的 I2C 外设里那几个 SMBUS、SMBTYPE、ENPEC、ENARP 位到底是干什么的。下面我按差异分析—寄存器推导—协议层实现—排错—实测验收的顺序走一遍代码以 STM32F1 的寄存器操作为主线其他系列F0/F3/F4/L4/G0 等思路完全一致只是超时寄存器和部分位名有差别我会在对应位置标出来。1. SMBus 与 I2C 的四处硬差异不搞清这些配置必然翻车很多人以为 SMBus 就是I2C 加个名字把 I2C 跑通就相当于支持 SMBus 了。实际调试下来出问题的几乎全部集中在下面四组差异上而且这四组差异是互相耦合的电气参数不对会拖慢边沿边沿慢了从机就更容易被超时复位超时复位之后地址不应答你就开始怀疑地址配错了。1.1 一张表看清哪些参数被钉死了先把结论摆出来下面这张表是我自己调试时贴在工位上的那版只保留了对写代码和画板子有影响的行项目I2C 标准模式SMBus 2.0实际影响时钟频率范围无下限可直流停住10 kHz ~ 100 kHz不能为了省事把 SCL 调到 1 kHz 去看清楚波形逻辑门限0.3·VDD / 0.7·VDD比例式VIL ≤ 0.8 VVIH ≥ 2.1 V固定1.8 V 器件直接接 3.3 V SMBus 有风险上升/下降沿≤ 1000 ns≤ 300 ns上拉电阻必须重算10 kΩ 通常不合格总线超时无规定SCL 低/高电平超过 25~35 ms 视为异常STM32 要开超时检测软件要有复位链路数据校验无标准算法PECCRC-8多项式 0x07硬件 ENPEC 或软件算都行但必须一致地址应答从机可不应答除忙以外必须应答收到 AF 基本可以判定是地址/电气问题中断线无SMBALERT# ARA0x0C可选但接上之后能省掉大量轮询表格里最容易被忽略的是固定门限和300 ns 上升沿这两条因为它们不在代码里在硬件上。我见过太多次把 1.8 V 的传感器直接挂到 3.3 V 总线上代码层面完全看不出问题示波器上看波形也挺漂亮但就是偶发不应答——原因就是 1.8 V 器件的高电平输出达不到 SMBus 要求的 2.1 V VIH。这种情况必须加电平转换不要指望上拉拽上去SMBus 是开漏总线高电平完全由上拉电阻提供器件自己不驱动高电平。1.2 10 kHz 下限为什么不能用低速慢慢读SMBus 规定 SCL 最低 10 kHz这个规定乍看莫名其妙其实和超时机制是配套的从机要靠SCL 长时间不动来判断主机是不是挂了如果允许主机用 1 kHz 慢慢磨那 25 ms 的超时窗口就完全失去意义了。所以 10 kHz 下限的真正含义是——总线上任何一个字节都必须在有限时间内传完。实测中这条限制有两种踩法。第一种是为了兼容长线缆把 CCR 调大让 SCL 降到 5 kHz结果某些严格的电池管理芯片直接不应答第二种是在软件里手动翻转 GPIO 模拟时序bit-banging翻转间隔随手写了 200 µs等效频率 2.5 kHz同样不合规。真要做软件模拟也得保证半周期不超过 50 µs也就是整体不低于 10 kHz。1.3 25 ms 超时STM32 各系列的实现差别很大超时是 SMBus 和 I2C 差别里最隐蔽的一条。它的表现不是通信报错而是从机悄悄把你的连接断掉——主机还在等 ACK从机已经复位回空闲状态于是你收到一个 NACK 或者干脆读到全 1。STM32 各系列在这块的硬件支持并不一样F1 系列I2C 外设没有可编程的超时寄存器SMBus 模式下由硬件做固定窗口的超时检测超时后在 SR1 里置 TIMEOUT 标志配合 ITERREN 可以进中断。也就是说你只能知道超时了不能改窗口大小。F0/F3/F4/L4/G0 等有独立的I2C_TIMEOUTR寄存器可以分别使能总线空闲超时和SCL 低电平超时并自行设定计数值。TIMEOUTR的计数单位是 2048 个外设时钟周期公式是t_timeout (TIMEOUT 1) × 2048 × T_pclk以 F4 的 I2C1 为例APB1 42 MHzT_pclk 23.8 ns那么 2048 × 23.8 ns ≈ 48.8 µs想得到 25 ms 的超时窗口TIMEOUT 25 ms / 48.8 µs - 1 ≈ 511填 0x1FF 就差不多了。填完之后记得把TIMEOUTEN总线超时使能置 1需要检测 SCL 被拉死的情况还要打开TEXTEN扩展超时使能。注意超时检测只能报告不能修复。真正的自愈要靠软件——检测到 TIMEOUT 之后必须走一次总线恢复流程本文第 3.4 节否则下一次通信还是照样失败。1.4 PEC不是可选装饰是协议的一部分PECPacket Error Code就是一个 CRC-8x^8 x^2 x 1即多项式 0x07初值 0x00MSB 优先不做反转也不做最终异或。关键在于计算范围从起始条件之后的第一个地址字节开始一直到最后一个数据字节全部参与计算包括地址字节本身也包括读操作里那个重复起始 地址R。这一点是新手最容易算错的地方。举个具体例子读一个字节Read Byte时参与 PEC 计算的字节序列是[addr1 | 0] → [命令字] → [addr1 | 1] → [数据字节]而不是只有数据字节。我第一次实现的时候只把数据丢进 CRC对了几十次都对不上后来把地址字节补进去立刻就对了。2. 从时钟树到寄存器STM32 侧配置的完整推导搞清楚差异之后配置就变成了一道算术题。这一节把 CCR、TRISE、CR1 里那几个位逐个拆开给出可以直接抄的数字并且说明为什么这么算。2.1 CCR 与 TRISE 的算法和一组现成数字STM32 标准模式下DUTY位为 0 时高电平和低电平时间是相等的都等于CCR × T_pclk所以CCR f_pclk / (2 × f_SCL)TRISE寄存器填的是允许的最大上升沿时间单位是外设时钟周期TRISE t_r_max / T_pclk 1I2C 标准模式允许 1000 ns 的上升沿所以 ST 的 HAL 库统一按FREQ 1来填但 SMBus 要求 300 ns必须自己覆盖掉。常用的几组值我列在下面可以直接查PCLK1目标 SCLCCRTRISESMBus300 ns8 MHz100 kHz40336 MHz100 kHz1801142 MHz100 kHz2101348 MHz100 kHz2401536 MHz50 kHz36011顺带说一句上拉电阻怎么算因为这事和TRISE是一体的。SMBus 的 300 ns 上升沿上限配合总线电容Cb可以反推出电阻上限Rp ≤ t_r / (0.8473 × Cb)假设一条短板上总线电容 100 pFRp ≤ 300 ns / (0.8473 × 100 pF) ≈ 3.5 kΩ下限则由 VOL 决定3.3 V 供电、VOL 最大 0.4 V、灌电流 3 mARp ≥ (3.3 - 0.4) / 3 mA ≈ 970 Ω所以 3.3 V 系统、100 pF 负载下1.8 kΩ ~ 2.2 kΩ是比较舒服的取值。而市面上大量传感器模块自带的 10 kΩ 上拉按上面的公式算下来上升沿约 850 ns已经超出 SMBus 上限近三倍——这就是我开头那块板子出问题的直接原因。把模块上的上拉拆掉或者并联一个 2.2 kΩ故障率立刻降下来。2.2 CR1 里那几个位到底该摆成什么状态以 F1 的I2C_CR1为例和 SMBus 相关的有五位它们的含义和推荐值如下位名称作用主机读从机时的推荐值bit1SMBUS切换到 SMBus 模式启用电平门限与超时检测1bit3SMBTYPE0 Device1 Host0bit4ENARP使能 SMBALERT 引脚与 ARP需要中断线时置 1bit5ENPEC使能硬件 PEC 计算用软件 PEC 时置 0bit7NOSTRETCH从机模式禁止时钟拉伸主机模式无影响保持 0SMBTYPE这一位特别容易搞反。很多人看到主机两个字就想置 1其实它控制的是作为从机被寻址时的地址匹配行为——置 1 之后接口会对 SMBus Host 地址0x08作出应答配合 SR2 里的 SMBHOST 标志用于 Host Notify 协议。当你只是用 STM32 去读写一颗电池芯片时要的是 Device 模式这一位保持 0。ENPEC我也建议先关掉用软件算。原因不是硬件算得不对而是硬件 PEC 的计算范围取决于接口实际发出和收到的每一个字节一旦中间插入 DMA、或者传输被中断打断重启PECR里的值就对不上了排查起来比软件算法麻烦得多。软件 PEC 每字节一次 CRC 更新100 kHz 下最多几十微
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑