address-cell& size-cell

I2C子设备为啥size-cell为零

在设备树(Device Tree)中,I2C 子设备的 #size-cells 为零,主要是由 I2C 总线的寻址特性决定的。

简单来说,这是因为 I2C 设备在总线上占据的是一个**"点"(单一地址),而不是一个"范围"**(地址区间)。

以下是详细的原因分析:

1. reg 属性的含义

在设备树中,子节点的 reg 属性通常由父节点的两个属性来定义格式:

  • #address-cells :定义 reg 中"地址"字段占用的字数(cell,每个 cell 为 32 位)。
  • #size-cells :定义 reg 中"长度/大小"字段占用的字数。

对于常见的内存映射设备 (如片上外设),它们占据一段连续的内存空间(例如:起始地址 0x40001000,长度 0x100),因此需要 size 来描述范围。

2. I2C 的寻址方式:单一地址 vs 地址范围

  • 非内存映射 :I2C 是一种串行总线,每个从设备(Slave)由一个唯一的 7位或10位地址 标识。
  • 没有"长度"概念:当你访问一个 I2C 设备时,你只需要知道它的从机地址(Slave Address)。这个地址是一个离散的标识符,它不代表一段地址空间,也没有"从地址 A 到地址 B"这种长度的概念。
  • reg 属性的简化 :在 I2C 节点下,reg = <0x50>; 就足够表示这个设备(比如 EEPROM)的地址是 0x50。由于不需要描述"占用多少地址空间",所以 reg 里不需要包含 length 字段。

3. 设置为零的具体作用

在 I2C 控制器(父节点)中设置 #size-cells = <0>;,是为了告诉内核:"我的子设备(I2C 从机)在描述自己的资源(reg)时,只需要写地址,不需要写长度。"

示例对比:

  • 内存总线(需要 Size)

    dts 复制代码
    soc {
        #address-cells = <1>;
        #size-cells = <1>;
        serial@40001000 {
            reg = <0x40001000 0x100>; // 地址是0x40001000,长度是0x100
        };
    };
  • I2C 总线(不需要 Size)

    dts 复制代码
    i2c@40002000 {
        #address-cells = <1>;
        #size-cells = <0>; // 规定子设备不需要长度字段
        eeprom@50 {
            reg = <0x50>;     // 只需要地址,没有第二个数字
        };
    };

总结

I2C 子设备的 size-cell 为零是因为:

  1. I2C 协议基于从机 ID 寻址,每个设备只占用一个逻辑地址。
  2. 没有物理上的"空间长度" 需要被映射。
  3. 同样的逻辑也适用于 SPI 总线 (地址是片选线编号)和 CPU 节点 (地址是内核 ID),它们的 #size-cells 通常也是 0。

为啥内存总线需要 Size

内存总线(Memory-mapped I/O,简称 MMIO)之所以需要 size(即 #size-cells 不为 0),是因为内存地址空间和 I2C 这种串行总线在硬件寻址逻辑操作系统管理方式上有本质的区别。

以下是为什么要定义"长度(Size)"的四个核心原因:

1. 内部寄存器范围(Offset 概念)

一个内存映射设备(如 UART 控制器、网卡、GPU)通常不只有一个寄存器,而是有一堆寄存器。

  • I2C 设备 :你向地址 0x50 发送指令,具体的内部寄存器(如 EEPROM 的存储地址)是在数据包里定义的,不是在总线层面定义的。
  • 内存映射设备 :CPU 直接通过地址访问。比如一个 UART 控制器:
    • 0x40001000 是数据寄存器
    • 0x40001004 是控制寄存器
    • 0x40001008 是状态寄存器
  • 结论 :这个设备占据了从 0x40001000 开始的一整块"领地"。操作系统必须知道这块地有多大,才能给驱动程序提供正确的访问范围。

2. 内存管理单元(MMU)与页表映射

在现代操作系统(如 Linux)中,驱动程序不能直接访问物理地址,必须通过 虚拟地址 访问。

  • 内核在加载驱动时,会调用类似 ioremap(base, size) 的函数。
  • 映射单位 :MMU 是按"页"(通常是 4KB)来映射的。如果 OS 不知道设备的 size,它就不知道该为这个设备在虚拟地址空间里分配多大的区域,也不知道该映射多少个页表项。

3. 防止地址冲突(Resource Allocation)

系统内存地址空间是极其宝贵的"房地产"。

  • 内核有一个资源管理器(在 Linux 里可以通过 cat /proc/iomem 查看)。
  • 为了防止两个设备被分配到重叠的地址区域,内核需要记录每个设备从哪开始 以及到哪结束
  • 如果没有 size,内核只知道 0x40001000 被占用了,但不知道 0x40001004 是不是也被这个设备占用了,这会导致资源管理的混乱。

4. 总线解码器(Hardware Decoder)的工作原理

从硬件设计的角度看:

  • I2C:总线上的所有设备都看着数据流,当地址匹配时,某个设备跳出来响应。
  • 内存总线:CPU 发出一个地址信号。总线控制器(Bus Fabric/Interconnect)需要根据这个地址来决定把信号传给哪个外设。
  • 译码逻辑 :硬件内部的地址译码器就像一个"围墙"。它判断:if (Address >= Base && Address < Base + Size),则激活该设备。这个 Size 是硬件逻辑电路中真实存在的范围。

类比理解

  • I2C 就像"快递员投递"
    你只需要写一个门牌号 (地址 0x50)。快递员顺着街道走,看到门牌号就敲门。他不需要知道你家房子有多大。
  • 内存总线就像"土地规划"
    政府(CPU/OS)要把一块地划拨给工厂(外设)。政府不仅要给工厂一个起始坐标 (Base Address),还必须标明这块地占地几亩(Size)。否则,隔壁的工厂可能会把楼盖到你的地盘上,或者你在自家院里走路(访问寄存器)却走到了别人家里。

总结

特性 I2C 子设备 内存映射设备 (MMIO)
访问方式 串行协议包发送地址 CPU 指令直接读写内存地址
占用空间 逻辑上的一个点 物理上的一个地址区间
映射需求 不需要映射,直接由驱动发包 需要 MMU 映射成虚拟地址
#size-cells 0 通常为 1 或 2
相关推荐
车载诊断技术1 小时前
在工作中如何保持奋斗的动力?
网络·架构·汽车·电子电气架构·ecu 诊断 diag
其实防守也摸鱼1 小时前
软件安全与漏洞--实验 软件安全需求分析
网络·安全·网络安全·需求分析·法律·实验·软件安全与漏洞
小则又沐风a1 小时前
基础的开发工具(Linux)
linux·运维·服务器
深邃-1 小时前
【Web安全】-Kali,Linux配置(2):Java环境配置,Python环境配置,Conda使用,PIP配置使用,SSH远程登录
java·linux·python·安全·web安全·网络安全·php
Fanfanaas1 小时前
Linux 系统编程 进程篇 (六)
linux·服务器·c语言·开发语言
爱笑的Sunday1 小时前
Linux Java前后端项目 企业级0-1完整部署手册
java·linux·运维·服务器
xyx-3v1 小时前
FreeRTOS队列通信
java·服务器·网络
weixin_451431561 小时前
HLS加密流解码异常导致视频花屏?通用技术解析及合规指引
网络·音视频
wanhengidc1 小时前
云手机是什么黑科技?
运维·网络·科技·安全·web安全·智能手机