四、ENTDAA时序参数详解:tRECOVER、tLOCK、tUNLOCK、tSYNC
提到 ENTDAA(Enter Dynamic Address Assignment),很多工程师第一反应就是「发个 CCC 命令,然后等从机应答」。但实际上,这段过程里藏着好几个容易踩坑的时序参数。我做 I3C 调试头两年,因为这些参数没吃透,至少浪费了两周的时间去追一个本不该出现的加锁问题。
这一节,我把 ENTDAA 里最关键的四个时序参数拉出来逐个聊:tRECOVER、tLOCK、tUNLOCK、tSYNC。你搞懂它们,基本就能覆盖 90% 的 ENTDAA 异常场景。
4.1 整体时序脉络
先看一眼这几个参数在整个 ENTDAA 流程里出现在哪。
这个时序图是我自己整理的过程中画的,你可能会发现跟某些厂商的文档不完全一样——没关系,I3C 规范允许一定实现差异,但关键时序窗口必须满足最小/最大值。
4.2 tRECOVER:总线恢复时间
定义: tRECOVER 是主机完成 ENTDAA CCC 命令发送后,到正式启动下一步 SDR 转换之间的最小空闲时间。说白了,就是给总线一个「喘口气」的机会。
我遇到过最经典的问题:一台主机连续发送 ENTDAA 请求,中间没有留足够的 tRECOVER,结果从机根本没有识别到上一个协议终止信号,导致后续所有地址分配全部错位。最后用示波器一抓,SCL 高电平维持时间只有 2 个时钟周期,而规范要求至少 4 个时钟周期(数据手册一般写 5~7 个 tBIT)。
| 参数 | 最小值 | 典型值 | 最大值 | 说明 |
|---|---|---|---|---|
| tRECOVER | 4 tBIT | 6 tBIT | 无上限 | 从 STOP 到下一个 START 的间隔 |
| 实际影响 | 过小导致从机掉帧 | 安全余量 | 过大影响带宽 | 建议保留 20% 余量 |
我的经验: 写固件时别偷懒去算死 4 tBIT。I3C 总线速度可变,如果你在 12.5 MHz 下算 4 tBIT ≈ 320 ns,但切换到 6.25 MHz 就变成 640 ns。我个人的写法是「固定等待一个微秒级轮询 + 一个硬件计数超时」,这样速度切换时不会出幺蛾子。
4.3 tLOCK:锁定时间
tLOCK 发生在成功分配动态地址之后。主机通过设置 LOCK 标志位(通常在控制寄存器里),告诉从机:「这个地址归你了,别让别人抢」。从机收到后,需要一段保持时间把地址固化到内部寄存器。
这个时间多长?I3C v1.1 规范里写的是 至少 10 个 SCL 周期。但别急着照抄。我之前碰到过一个奇葩芯片,它的地址锁存逻辑非常慢,需要 15 个周期才稳定。如果你只等 10 个周期就去访问,从机要么回 NACK,要么返回错误数据。
⚠ 我曾经踩过的坑: 某批次 I3C 从机晶振频率偏低 2%,导致内部时钟偏慢,10 个 SCL 周期内锁存不完整。从那以后我强制在 DAL 寄存器写入后额外插入一个 delay_us(10),彻底告别偶发地址丢失。
| 参数 | 规范值 | 安全值(建议) | 异常症状 |
|---|---|---|---|
| tLOCK | ≥ 10 SCL | 15 SCL + 5 µs | DA 不响应,地址冲突 |
4.4 tUNLOCK:解锁时间
与 tLOCK 对应,当你要释放某个动态地址(比如从机离线、热插拔、重新寻址)时,主机需要写 UNLOCK 命令。从机收到后,必须在 tUNLOCK 时间内完成地址释放。
规范里 tUNLOCK 没有给出明确的固定值,只提了「足够长让从机完成内部擦除」。多数芯片实现为 1~5 个 SCL 周期。但我还是建议留 10 个周期以上——因为解锁操作往往涉及寄存器写保护,太快释放会被总线噪声误触发。
你想想看,如果一个从机刚解锁,紧接着另一个设备来了一个启动信号,从机还没清干净旧的地址,那总线仲裁会乱成什么样子?我见过一次总线死锁,就是 tUNLOCK 太短造成的。
4.5 tSYNC:同步时间
tSYNC 是 ENTDAA 过程中最容易被忽视的参数。它发生在 SDR 转换阶段——从机从 CCC 模式切换到地址广播模式,需要重新同步时钟沿。具体来说,主机发送一个特殊的 SDR 同步序列(一般包含一个低速的 01 交替),从机根据这个序列校准自身的采样相位。
典型值: 规范要求 tSYNC 至少 8 个 SCL 周期,实际设计里我做过的芯片用了 12 个周期。为什么多?因为从机的 PLL 锁定时间、时钟分频器切换都需要 margin。
如果 tSYNC 不足,从机可能采样到错误的位宽或者错误的起始位,直接导致后续地址读取全乱。我在项目中用逻辑分析仪抓到过一次,主机只发了 5 个同步时钟,从机成功接收概率只有 30%。
一点实用建议: 写代码时把 tSYNC 做成可配置参数,比如 #define ENTDAA_SYNC_CYCLES 16。这样调试时可以从 8 逐步往上加,直到 100% 稳定。我一般保留 16 个周期作为黄金值,兼容性最好。
4.6 参数速查表
把上面四个参数放到一起对比,方便你快速查阅:
| 参数 | 作用阶段 | 方向 | 最小周期数 | 常见问题 |
|---|---|---|---|---|
| tRECOVER | CCC 后 | 主机→总线 | 4 tBIT | 总线忙,从机丢状态 |
| tLOCK | DA 分配后 | 主机→从机 | 10 SCL | 地址未固化,后续访问 NACK |
| tUNLOCK | 释放地址 | 主机→从机 | (实现定义) | 总线死锁,地址残留 |
| tSYNC | SDR 转换 | 主机→从机 | 8 SCL | 采样偏移,地址乱码 |
4.7 几个容易混淆的点
最后聊两个我在交流中经常被问到的点。
- tRECOVER 和 tSYNC 有什么区别? 差别很大。tRECOVER 是 总线空闲间隔,与从机内部状态无关;tSYNC 是 从机主动同步时钟,需要从机内部锁相环参与。前者超时不会死机,后者超时基本就失败。
- tLOCK 和 tUNLOCK 能省略吗? 严格来说不能。即使你不主动锁地址,从机也会默认在 tLOCK 时间内自锁。省略 UNLOCK 会导致下次 ENTDAA 时地址冲突。我建议每次 ENTDAA 结束后,显式地做一次 UNLOCK 再进入 Idle 状态。
⚠ 注意: 不同厂商芯片对这几个参数的实现可能略有差异。尤其是一些低功耗 I3C 从机,会把 tRECOVER 缩短到 2 tBIT 左右来节省功耗——这种芯片必须配合主机做更长的等待才稳定。买芯片前一定看数据手册的 Timing Characteristics 表,不要只看规范里写的值。