ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Zephyr BSP: 05-Zephyr SoC Devicetree

Zephyr BSP: 05-Zephyr SoC Devicetree 摘要:本文是 Zephyr SoC Porting 系列的第 5 篇,聚焦于如何通过 Devicetree 描述一个 SoC 的硬件资源。文章从 Devicetree 文件层次(.dts / .dtsi / .overlay / .yaml)讲起,厘清 SoC 公共硬件与 Board 特定硬件的职责划分;随后深入讲解 compatible、Binding、reg、interrupts、Clock、GPIO 等核心概念,并强调status = "disabled"的默认策略。最后通过west build生成的zephyr.dts与devicetree_generated.h,揭示 Devicetree 在编译期被转换为 C 宏的机制,帮助读者建立「SoC 描述硬件能力、Board 描述硬件连接」的核心认知,为后续 SoC Devicetree 实战打下基础。Zephyr SoC Devicetree如果你的最终目标是把公司的 SoC 正式加入 Zephyr 生态,那么这一篇非常关键。前面你已经在学习:01 Zephyr Hardware Model ↓ 02 Architecture → SoC → Board ↓ 03 Zephyr BSP ↓ 04 Zephyr SoC Porting ↓ 05 SoC Devicetree ← 现在这一篇先不要急着写完整 Board,而是把一个问题彻底搞明白:Zephyr 是如何通过 Devicetree 描述一个 SoC 的 CPU、RAM、Flash、Clock、UART、GPIO、Timer、Interrupt Controller 等硬件资源的?Zephyr 官方也明确把 SoC 的硬件描述放在 dts//.dtsi 中,并要求使用该 SoC 的 Board 去 include 这个 .dtsi。1. SoC Devicetree 到底是什么?先不要把 .dtsi 理解成"配置文件"。更准确地说:SoC Devicetree 是 Zephyr 对 SoC 硬件拓扑和硬件资源的描述。例如你的公司 SoC:这些硬件资源最终都需要在 Devicetree 中有所描述。所以你可以把:soc.dtsi理解成:SoC 的硬件地图。2. Zephyr 的 Devicetree 文件层次一个比较典型的结构是:官方文档把 Devicetree 输入分成四类:.dts .dtsi .overlay .yaml为了更直观地对比这四类文件,下面用一张表格总结它们的职责、内容与协作关系:文件类型典型用途包含内容示例路径协作关系.dtsBoard 级硬件描述Board 特有硬件(LED、Button、引脚复用、外设使能)boards/arm/nucleo_f303re/nucleo_f303re.dtsinclude 对应的 SoC.dtsi,并引用其中节点进行使能.dtsiSoC / 公共硬件描述CPU、RAM、Flash、UART、GPIO、Clock 等 SoC 公共资源dts/arm/st/f3/stm32f303.dtsi被 Board.dtsinclude,提供 SoC 硬件能力.overlay应用 / Board 的增量修改针对特定应用或 Board 的节点覆盖与追加app.overlay在编译期叠加到.dts之上,常用于修改status、引脚等.yamlDevicetree binding节点允许的属性、类型与约束规则dts/bindings/serial/st,stm32-uart.yaml通过compatible与 DTS 节点匹配,指导驱动生成宏简单来说:.dtsi描述 SoC 有什么,.dts描述 Board 怎么用,.overlay做增量修改,.yaml定义属性规则。四者最终在编译期合并为zephyr.dts,再生成驱动可用的 C 宏。其中:.dts:通常是 Board 的硬件描述.dtsi:SoC 或公共硬件描述.overlay:针对应用/Board 的修改.yaml:Devicetree binding3. .dts 和 .dtsi 的关系这是做 SoC Porting 必须理解的地方。假设你有:Company SoC ↓ MY1234 ↓ 两个 Board ├── my1234_devkit └── my1234_eval那么两个 Board 很可能共享:my1234.dtsi例如:dts/ └── arm/ └── company/ └── my1234.dtsi然后:boards/ └── arm/ ├── my1234_devkit/ │ └── my1234_devkit.dts │ └── my1234_eval/ └── my1234_eval.dts关系:这就是为什么:SoC 公共硬件放 .dtsi,Board 特有硬件放 .dts。4. 一个 SoC .dtsi 应该描述什么?对于公司 SoC,通常可以从这些东西开始:CPU RAM Flash Interrupt Controller Clock UART GPIO Timer SPI I2C DMA PWM ADC...例如:#includelt;arm/armv7-m.dtsigt;/{soc{compatible="company,my1234";uart0:uart@40000000{compatible="company,my-uart";reg=lt;0x400000000x1000gt;;interrupts=lt;50gt;;status="disabled";};gpio0:gpio@40010000{compatible="company,my-gpio";reg=lt;0x400100000x1000gt;;interrupts=lt;60gt;;status="disabled";};};};这里暂时不用纠结具体 syntax。先看结构:soc │ ├── uart0 │ ├── gpio0 │ ├── spi0 │ ├── i2c0 │ └── timer0这就是 SoC 的硬件资源树。5. compatible 是最重要的东西之一例如:uart0: uart@40000000{compatible="company,my-uart";};这里:compatible="company,my-uart";非常重要。它实际上是在告诉 Zephyr:这个节点是什么类型的硬件?Zephyr 会根据 compatible 去寻找对应的 binding。官方文档说明,Devicetree node 会通过 compatible 与 YAML binding 匹配。例如:DTS compatible="company,my-uart";│ ↓ dts/bindings/serial/company,my-uart.yaml │ ↓ UART Driver所以:DTS │ │ compatible ↓ Binding │ ↓ Driver这是你以后做公司 SoC BSP 时必须牢牢记住的一条链。6. Binding 是什么?例如:dts/bindings/serial/company,my-uart.yaml可能:description: Company UART compatible:"company,my-uart"include: - uart-controller.yamlBinding 并不是驱动。它更像:告诉 Zephyr:这种硬件节点允许有哪些属性、这些属性是什么类型。例如:uart0: uart@40000000{compatible="company,my-uart";reg=lt;0x40000000 0x1000gt;;interrupts=lt;50gt;;current-speed=lt;115200gt;;status="okay";};Binding 则告诉 Zephyr:reg ↓ 这是地址/长度 interrupts ↓ 这是中断信息 current-speed ↓ 这是 UART 波特率 status ↓ 这是设备状态官方文档也特别强调,binding 不仅用于验证 node 内容,还用于生成驱动和应用可使用的 Devicetree 宏。7. SoC .dtsi 最核心的几个节点对于你以后真正做公司 SoC BSP,我建议先重点理解下面这些。7.1 CPU例如:cpus{# address-cells = lt;1gt;;# size-cells = lt;0gt;;cpu@0{device_type="cpu";compatible="arm,cortex-m4";reg=lt;0gt;;};};它描述:CPU │ └── Cortex-M4如果你的公司 SoC 是:Cortex-M33那么这里的描述自然会不同。如果是:RISC-V则整个 Architecture 层又不同。这也正好对应你上一篇:Architecture ↓ SoC ↓ Board8. Memory例如:memory@20000000{compatible="mmio-sram";reg=0x20000000 0x20000;};表示:0x20000000 │ ├───────────────┐ │ │ ↓ ↓ RAM...128KBFlash 也类似。例如:flash0: flash@8000000{compatible="soc-nv-flash";reg=0x08000000 0x80000;};实际项目中具体 binding 和 flash controller 的描述会根据 SoC 架构而变化。9. reg:描述硬件地址这是 SoC Devicetree 中非常核心的概念。例如:uart0: uart@40000000{reg=lt;0x40000000 0x1000gt;;};意思可以直观理解成:UART0 Base: 0x40000000 Size: 0x1000即:于是驱动就知道:UART registers ↓ 0x4000000010. interrupts:描述中断连接例如:uart0: uart@40000000{interrupts=lt;50gt;;};可以理解为:
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进