新闻详情

新闻详情

首页 / 资讯中心 / 详情

Zephyr BSP: 07-SoC驱动与设备树绑定

发布时间:2026/9/30 10:14:44来源:尧图网络
Zephyr BSP: 07-SoC驱动与设备树绑定
摘要:承接第 06 篇的 Devicetree 实战,本篇进入 SoC BSP 的驱动层,核心主线是「Binding 定义规则、DTS 描述实例、Driver 执行操作」。通过一个完整 UART 实例,串联 Binding YAML → Devicetree 节点 → Driver 宏的编译期链路,并剖析 Config/Data 模式与多实例生成机制,为下一篇 UART Driver 最小实战铺路。SoC Driver 与 Devicetree Binding这一篇正好进入Zephyr SoC BSP 真正的"驱动层"。你前面已经建立了这条主线:01 Zephyr Hardware Model02 Architecture → SoC → Board03 Zephyr SoC Porting04 SoC Porting 实战05 Zephyr SoC Devicetree06 SoC Devicetree 实战07 SoC Driver + Devicetree Binding ← 现在对于你的最终目标——把公司自己的 SoC 加入 Zephyr 开发生态——这一篇尤其重要,因为从这里开始,你要理解:本文核心结论速览在深入正文之前,先把本篇最关键的几条结论放在这里,方便你带着主线阅读:三者分工:Binding 定义规则(属性 schema),DTS 描述实例(硬件长什么样),Driver 执行操作(如何控制硬件)。三者通过compatible这条"钥匙"串成完整链路。compatible 匹配机制:Devicetree 节点里的compatible = "mycompany,myuart"与 Binding YAML 中的compatible完全一致时,Binding 才会被应用;Driver 再通过#define DT_DRV_COMPAT mycompany_myuart(逗号转下划线)绑定到同一批节点。编译期生成原理:DT_INST_*宏(如DT_INST_REG_ADDR、DT_INST_IRQ)不是运行时查询,而是 Devicetree Compiler 在编译期把节点属性展开成字面量常量,直接写进config结构体。多实例机制:DT_INST_FOREACH_STATUS_OKAY(MYUART_DEFINE)在编译期遍历所有status = "okay"的同 compatible 节点,逐个展开宏,让一个 Driver 自动服务多个硬件实例(uart0 → inst=0,uart1 → inst=1)。Config/Data 设计模式:config保存"这个硬件是什么"(编译期确定),data保存"当前处于什么状态"(运行时可变),这是 Zephyr Driver 的核心思维。SoC BSP 职责边界:硬件描述问题看 Devicetree/Binding,硬件操作问题看 Driver,SoC 初始化问题看 SoC Porting,板级连接问题看 Board DTS——四类问题各有归属,不要混为一谈。SoC 硬件资源如何通过 Devicetree 描述,再由 Driver 读取这些描述并控制硬件。一、先建立整体认识很多初学者会把这几个概念混在一起:Devicetree Binding Driver HAL SoC Board实际上它们各自解决不同的问题。可以先记住:Zephyr Application │ ▼ Zephyr API │ ▼ Driver │ ┌──────────┴──────────┐ │ │ Devicetree HAL / Register │ │ ▼ ▼ 硬件描述 硬件操作 │ │ └──────────┬──────────┘ ▼ SoC例如:gpio_pin_set_dt(led, 1);Application 并不知道:GPIO controller 在哪里 哪个寄存器 哪个 bit clock 怎么开 pinmux 怎么配置为了更直观地看清六者的完整调用链和数据流,这里给出一张总览图:┌─────────────────────────────────────────────────────────────────────┐ │ Zephyr Application │ │ (调用 Zephyr API,不感知底层硬件细节) │ └───────────────────────────────┬─────────────────────────────────────┘ │ ① 调用标准 API(如 uart_poll_out) ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Zephyr API │ │ (uart / gpio / spi 等子系统对外统一接口) │ └───────────────────────────────┬─────────────────────────────────────┘ │ ② 分发到具体 Driver 的 API 回调 ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Driver │ │ ┌───────────────────────┐ ┌───────────────────────────┐ │ │ │ config(编译期常量) │ │ data(运行时状态) │ │ │ │ 来自 DT_INST_* 宏 │ │ 波特率、缓冲、标志位等 │ │ │ └───────────┬───────────┘ └───────────────────────────┘ │ │ │ ③ 读取编译期生成的硬件配置 │ └───────────────┼─────────────────────────────────────────────────────┘ │ ④ 通过 DT_INST_* 宏取地址/中断/时钟 ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Devicetree(DTS)│ │ uart0: serial@40000000{compatible="mycompany,myuart";...}│ │ (描述硬件实例:地址、中断、时钟、引脚) │ └───────────────┬─────────────────────────────────────────────────────┘ │ ⑤ 节点属性由 Binding 校验合法性 ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Binding YAML │ │ compatible:"mycompany,myuart"│ │ properties: reg / interrupts / clocks... │ │ (定义属性 schema,编译期被 Devicetree Compiler 读取) │ └───────────────┬─────────────────────────────────────────────────────┘ │ ⑥ 校验通过后,节点属性被编译成宏 ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ HAL │ │ (寄存器读写封装:sys_read32 / sys_write32,屏蔽位操作细节) │ └───────────────┬─────────────────────────────────────────────────────┘ │ ⑦ 最终读写 SoC 物理寄存器 ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ SoC │ │ (UART / GPIO / SPI 等外设的物理寄存器,由 SoC Porting 提供时钟、 │ │ 中断控制器、低层启动等基础能力) │ └───────────────┬─────────────────────────────────────────────────────┘ │ ⑧ 引脚/板级连接由 Board DTS 决定 ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Board │ │ (板级 DTS / overlay:UART0 接到哪个 pin、LED 接哪个 GPIO 等) │ └─────────────────────────────────────────────────────────────────────┘这张图把六者的职责和相邻层之间的接口串成一条完整链路,可以这样理解:Application → Zephyr API:应用只调用标准 API,不感知底层硬件细节,接口是uart_poll_out()、gpio_pin_set_dt()这类统一函数。Zephyr API → Driver:API 层把调用分发到具体 Driver 的 API 回调(如uart_driver_api中的poll_out),接口是struct uart_driver_api。Driver → Devicetree → Binding:Driver 通过DT_INST_*宏在编译期读取 Devicetree 节点属性,而节点属性是否合法由 Binding 校验;接口是DT_INST_REG_ADDR()、DT_INST_IRQ()等宏。Driver → HAL → SoC:Driver 通过 HAL 的寄存器读写封装(sys_read32/sys_write32)最终操作 SoC 物理寄存器;接口是寄存器读写函数。SoC → Board:SoC 提供外设控制器,但具体引脚连接、板级外设由 Board DTS 决定;接口是板级 DTS 中的pinctrl和节点引用。这些事情由下面几层共同完成:Application ↓ GPIO API ↓ GPIO Driver ↓ Devicetree ↓ SoC GPIO registers二、为什么 SoC BSP 一定会遇到 Driver?假设你的公司 SoC 有:UART0 UART1 GPIO0 GPIO1 I2C0 SPI0 TIMER0 PWM0 ADC0那么 Zephyr 必须知道:UART0 在哪里? UART0 有哪些寄存器? UART0 的 clock 怎么打开? UART0 的 interrupt 是什么? UART0 使用哪个 pin?这些信息不能全部硬编码在 Driver 中。否则你最后可能写出:# define UART0_BASE 0x40000000# define UART0_IRQ 32# define UART0_CLK ...然后 Driver 里面到处都是:# define ...这会导致 Driver 与具体 SoC 强耦合。Zephyr 更希望:Devicetree ↓ 描述硬件实例 ↓ Driver ↓ 读取硬件配置所以:Devicetree Binding + Devicetree + Driver 是一组完整体系。三、什么是 Devicetree Binding?Binding 可以理解成:告诉 Zephyr:一个 Devicetree 节点允许有哪些属性,以及这些属性分别是什么类型。例如我们有:uart0: serial@40000000{compatible="company,foo-uart";reg=lt;0x40000000 0x1000gt;;interrupts=lt;32gt;;clocks=lt;clk UART0_CLKgt;;status="okay";};这里:compatible reg interrupts clocks status都是 Devicetree properties。Binding 则描述:compatible: company,foo-uart properties: reg: type: array interrupts: type: array clocks: type: phandle-array所以:DTS │ │"我有这些属性"▼ Binding │ │"这些属性是否合法、是什么类型"▼ Devicetree validation四、Binding 最重要的东西:compatible在 Zephyr Driver 中,最重要的连接点之一就是:compatible="company,foo-uart";Driver 通过它识别硬件。例如:compatible="mycompany,myuart";对应:compatible:"mycompany,myuart"然后 Driver:# define DT_DRV_COMPAT mycompany_myuart注意这里有一个非常重要的转换:"mycompany,myuart"↓ mycompany_myuart也就是:vendor,device ↓ vendor_device然后:DT_INST_FOREACH_STATUS_OKAY(...)就可以找到 Devicetree 中:compatible="mycompany,myuart";的实例。五、Binding 文件放在哪里?Zephyr 中通常是:dts/ └── bindings/ ├── serial/ ├── gpio/ ├── i2c/ ├── spi/ ├── pwm/ └──...例如:dts/bindings/serial/mycompany,myuart.yaml可能写成:description: MyCompany UART controller compatible:"mycompany,myuart"include:\- name: base.yaml properties: reg: required:trueinterrupts: required:trueclocks: required:true这里最重要的是:compatible:"mycompany,myuart"它把:Binding和:Devicetreenode联系起来。六、一个完整例子假设公司 SoC 有一个 UART:UART0 Base Address=0x40000000 Size=0x1000 IRQ=32那么我们可以设计:1. Bindingdts/bindings/serial/mycompany,myuart.yaml例如:description: MyCompany UART compatible:"mycompany,myuart"properties: reg: required:trueinterrupts: required:trueclocks: required:true2. Devicetreeuart0: serial@40000000{compatible="mycompany,myuart";reg=lt;0x40000000 0x1000gt;;interrupts=lt;32gt;;clocks=lt;clk UART0_CLKgt;;status="okay";};3. Driver# define DT_DRV_COMPAT mycompany_myuart然后:static const struct device\*dev;Driver 就可以通过 Devicetree 宏取得:reg interrupts clocks例如:# define UART_BASE(inst) \\DT_INST_REG_ADDR(inst)最终:UART_BASE(0)可能得到:0x40000000这就是 Zephyr 非常核心的一种工作方式:DTS │ ▼ Devicetree Compiler │ ▼ generated devicetree information │ ▼ DT_INST_REG_ADDR()DT_INST_IRQ()DT_INST_PROP()DT_INST_CLOCKS_... │ ▼ Driver七、Driver 到底在做什么?以 UART 为例。应用:printk("Hello\\n");最终需要 UART Driver。Driver 的职责通常包括:初始化 ↓ clock ↓ pinmux ↓ UART registers ↓ interrupt ↓ buffer ↓ Zephyr UART API例如:staticintmyuart_init(conststructdevice\*dev){conststructmyuart_config\*config=dev-config;/* enable clock *//* configure registers *//* configure interrupt */return0;}这里:config往往就是从 Devicetree 生成的。八、Config 和 Data 是 Driver 设计中的核心Zephyr Driver 中非常重要的一个模式:structmyuart_config{uintptr_tbase;intirq;};structmyuart_data{...};通常:config ↓ 硬件配置 ↓ 编译期确定而:data ↓ 运行时状态例如:struct myuart_config{uintptr_t base;};struct myuart_data
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

C++五子棋源码详解:从棋盘判定到贪心人机AI 2026/9/30 10:14:41

C++五子棋源码详解:从棋盘判定到贪心人机AI

简介:一款使用C语言编写的五子棋游戏及其完整源码,同时支持人机对战与人人对战,适合游戏编程初学者、在校学生以及希望积累C项目经验的开发者。程序实现中运用了类与对象机制,并通过STL容器管理棋盘数据;人机模式采用基…

阅读更多 →
Ubuntu中文输入法设置全攻略:从iBus到Fcitx5及搜狗移植 2026/9/30 10:14:41

Ubuntu中文输入法设置全攻略:从iBus到Fcitx5及搜狗移植

从 Windows 切到 Ubuntu 的第一天,我就在“中文输入法”这道坎上栽过跟头。装完系统之后中文字库是正常的,但敲键盘只能出英文,翻遍了系统设置也没找到“添加中文拼音”的入口,后来才知道 Ubuntu 桌面版默认用的是 iBus 输入法框架…

阅读更多 →
WorkBuddy 从入门到精通:Agent、Skill 与 models.json 配置实战指南 2026/9/30 10:14:41

WorkBuddy 从入门到精通:Agent、Skill 与 models.json 配置实战指南

1. 先搞清楚 WorkBuddy 到底是个什么东西很多人第一次听到 WorkBuddy 这个名字,第一反应是"又一个套壳聊天工具"。我一开始也这么想,直到真正把它接进日常工作流跑了两周,才发现它和普通对话式 AI 的定位完全不是一回事。WorkBuddy…

阅读更多 →
WorkBuddy AI工作台实战:Agent与Skill机制及自定义模型配置指南 2026/9/30 10:14:41

WorkBuddy AI工作台实战:Agent与Skill机制及自定义模型配置指南

1. 为什么我要认真聊聊 WorkBuddy 这个 AI 工作台 第一次接触 WorkBuddy 是在一个做企业数字化的朋友推荐下,当时我的第一反应是"又一个套壳聊天工具"。但真正用起来之后,我发现它和市面上大多数"对话框模型"的产品完全不是一个思路…

阅读更多 →
法律咨询智能路由:DeepSeek语义解析与GNN专家精准匹配方案 2026/9/30 10:14:27

法律咨询智能路由:DeepSeek语义解析与GNN专家精准匹配方案

简介:面向图神经网络算法工程师、法律科技产品研发与自然语言处理研究者,这份474页技术方案围绕DeepSeek法律咨询智能路由与专家匹配场景,系统解决用户问题语义解析与专家资源精准对接两大核心难题。文档按51个大章节展开,覆盖法律…

阅读更多 →
农行Web端网银支付Java对接实践:表单跳转、签名验签与证书管理详解 2026/9/30 10:14:27

农行Web端网银支付Java对接实践:表单跳转、签名验签与证书管理详解

简介:面向Java后端开发者,资源包用于打通农行Web端网银支付的Java接口集成链路。适合电商、在线服务等需要接入农行网银支付的团队,尤其是在银行对接方面缺少经验的开发者,可据此快速理解接口文档,降低启动门槛。压缩包…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉