Zephyr设备树

设备树:

详解Zephyr设备树(DeviceTree)与驱动模型

来自 <https://www.cnblogs.com/jayant97/articles/17209392.html>

设备树文件有*.dts、*.dtsi两种,其中,图3、图4是图1的xp_cortex_m7.dts引用头文件xpm7.dtsi内容,*.dts文件是一种ASCII文本对Device Tree的描述,一个*.dts文件对应一个ARM的machine,由于一个SOC可能有多个不同的电路板,而每个电路板拥有一个 *.dts。这些dts势必会存在许多共同部分,为了减少代码的冗余,设备树将这些共同部分提炼保存在*.dtsi文件中,供不同的dts共同使用。*.dtsi的使用方法,类似于C语言的头文件,在dts文件中需要进行include *.dtsi文件。当然,dtsi本身也支持include 另一个dtsi文件。

类似于sram0:memory@40000000{}这样的子节点,其中40000000是一种新的设备树概念即单元地址,使用@符号将子节点与单元地址衔接

下面了解一下设备树节点中的各种属性,设备树常用属性有以下几种

compatible:代表的硬件设备的名称,推荐的格式是"vendor,device",“vendor”部分是供应商名字,可以在 dts/bindings/vendor-prefixes.txt查询,“device”部分为模块对应驱动的名字,构建系统使用 compatible 属性为节点找到 正确的绑定,作为驱动和设备(设备节点)的匹配依据,以图4为例,compatible = “arm,pl011”;参数为arm公司的pl011 驱动,而根目录下compatible = "ti,lm3s6965evb-qemu", "ti,lm3s6965";会发现没有ti这样的公司,也没有lm3s6965这样 的驱动,实际上这里的"ti,lm3s6965"为zephyrproject/zephyr/dts/arm目录下ti文件夹的lm3s6965.dtsi,而lm3s6965.dtsi 内完成了类似图4这样的驱动设备匹配工作。

label:标签属性与节点标签不是一个内容,标签属性依据设备驱动模型而来,例如UART、I2C等,设置label为I2C_0,则会 调用device_get_binding("I2C_0")并返回一个指向设备结构的指针,该结构可以传递给I2C API函数, 如 i2c_transfer(), 生成的 C 头文件将包含该字符串的宏。

reg:用于描述设备地址空间资源信息,一般都是某个外设的寄存器地址范围信息,常见设置模式为(address, length)。

status:描述设备的状态信息,okay代表设备正常运行,disable代表该设备尚未运行,fail代表表明设备不可操作,fail-sss代 表含义和“fail”相同,后面的 sss 部分是检测到的错误内容。

model:描述板子的型号或者芯片型号,仅仅是给人看的,无其他特殊用途。

#address-cells:决定了子节点 reg 属性中地址信息所占用的字长(u32)。

#size-cells:决定了子节点 reg 属性中长度信息所占用的字长(u32)。

name:用于记录节点名字,已废弃,不建议使用。

ranges:格式 <local地址, parent地址, size>, 表示将local地址向parent地址的转换,比如对于#address-cells和#size-cells 都为1的话,以<0x0  0x10 0x20>为例,表示将local的从0x0~(0x0 + 0x20)的地址空间映射到parent的0x10~(0x10 + 0x20),其中,local地址的个数取决于当前含有ranges属性的节点的#address-cells属性的值,size取决于当前含有ranges 属性的节点的#size-cells属性的值。而parent地址的个数取决于当前含有ranges属性的节点的parent节点的 #address-cells的值。对于含有ranges属性的节点的子节点来说,子节点reg都是基于local地址的,ranges属性值为空 的话,表示1:1映射。

*.dts和*.dtsi是从是从目标的架构、SoC、板和应用程序目录中收集的,*.dts通过c预处理器来include *.dtsi,此外,c预处理器也会处理合并设备树扩展文件*.overlay,并在dts、dtsi、overlay文件中实现宏扩展,预处理器最终输出文件为build/zephyr/zephyr.dts.pre。

 gen_defines.py解析处理zephyr.dts.pre生成包含预处理宏的devicetree_unfixed.h头文件。devicetree.h包含device tree_unfixed.h,源代码通过包含devicetree.h来访问设备树预处理宏。gen_defines.py将最终设备树信息写入zephyr.dts

上述表示方式表示:中断号为0xA,中断优先级为8.

上述表示有2个中断控制器,PIC及GIC,第一个中断连接到中断控制器PIC总线上,中断号为0xA,优先级为8.

 我们无需关心devicetree_generated.h文件本身的内容,因为它不是给人看的,需要使用一套宏函数来将其读出。在需要操作DeviceTree的文件中包含以下头文件:

#include<zephyr/devicetree.h>

这里给出一个示例

/{
    zephyr,user {
        test-gpios = <&gpio0 17 0>;
    };

};

#include<zephyr/drivers/gpio.h>// 自己想要操作的节点的id,这里想要操作的节点是zephyr,user

#define NODE_ID DT_PATH(zephyr_user)

// 获取到zephyr,user节点的test-gpios属性,并把它作为gpio specifier,读入GPIO驱动。

Static const struct gpio_dt_spec test_io=GPIO_DT_SPEC_GET(NODE_ID, test_gpios);

// 实际代码

Int main()

{
    // 判断设备(这里是gpio控制器)是否已初始化完毕

   // 一般情况下,在application运行前,zephyr驱动就已经把控制器初始化好了

if(!device_is_ready(test_io.port)) {
        return;
    }
   
    // 重新配置IO

   // 如果DeviceTree里写好了,这里也可以不配

gpio_pin_configure_dt(&test_io, GPIO_OUTPUT_INACTIVE);
   
    // 操作IOgpio_pin_set_dt(&test_io,1);
    gpio_pin_set_dt(&test_io,0);
   
    return0;
}

 获得节点id的方式还有很多:通过父节点找子节点、通过子节点找父节点等等。详细不多赘述,可参考:

https://docs.zephyrproject.org/latest/build/dts/api-usage.html#node-identifiers

DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), clock_frequency)  /* 宏展开为 1 */

DT_NODE_HAS_PROP(DT_NODELABEL(i2c1), not_a_property)   /* 宏展开为 0 */

Devicetree API的参考手册

通用API及设备相关的特殊API接口,特殊API接口提供了与外设相关的特定的一些API操作。

整数与字符串示例:

DT_PROP(DT_PATH(soc, i2c_40002000), clock_frequency)  /* 宏展开为 100000, */

#define I2C1 DT_NODELABEL(i2c1)

DT_PROP(I2C1, status)  /* 宏展开为 "okay" */

数组示例:

​ 假设dts为

foo:foo@1234 {
          a = <1000 2000 3000>; /* array */

b = [aa bb cc dd];    /* uint8-array */

           c = "bar", "baz";     /* string-array */

};

则C代码中可以写作:

Zephyr标准驱动

Zephyr是一个跨平台的操作系统,自然少不了对各类标准硬件的跨平台支持。

详见: Peripherals — Zephyr Project Documentation

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值