最近在研究 Ubuntu 下的 ES8156 的声卡驱动,顺便学习了一下设备树(Device Tree) 和 I2S 声卡的工作原理。首先要搞懂这两个概念,简单来说,把写驱动比作盖房子,盖房子之前,先要看懂设计图纸(设备树)和水电原理(I2S协议)。

下面用最通俗的方式为你拆解这两个核心概念:
🌳 什么是设备树 (Device Tree)?
在以前的 Linux 内核中,硬件信息(比如有几个 CPU、内存多大、GPIO 接了什么设备)是直接写死在 C 语言代码里的。这导致内核代码非常臃肿,同一个内核代码无法通用于不同配置的开发板。
设备树就是一份"硬件说明书"。
它的作用是告诉 Linux 内核:"嘿,我现在这台电脑(开发板)上,长什么样,有哪些外设。"
1. 核心比喻:树状结构
想象一棵树:
- 树根 (Root):代表整个系统(SoC,也就是树莓派的芯片)。
- 树枝 (Buses):代表连接方式,比如 I2C 总线、SPI 总线、I2S 总线。
- 树叶 (Devices):代表具体的硬件,比如 ES8156 芯片。
2. 关键术语
- DTS (Device Tree Source) :后缀为
.dts的文本文件,人类可读,我们写的代码就是这个。 - DTB (Device Tree Blob) :后缀为
.dtb的二进制文件,由 DTS 编译而来,内核能读懂。 - Node (节点):描述一个硬件对象。例如一个 I2C 控制器是一个节点,挂在这个控制器上的 ES8156 也是一个节点。
- Property (属性) :节点的特征。例如
compatible(兼容性)、reg(寄存器地址/I2C地址)、clocks(时钟)。
3. 驱动匹配的"暗号"
这是最关键的一点:驱动程序是如何知道自己要控制哪个硬件的?
答案是:compatible 属性。
- 在设备树 里,写:
compatible = "everest,es8156"; - 在驱动源码 里,开发者也写了一个列表:
{"everest,es8156", ...} - 内核启动时,会拿着设备树里的字符串去驱动列表里找。只要这两个字符串对上了,内核就把这个硬件分配给这个驱动来管理。
🔊 I2S 声卡的工作原理
I2S 全称是 Inter-IC Sound,是飞利浦公司制定的一种数字音频传输标准。它专门用来在芯片之间传输声音数据(比如 CPU 和 音频解码芯片之间)。
为什么不用 USB 或网络传输音频?因为 I2S 是纯数字、点对点、低延迟的,音质最纯净。
1. 三根核心线 (信号)
I2S 接口通常由 3-4 根线组成,它们就像乐队的指挥和乐手:
表格
| 信号线 | 全称 | 作用 | 比喻 |
|---|---|---|---|
| BCLK | Bit Clock (位时钟) | 每传输 1 个 bit,它就跳变一次。频率非常高。 | 节拍器:每响一声,传一个音符。 |
| LRCLK | Left/Right Clock (声道时钟) | 高电平代表右声道,低电平代表左声道。 | 指挥棒:指左边乐队奏,指右边乐队停。 |
| DIN/DOUT | Data In/Out (数据线) | 真正传输声音波形数据的线路。 | 乐谱:上面写着具体要唱什么音。 |
| MCLK | Master Clock (主时钟) | 通常是采样率的 256 或 384 倍,用于同步芯片内部振荡。 | 校准表:确保大家的表时间一致,不走音。 |
2. 数据是怎么传的?
想象你要传输一个立体声(左/右)的音乐:
- LRCLK 变成低电平(代表左声道开始)。
- BCLK 开始疯狂跳动(比如 2.3MHz)。
- DIN 上按照 BCLK 的节奏,一位一位地送出左声道的数字(比如 16 位或 24 位数据)。
- LRCLK 变成高电平(代表右声道开始)。
- BCLK 继续跳动,DIN 上送出右声道的数据。
- 如此循环,形成了连续的声音流。
3. 常见的"坑" (极性)
I2S 虽然标准,但不同芯片的厂商习惯不同。
- 左对齐 (Left Justified) vs I2S 标准 (Philips Standard):数据是在 LRCLK 变化后的第一个时钟有效,还是第二个时钟有效?
- LRCLK 极性:高电平到底是左声道还是右声道?
- 解决方案 :这通常在设备树或驱动代码中通过
dai-format = "i2s";或dai-format = "left_j";来配置。如果配置错了,你会听到噪音,或者只有单声道。
🛠️ 开发调试 ES8156 的具体步骤
结合前面的理论,现在要做的事情可以拆解为以下 5 个步骤:
第一步:硬件连接 (物理层)
- 把树莓派的 GPIO 和 ES8156 的引脚焊对。
- I2C 线:连接 SDA、SCL(用于发送"播放"、"静音"、"调音量"等指令)。
- I2S 线:连接 BCLK、LRCLK、DIN/DOUT(用于传输真正的音乐数据流)。
- 供电:检查 VCC 和 GND。
第二步:确认 I2C 通信 (控制层)
- 在 Ubuntu 命令行输入
i2cdetect -y -1。 - 目的:确认电脑能看到 ES8156 这个"人"。如果扫到了地址(比如 0x1b),说明控制通道通了。
第三步:编写设备树 (描述层)
- 创建一个
.dts文件。 - 内容 :
- 告诉内核:"我在 I2C 总线上挂了一个设备,地址是 0x1b,它的名字叫
everest,es8156"。 - 告诉内核:"请把简单的音频卡(Simple Card)配置好,CPU 端用 I2S,Codec 端用刚才那个 ES8156"。
- 告诉内核:"我在 I2C 总线上挂了一个设备,地址是 0x1b,它的名字叫
第四步:加载与匹配 (软件层)
- 编译设备树,重启或动态加载。
- 输入
dmesg | grep es8156。 - 理想输出 :
es8156_probe: entered。这意味着驱动程序的probe函数被调用了,说明设备树和驱动匹配成功!
第五步:测试音频 (应用层)
- 输入
aplay -l。 - 如果能看到声卡列表里多了一个设备,恭喜你,硬件和驱动都通了!接下来就是调音量和测试播放了。
📌 总结
- 设备树 = 给内核看的 简历,告诉内核硬件长什么样。
- I2S = 芯片间传输声音的 专用高速公路,有严格的时钟同步要求。
- 调试核心 :先通 I2C(控制),再通 I2S(数据),靠
compatible字符串牵线搭桥。
老徐,2026 0123