4、I3C 地址类型:静态地址与动态地址,7 位地址空间

说到 I3C 的地址,我记得早期调试时总被这个“7 位”给绕进去。你想想看,I2C 也是 7 位地址,可 I3C 的玩法完全不一样。它把地址分成了两套:静态地址和动态地址。说白了,一个设备有两个“身份证号”,一个出厂自带,一个上车之后重新分配。

4.1 7 位地址空间到底有多大?

I3C 沿用 7 位地址,范围是 0x00 – 0x7F,共 128 个。但别高兴太早,这 128 个里有一半以上被预留给特殊用途。我在项目里踩过一个坑:以为 128 个地址足够用,结果挂上 30 多个传感器后,发现广播地址、I2C 保留地址一扣,能用的动态地址只剩 60 多个。

用途地址范围备注
广播地址(所有设备)0x7E用于全局寻址,不分配给具体设备
I2C 保留地址0x00 – 0x07
0x78 – 0x7F
共 16 个,I3C 主控不能使用
动态地址池0x08 – 0x77共 112 个,但实际可用约 96 个(扣除部分保留)
静态地址(I2C 兼容)0x08 – 0x77I3C 设备也可用这个范围,但更推荐动态分配

你会问:地址空间看着挺大啊,为什么实际挂不了太多设备?嗯,这里有个关键点——I3C 主控支持的设备数量主要受限于时间槽和总线电容,地址本身反而不是最紧的瓶颈。我曾经在一个项目中挂了 50 个 I3C 传感器,地址池还富余,但总线负载已经快到极限了。

我的经验:规划地址池时,先把广播地址(0x7E)和 I2C 保留区记死。别图省事硬编码 0x00 或 0x7F,那两条地址在 I3C 总线上会引发仲裁异常。

4.2 静态地址:出厂自带的“古董身份证”

静态地址,说白了就是设备出厂时烧死的 7 位 I2C 地址。I3C 为了向下兼容 I2C 设备,保留了这套机制。静态地址一旦设定,一辈子不能改。如果总线上两个设备静态地址冲突,那不好意思,硬件必须改板。

但 I3C 设备一般不会只用静态地址。我记得刚开始用 I3C 时,总觉得“既然有静态地址了,那动态分配也没啥用啊”。结果翻手册发现——在 I3C 总线中,所有 I3C 设备完成动态地址分配(DAA)之前,主控是不允许用动态地址跟它通信的。你设备再牛,刚上电也得先用静态地址被主控点名。

  • 静态地址长度:7 位,取值范围 0x08 – 0x77
  • 读写方向:在 I3C 的 SDR 模式下,静态地址的最低位(R/W#)决定了操作类型
  • 冲突风险:完全依赖厂商分配,无法由主机动态解冲突
  • 典型用途:DAA 阶段的“敲门砖”,以及挂接传统 I2C 从机
避坑指南:我曾经遇到过一个 I3C 传感器,它的静态地址是 0x12,结果同一板子上还有一颗 I2C EEPROM 也用的 0x12。上电后主控做 DAA 时把两颗设备全当 I3C 来枚举,直接导致总线锁死。解决方案只能是改 I2C 器件的地址引脚,或者换型号。

4.3 动态地址:I3C 的灵魂机制

动态地址,你可以理解成“热插拔临时工号”。主控在上电或接到热加入请求后,会依次给每个 I3C 设备分配一个唯一的 7 位地址。这个过程叫动态地址分配(Dynamic Address Assignment,DAA)。

我习惯用一张图来描述这个关系——

I3C 地址类型与动态地址分配(DAA)概览 静态地址 出厂固化,不可修改 用于 DAA 初始阶段通信 兼容 I2C 从机 范围:0x08-0x77 动态地址 由主控分配,每次上电可能不同 唯一性强,冲突可规避 DAA 完成后日常通信使用 范围:0x08-0x77(动态池) DAA 转换 动态地址分配(DAA)核心步骤 ① 主控发送 ENTDAA CCC ② 从设备使用静态地址响应 ③ 主控分配动态地址给该设备 ④ 重复②③直到所有设备被分配 注:支持 I2C 的静态地址设备不参与 DAA,始终使用静态地址工作

你看看这张图,左侧是静态地址——它是设备出厂时自带的 I2C 兼容地址。右侧是动态地址——主控通过 DAA 流程分配给 I3C 设备的临时但唯一的地址。

4.4 DAA 流程中的地址分配细节

实际 DAA 是怎么跑起来的?我拆解一下:

  1. 主控发送 ENTDAA(Enter Dynamic Address Assignment)CCC 命令,广播给所有 I3C 从设备。
  2. 从设备收到后,如果还没被分配动态地址,就用自己的 静态地址 去响应主控的 GETDAA 请求。
  3. 主控收到响应后,从自己的动态地址池里选一个未被占用的 7 位地址,通过 SETDAA(Set Dynamic Address)命令把该地址写入从设备。
  4. 从设备确认后,主控更新本地设备表,然后继续查询下一个未分配的设备。
  5. 如果某个设备在响应时发生总线冲突(多个设备同时用相同静态地址响应),主控会通过 OEN(Optional Error Notification) 或重试机制来仲裁。
阶段主控动作从设备动作地址使用情况
上电 / 复位发送 ENTDAA等待被呼叫仍使用静态地址
呼叫发出 GETDAA(含静态地址)匹配到自己的静态地址后回复静态地址用于识别
分配发送 SETDAA(新动态地址)存储新地址动态地址生效
后续通信使用动态地址寻址响应动态地址静态地址不再用于数据通信
重点:I3C 协议规定——一个 I3C 设备在 DAA 完成后,主控必须使用动态地址进行后续读写。只有部分特殊 CCC 命令(如 GETDAA)才允许使用静态地址。这个规则我刚开始总记混,后来调试时发现主控一直用静态地址发 I3C 读命令,从机根本不理我,查了两天才反应过来。

4.5 静态 vs 动态:什么时候用哪个?

其实决策很简单:

  • 总线上混接了传统 I2C 器件 → 它们只用静态地址,不参与 DAA。
  • 纯 I3C 器件 → 全部走动态地址。
  • 特殊情况:如果 I3C 设备需要支持热加入(Hot-Join),也必须先通过静态地址完成 DAA,才能被主控识别。

我个人习惯:不管你的 I3C 设备有多少,都让主控跑一遍 DAA。就算你打算把设备地址固定下来,DAA 也能帮你验证总线上是否有地址冲突。我曾经偷懒跳过 DAA,直接用预设动态地址,结果两个不同厂家模块的默认动态地址竟然是同一个数……嗯,那次排查花了整整一个下午。

小技巧:调试阶段可以在主控中断处理中打印 DAA 分配的地址表。你只要看一遍地址,就知道哪些地址被用了,哪些空闲。比对着数据手册猜地址快多了。

4.6 关于 7 位地址的常见误解

  • 误解一:“动态地址也是 7 位,所以 I3C 总线上最多只能挂 127 个设备。”
    实际上:广播地址 (0x7E) 和 I2C 保留区扣掉后,可用动态地址约 96 个。而且总线电气能力通常撑不到那个数量。
  • 误解二:“静态地址和动态地址不能相同。”
    实际上:可以相同,但强烈不推荐。一旦冲突,DAA 之后主控无法区分该地址是静态的还是动态的。
  • 误解三:“设备断电后动态地址会丢失,下次上电需要重新 DAA。”
    实际上:没错,这是标准行为。部分厂商的 I3C 设备可以在内部保存上次分配的动态地址,但主控一般不会信任它,还是会重新分配。
我的踩坑记录:有一次我让主控在 DAA 时给设备分配了一个静态地址相同的动态地址(比如设备静态是 0x30,动态也给了 0x30)。结果主控自检时发现地址表里有两个 0x30,一个标记为 I3C 动态,一个标记为 I2C 静态。后续读写时,主控的仲裁逻辑直接挂起了。从那以后我的代码里强制动态地址避开设备的静态地址,省心很多。

好了,关于 I3C 的地址类型和 7 位地址空间,核心就是静态地址负责“入门”,动态地址负责“日常”。理解了这个分工,后面看 DAA 详细流程、热加入以及地址冲突处理时,你会觉得顺理成章。