Linux设备树简介以及相关API与历程分享

目录

设备树简介

设备树说明

设备树源文件中相关内容介绍

设备树源文件中的节点示例

设备树相关API简介

of_find_node_by_path()

of_find_node_by_name()

of_get_named_gpio()

设备树相关历程

历程简介

设备树中添加的节点

驱动代码分享


设备树简介

        Linux设备树(Device Tree)是一种描述硬件设备的数据结构,用于在Linux内核启动过程中传递硬件信息给内核。它是一种与硬件平台无关的描述语言,旨在提供一种统一的方式来描述硬件设备的配置和连接关系。

        设备树的主要作用是解决硬件平台多样性和可扩展性的问题。传统上,嵌入式系统在内核编译时需要为每个硬件平台进行配置,这导致了内核的臃肿和不可移植性。而设备树的引入使得内核可以在运行时动态地获取硬件信息,从而支持更多的硬件平台和设备。

        设备树的结构是一种层级的树状结构,以.dts(设备树源文件,相当于C语言里的源文件)、.dtsi(设备树头文件,厂商写的设备树文件,我们的设备树文件一般要包含这类文件)和.dtb(设备树二进制文件,相当于C语言中的可执行文件)的形式存在。设备树描述了硬件设备的各种属性和连接关系,包括设备的类型、地址、中断信息、寄存器配置等。它可以描述处理器、总线、外设等各个层次的硬件设备。

        在Linux内核启动过程中,Bootloader会加载设备树二进制文件,并将设备树传递给内核。内核通过解析设备树来获取硬件信息,并根据设备树的描述来初始化和配置硬件设备,从而使得内核能够正确地与硬件进行交互。

相比于老式的板级适配,设备树有以下优势:

  1. 更好的可移植性。基于通用设备树,内核可以支持更多的硬件平台。
  2. 更好的可扩展性。可以轻松添加设备信息,无需改内核代码。
  3. 更清晰的架构。内核与硬件平台解耦。
  4. 更高效的引导。内核只检测真正存在的硬件。

        总而言之,Linux设备树是一种描述硬件设备的数据结构和描述语言,用于在Linux内核启动过程中传递硬件信息给内核,从而实现对多样性硬件平台的支持和配置

设备树说明

        设备树下有许多以.dts结尾的设备树源文件,用于适配不同的开发板,但设备树下以.dtb结尾的文件只有一个,我们可以根据.dtb文件的名字来寻找本开发板对应的.sts文件

设备树源文件中相关内容介绍

  1. /dts-v1/:设备树源文件的头部,指定设备树的版本。
  2. / {
    }:根节点,表示设备树的最顶层。
  3. compatible:设备的兼容性信息,用于匹配设备树和驱动程序。
  4. reg:设备的寄存器地址和大小。
  5. interrupt-parent:中断控制器的父节点。
  6. interrupts:设备的中断号。
  7. clocks:设备的时钟源。
  8. gpio:设备的GPIO引脚。
  9. i2c:设备的I2C地址和总线号。
  10. spi:设备的SPI片选号和总线号。
  11. phandle:设备节点的句柄,用于在设备树中引用其他设备节点。
  12. node:设备节点,描述一个具体的设备或子系统。

        设备树源文件中的节点和属性可以根据需要进行扩展和修改,以适应具体的硬件配置和连接关系。通过修改设备树源文件,可以实现对硬件设备的配置和初始化,以及设备之间的连接关系的描述。需要注意的是,设备树源文件是一种描述硬件的中立语言,具体的设备树源文件内容和结构会根据不同的硬件平台和设备而有所不同。因此,具体的设备树源文件内容需要参考硬件平台和设备的文档和规范。

设备树源文件中的节点示例

//该节点描述了一个名为"bigbeep"的设备
bigbeep: big-beep{
		compatible = "mybeep";//指定设备的兼容性字符串,用于匹配设备树和驱动程序。在这里,"mybeep"是自定义的兼容性字符串,用于指定与此设备兼容的驱动程序
		label = "beep";//指定设备的标签,用于标识设备的名称或功能
		gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;//定设备所使用的GPIO引脚。"&gpio0"表示引用名为"gpio0"的GPIO控制器节点,"RK_PC3"表示引脚的名称或编号,"GPIO_ACTIVE_HIGH"表示引脚的电平触发方式为高电平触发
		default-state = "off";//指定设备的默认状态。在这里,设备的默认状态为关闭(off)
	};

设备树相关API简介

of_find_node_by_path()

功能
	通过路径查找节点信息
头文件
    linux/of.h
原型
    struct device_node *of_find_node_by_path(const char *path)
参数
    const char *path	设备树里节点的路径
返回值
    成功 设备树的节点的结构体指针
    失败 NULL

of_find_node_by_name()

功能
	通过节点名查找节点信息
头文件
    linux/of.h
原型
    struct device_node *of_find_node_by_name(struct device_node *from, const char *name)
 参数
     struct device_node *from    NULL 从根节点开始查找
     const char *name    要查找的节点名字
返回值
    成功 设备树的节点的结构体指针
    失败 NULL

of_get_named_gpio()

功能
	通过设备树节点结构体获取gpio信息
头文件
	linux/of_gpio.h
原型
		int of_get_named_gpio(struct device_node *np, const char *propname, int index)
参数
		struct device_node *np		节点结构体
		const char *propname       gpio属性的名字
		int index                   索引号  一般写  0
返回值
		gpio的编号

设备树相关历程

历程简介

这个例程的功能是通过设备树中的节点信息来控制蜂鸣器。

  1. 在设备树中添加了一个名为 bigbeep 的节点,该节点包含了蜂鸣器的设备信息,包括兼容性属性、标签、GPIO 引脚信息和默认状态。
  2. 驱动代码中,通过调用函数 of_find_node_by_path() 来查找设备树中的 bigbeep 节点,并将其地址保存在 mynode 变量中。
  3. 使用函数 of_get_named_gpio() 从设备树中获取名为 "gpios" 的属性值,并将其赋值给 gpio_num 变量。
  4. 调用函数 gpio_request() 来申请使用 gpio_num 对应的 GPIO 引脚。
  5. 调用函数 gpio_direction_output() 将 gpio_num 对应的 GPIO 引脚设置为输出模式。
  6. 调用函数 gpio_set_value() 将 gpio_num 对应的 GPIO 引脚设置为高电平,从而点亮蜂鸣器。
  7. 在退出函数 mytest_exit() 中,没有进行任何操作(懒得写)。
  8. 使用宏 module_init() 和 module_exit() 注册初始化函数和退出函数。
  9. 使用宏 MODULE_LICENSE() 声明模块的许可证。

设备树中添加的节点

bigbeep: big-beep{
		compatible = "mybeep";
		label = "beep";
		gpios = <&gpio0 RK_PC3 GPIO_ACTIVE_HIGH>;
		default-state = "off";
	};

驱动代码分享

#include 
#include 
#include 
#include 
#include 

struct device_node *mynode = NULL;
int gpio_num = 0;

static int __init mytest_init(void){
	
	int ret;
	//通过路径查找设备树节点
	mynode = of_find_node_by_path("/bigbeep");
	if(mynode == NULL){
		printk("获取结构体地址失败\n");
		return -1;
	}

	//从设备树中获取gpio编号
	gpio_num = of_get_named_gpio(mynode, "gpios", 0);
	printk("name=%s\n", mynode->);
	printk("引脚编号 %d\n", gpio_num);

	//申请io口
	ret = gpio_request(gpio_num, "beep");
	if(ret < 0){
		printk("io口申请失败\n");
		return -1;
	}

	//设置工作模式为输出模式
	gpio_direction_output(gpio_num, 0);

	//设置引脚值
	gpio_set_value(gpio_num, 1);
	
	return 0;
}

static void __exit mytest_exit(void){

}

module_init(mytest_init);
module_exit(mytest_exit);
MODULE_LICENSE("GPL");

你可能感兴趣的:(Linux驱动开发,linux,驱动开发,mcu,c语言)