☰
Zephyr BSP: 26-Devicetree 描述 Company SoC
2026/9/29 3:50:35 网站建设 项目流程

摘要:本文讲解 Zephyr Devicetree 的核心概念与实战用法。你将理解 Devicetree 如何描述 SoC 硬件、.dtsi与.dts的分工、compatible如何连接驱动、reg/interrupts/clocks等关键属性,以及 Devicetree 如何最终生成 C 宏进入驱动代码。文章从最小 Company SoC 示例出发,串联 Kconfig、DTS、CMake 与 Driver Model,帮助你建立完整的 BSP 世界观。

Devicetree:把 Company SoC 描述给 Zephyr

到了这里,你已经把:

BOARD → SOC → ARCH → CMake → SoC code → Clock/Reset → IRQ

这条链路基本打通了。

下一步非常关键:
Zephyr 怎么知道你的 Company SoC 里面到底有什么硬件?

答案就是:
Devicetree

可以把它理解成:
Kconfig 决定"编译哪些东西",Devicetree 决定"你的 SoC 上有哪些硬件,以及它们在哪里、怎么连接"。

1. 先建立整个 BSP 的世界观

假设你的公司做了一颗 SoC:

Company SoC │ ├── CPU │ └── Cortex-M4 │ ├── Clock Controller │ └── 0x4000_0000 │ ├── Reset Controller │ └── 0x4000_1000 │ ├── GPIO │ └── 0x4800_0000 │ ├── UART0 │ └── 0x4001_0000 │ ├── UART1 │ └── 0x4001_1000 │ ├── Timer0 │ └── 0x4002_0000 │ └── Interrupt Controller └── CPU private/system interrupt

你当然可以直接在 C 代码里写:

# define UART0_BASE 0x40010000# define UART0_IRQ 5

但这不是 Zephyr 推荐的方式。

Zephyr 希望你描述成:

Devicetree │ ▼ UART0node│ ├── reg ├── interrupts ├── clocks ├── status └── compatible │ ▼ UART Driver

也就是说:
硬件描述和驱动代码分离。

2. Company SoC 的 Devicetree 放在哪里?

典型结构:

zephyr/ └── dts/ ├── arm/ ├── riscv/ ├── x86/ └── bindings/ soc/ └── company/ └── my_soc/ ├── my_soc.dtsi └──... boards/ └── company/ └── my_board/ ├── my_board.dts ├── my_board.yaml └──...

一个很重要的原则:

SoC hardware ↓ SoC .dtsi Board hardware ↓ Board .dts

例如:

my_soc.dtsi

描述:

CPU UART0 UART1 GPIO CLOCK RESET TIMER PLIC/GIC/IRQ

而:

my_board.dts

描述:

LED Button Board connector External crystal Board-specific peripherals chosen aliases

3. .dtsi 和 .dts 到底是什么关系?

这是学习 Zephyr Devicetree 时必须彻底理解的一点。

假设:

Company SoC

有:

UART0 UART1 GPIO0 TIMER0

那么可以建立:

my_soc.dtsi

例如:

/{cpus{cpu0: cpu@0{compatible="company,my-cpu";device_type="cpu";};};soc{uart0: uart@40010000{compatible="company,my-uart";reg=<0x40010000 0x1000>;status="disabled";};uart1: uart@40011000{compatible="company,my-uart";reg=<0x40011000 0x1000>;status="disabled";};gpio0: gpio@48000000{compatible="company,my-gpio";reg=<0x48000000 0x1000>;status="disabled";};};};

注意:

status="disabled";

这并不是说硬件不存在。
而是:
这个 SoC 提供了这个硬件,但具体 Board 是否使用,由 Board DTS 决定。

4. Board DTS 再打开它

例如:

#include <company/my_soc.dtsi>/{model="Company MyBoard";compatible="company,my-board";};&uart0{status="okay";};&gpio0{status="okay";};

最终形成:

│ │ ┌────────▼────────┐ │ Company SoC │ │ │ │ UART0 disabled │ │ UART1 disabled │ │ GPIO0 disabled │ └────────┬────────┘ │ │ include ▼ my_board.dts │ ┌─────┴─────┐ │ │ UART0 GPIO0 okay okay

所以:
SoC DTSI 描述"芯片有什么",Board DTS 决定"这块板子用了什么"。

5. compatible 是 Devicetree 最重要的字段之一

例如:

uart0: uart@40010000{compatible="company,my-uart";reg=<0x40010000 0x1000>;};

这里:

compatible="company,my-uart";

实际上是在告诉 Zephyr:
“这个节点应该由哪一种 driver 来处理?”
对应 binding:

dts/bindings/ serial/ company,my-uart.yaml

例如:

compatible:"company,my-uart"include: - base.yaml properties: reg: required:trueinterrupts: required:true

于是关系变成:

DTS │ │ compatible ▼"company,my-uart"│ ▼ Binding │ ▼ Driver

6. Devicetree Binding 到底是什么?

可以把 Binding 理解成:

Devicetree 节点的"类型定义"。

比如 C:

structuart{uintptr_tbase;intirq;uint32_tclock;}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询