设备树简介
设备树是用来描述硬件的分层数据结构,Zephyr操作系统使用设备树来描述器支持的板子上可以使用的硬件设备,以及硬件的初始配置。
分为两种类型的设备输入文件:设备树源和设备树绑定。其中设备树源文件包含设备树本身,绑定描述了它的内容,包括数据类型。构建系统使用设备树源和绑定来生成C头文件,这个生成头文件的内容被include\devicetree.h API抽象,可以用它获取设备树的信息。
设备树文件的拓展名为:.dts
设备树文件的“头”文件(通用文件):.dtsi,类似于C语言的头文件,.dtsi
文件描述了 Zephyr 运行的 CPU 或片上系统,可能包括其他 .dtsi
文件。它们还可以描述多个板共享的其他常见硬件功能,到时候直接引用该.dtsi文件即可。
设备树举例说明
我的开发板是stm32g071rb系列的,因此以该硬件的设备树为例,对设备树语法进行分析学习。
boards\arm\nucleo_g071rb\nucleo_g071rb.dts
/dts-v1/;
#include <st/g0/stm32g071Xb.dtsi>
#include <st/g0/stm32g071r(6-8-b)tx-pinctrl.dtsi>
#include "arduino_r3_connector.dtsi"
/ {
model = "STMicroelectronics STM32G071RB-NUCLEO board";
compatible = "st,stm32g071rb-nucleo";
chosen {
zephyr,console = &usart2;
zephyr,shell-uart = &usart2;
zephyr,sram = &sram0;
zephyr,flash = &flash0;
};
power-states {
stop0: state0 {
compatible = "zephyr,power-state";
power-state-name = "suspend-to-idle";
substate-id = <1>;
min-residency-us = <20>;
};
stop1: state1 {
compatible = "zephyr,power-state";
power-state-name = "suspend-to-idle";
substate-id = <2>;
min-residency-us = <100>;
};
};
leds {
compatible = "gpio-leds";
green_led_1: led_4 {
gpios = <&gpioa 5 GPIO_ACTIVE_HIGH>;
label = "User LD4";
};
};
gpio_keys {
compatible = "gpio-keys";
user_button: button {
label = "User";
gpios = <&gpioc 13 GPIO_ACTIVE_LOW>;
};
};
aliases {
led0 = &green_led_1;
sw0 = &user_button;
};
};
&clk_hsi {
status = "okay";
};
...
&usart1 {
pinctrl-0 = <&usart1_tx_pc4 &usart1_rx_pc5>;
pinctrl-names = "default";
current-speed = <115200>;
status = "okay";
};
};
/dts-v1/
表示该设备树文件,DTS语法版本是V1;
三个include:引用其它通用设备树文件;
/
表示根节点;
model
:其属性用来描述设备模块信息,属性值一般是字符串形式;这里描述了“意法半导体硬件型号”
compatible
:兼容性属性 ,值为字符串,用于将设备与驱动绑定起来;字符串序列用于选择设备要使用的驱动程序;可以有多个值。
chosen
:chosen节点位于根节点,其不代表实际的硬件,用于给内核传递参数;
子节点
power-states、leds、gpio_keys...都是根节点下的子节点。
其中像power-states节点中又包括了两个子节点。
label
:标签,用于代表节点,方便访问节点,可以通过&label访问该节点。
aliases
:给节点起别名,目的也是为了方便访问节点;
aliases {
led0 = &green_led_1; #给节点green_led_1起个别名为led0
sw0 = &user_button;
};
&节点名
:用于对已有的节点进行追加内容,或者修改内容。
以&clk_hsi为例:
在通用文件:dts\arm\st\g0\stm32g0.dtsi中:
clk_hsi: clk-hsi {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <DT_FREQ_M(16)>;
status = "disabled";
};
在boards\arm\nucleo_g071rb\nucleo_g071rb.dts中,将禁止状态修改为使能状态:
&clk_hsi {
status = "okay";
};
下面看一下nucleo_g071rb.dts引用的通用文件stm32g071Xb.dtsi
#include <mem.h>
#include <st/g0/stm32g071.dtsi>
/ {
sram0: memory@20000000 {
reg = <0x20000000 DT_SIZE_K(36)>;
};
soc {
flash-controller@40022000 {
flash0: flash@8000000 {
reg = <0x08000000 DT_SIZE_K(128)>;
};
};
};
};
在这个文件中只有很少的内容,在根节点下面有两个子节点
以sram0为例。它是描述静态随机存储器的硬件信息。
memory@20000000 指的就是stm32g071xb芯片上的SRAM起始地址为0x20000000
#define DT_SIZE_K(x) ((x) * 1024)
DT_SIZE_K(36) 即36KB,
也就是说设置SRAM的内存大小为36KB。
我们可以对照一下参考手册的Memory map 各寄存器地址分布
再看一下stm32g071Xb.dtsi引用的通用文件
#include <st/g0/stm32g071.dtsi>,其部分内容如下:
/ {
soc {
usart3: serial@40004800 {
compatible = "st,stm32-usart", "st,stm32-uart";
reg = <0x40004800 0x400>;
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00040000>;
interrupts = <29 0>;
status = "disabled";
label = "UART_3";
};
usart4: serial@40004c00 {
compatible = "st,stm32-usart", "st,stm32-uart";
reg = <0x40004c00 0x400>;
clocks = <&rcc STM32_CLOCK_BUS_APB1 0x00080000>;
interrupts = <29 0>;
status = "disabled";
label = "UART_4";
};
}
我们可以看到soc节点下的usart节点:
其中usart3寄存器的起始地址为0x40004800
其中usart4寄存器的起始地址为0x40004c00
对照一下参考手册的Memory map 各寄存器地址分布