驱动(RK3588S)第七课时:单节点设备树

news2024/9/19 9:31:25

目录

  • 需求
  • 一、设备树的概念
    • 1、设备树的后缀名:
    • 2、设备树的语法格式
    • 3、设备树的属性(重要)
    • 4、设备树格式举例
  • 二、设备树所用函数
    • 1、如何在内核层种获取设备树节点:
    • 2、从设备树上获取 gpio 口的属性
    • 3、获取节点上的属性只针对于字符串属性的
    • 4、函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的 u32 类型的数据的个数。
  • 三、设备树的编译与烧写
  • 四、代码
  • 五、现象

需求

利用设备树和字符设备驱动实现对LED等的控制。

一、设备树的概念

设备号:这里用到的是linux2.6动态创建的设备号。他是一个完整的设备号,这个完整的设备号里包含了主设备号和次设备号,这里他是一个 32 位的设备号,32 位里前 12 位是主设备号,后 20 位是次设备号,所以他的这个设备号的取值范围是比较大的。
设备树:他是描述硬件设备资源的文本文件,因为设备树里边的内容架构像树形结构,因此就被称为设备树。以前是没有设备树,之所以有设备树,是因为 linux 之父在 Linux 社区公开开骂,是因为内核太过于臃肿了,内核里的内容太过于复杂,大部分都是垃圾代码,Linux 本身就是开源免费的,其实他就提供一个 ARM 架构的框架,因为当今电子产品跟新换代太快了,所有的厂商都可以使用 linux 内核架构,他们各大厂商都会把自己公司代码,统统往内核塞,所以这些 Linux 社区里的大神看到 Linux 之父的愤怒,因此就搞了一个新
的内容出来,他就是设备树,设备树他就是一个文件,只不过这个文件是用来描述硬件设备资源的。
在这里插入图片描述
目前设备树的使用在驱动里是非常受欢迎的因为其使用简单,它大大的简化了你写驱动代码的架构。
其实驱动代码他在平台设备总线里的分为了两部分。
设备端:他就只提供硬件设备的资源 比如:中断资源 GPIO 资源等。
驱动端:就是驱动代码的框架使用杂项或 Linux2.6 创建设备号。他会和设备端进行 匹配,然后从设备端获取硬件的资源,来驱动对应的硬件,但是有了设备树之后就把设备端给替代了。

1、设备树的后缀名:

设备树他有自己的语法规则,就类似于一门语言,你编写设备树的时候需要遵循设备树的语法规则。
dts:就是咱们编写修改的文件 — 有点像你 C 语言的.c 文件
dtsi:他是设备的原始文件 — 一般是有厂商写的 — 有点像你 C 语言的.h 文

dtb:就是设备树编译生成的二进制文件 — 有点像你 C 语言的.o 文件
dtc:编译设备树的工具 — 有点像你 C 语言的 gcc 文件

2、设备树的语法格式

/dts-v1/; — 设备树的版本 — 一般是必须要有的
/ ---- 这个设备树文件的根 ,也就是起始的位置
他下边可以保护很多的子节点,子节点里可以包含在的子节点
/ {
属性名=属性值;
属性名=属性值;
子节点名 {
属性名=属性值;
属性名=属性值;
子节点名 {
属性名=属性值;
属性名=属性值;
};
};
};
在这里插入图片描述

3、设备树的属性(重要)

model:他是描述开发板信息的属性 ,主要是公司芯片的型号 它是一个字符串。
compatible:他是设备树属性里最重要的一个属性。他就是用来做匹配的,因为设备树是描述设备信息的,而设备信息是驱动代码使用的。驱动代码怎么找到设备树里的具体某一个设备 节点的信息,设备树里可以包含很多个节点信息,这里就通过 compatible 去找到这个节点他也是一个字符串,他也可以是多个字符串如compatible = “xyd-led”, “rk-led”;查找顺序是现按照 xyd-led,如果找不到就在往后找 rk-led。几乎每一个节点里都包含了此节点。
status:设备当前的一个状态 — 他的属性值也是一个字符串。
okay — 他是可以使用的
disabled — 禁用/失能
就是这个设备默认是否可以使用。

4、设备树格式举例

设备树有以下三种格式。
/ {
model = “xyd rk3588s leds gpios”
xydled1 {
compatible = “xyd-led1”;
led-gpios = <&gpio1 RK_PB4 GPIO_ACTIVE_LOW>;
status = “okay”;
};
xydled2: myled {
compatible = “xyd-led2”;
led-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
status = “okay”;
};
xydled3: myled@ff690000 {
compatible = “xyd-led2”;
led-gpios = <&gpio0 RK_PB5 GPIO_ACTIVE_LOW>;
status = “okay”;
};
};

二、设备树所用函数

1、如何在内核层种获取设备树节点:

一共有三种方法:用的比较多的是用属性进行查找。
struct device_node *of_find_node_by_name(struct device_node
*from, const char *name);
**struct device_node *of_find_compatible_node(struct device_node
*from, const char type, const char compatible)
struct device_node *of_find_node_by_path(const char *path)
函数功能:在设备树上寻找你指定的设备节点
函数原型:struct device_node of_find_compatible_node(struct device_nodefrom, const char *type,const char *compatible)
函数头文件:#include <linux/of.h>
函数参数:device_node:写 NULL 代表从头开始
type:写 NULL
compatible:设备节点上的 compatible 的属性的值
函数返回值:成功返回指向一个 struct device_node 指针 失败 NULL

2、从设备树上获取 gpio 口的属性

函数功能:从设备树上获取 gpio 口的属性
函数原型:int of_get_named_gpio(struct device_node *np,const char *propname, int index)
函数头文件:#include <linux/of_gpio.h>
函数参数:np:设备树节点的信息
propname:获取 gpio 口属性的名字
index:获取 gpio 口资源的编号 — 你要获取第几个资源
函数返回值:成功获取得到的 gpio 口的编号 失败返回负数

3、获取节点上的属性只针对于字符串属性的

函数功能:获取节点上的属性 — 针对于字符串属性的
函数原型:int of_property_read_string(struct device_node np,const charpropname, const char **out_string)
函数头文件:#include <linux/of.h>
函数参数:np:设备节点
propname:获取的节点属性的名字
out_string:保存获取得到的属性的值
函数返回值:成功返回 0 失败返回负数

4、函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的 u32 类型的数据的个数。

函数功能:函数读取 np 结点中的 propname 属性的值,并将读取到的 u32 类型的值保存在 out_value 指向的内存中,函数的返回值表示读取到的 u32 类型的数据的个数。
函数原型:int of_property_read_u32_index(const struct device_node *np,
const char *propname,u32 index,u32 *out_value)
函数头文件:#include <linux/of.h>
函数参数:np:设备节点
propname:节点里的那一个属性 — 属性的名字
index:获取这个属性里的一个值 — 如果一个默认就写 0
out_value:保存获取得到信息
函数返回值:成功返回 0 失败返回负数

三、设备树的编译与烧写

这里我使用瑞芯微编写好的脚本去编译的。
你在设备树里写好自己的设备节点信息之后返回 RK3588S 的顶层目录执行
./build.sh kernel ,就会默认就编译设备树文件了,并且他把编译生成的设备树的 dtb 文件给继承了到 boot.img 镜像里使用烧录工具单独去烧写 boot.img 即可里边就包括了你自己写的设备节点。
开发板设备树节点的位置
/sys/firmware/devicetree/base/xyd_led
/proc/device-tree/xyd_led

内核中的设备树节点:
在这里插入图片描述
dev下的设备节点:
在这里插入图片描述

四、代码

内核底层驱动:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/gpio.h>
#include <linux/device.h>
#include <linux/fs.h>
dev_t dev;
int all;
struct cdev mydev;
struct class *myclass=NULL;
int gpio_values[2]={0};
const char *out_string = NULL;
ssize_t myled_read (struct file *file, char __user *user, size_t size, loff_t *fd)
{
	printk("myled read ok\n");
	printk("读取数据成功\n");
	return 0;
}
ssize_t myled_write (struct file *file, const char __user *user, size_t size, loff_t *fd)
{
	printk("myled write ok\n");
	printk("写入数据成功\n");
	return 0;
}
int myled_open (struct inode *inode, struct file *fp)
{
	gpio_set_value(gpio_values[0],1);
	gpio_set_value(gpio_values[1],1);
	printk("myled open ok\n");
	printk("myled open 正确打开\n");
	return 0;
}

int myled_close (struct inode *inode, struct file *fp)
{
	gpio_set_value(gpio_values[0],0);
	gpio_set_value(gpio_values[1],0);
	printk("myled close ok\n");
	printk("myled close 关闭正确\n");
	return 0;
}
struct file_operations myfops={
	.owner = THIS_MODULE,
	.open = myled_open,
	.release = myled_close,
	.read=myled_read,
	.write=myled_write,

};
static int __init myled_init(void)
{	
	struct device_node *node=of_find_compatible_node(NULL,NULL,"myqxj_led");
	printk("节点的名字:%s\n",node->name);
	gpio_values[0]=of_get_named_gpio(node,"led-gpios", 0);
	gpio_values[1]=of_get_named_gpio(node,"led-gpios", 1);
	printk("gpio_values[0]:%d\n",gpio_values[0]);
	printk("gpio_values[1]:%d\n",gpio_values[1]);
	of_property_read_string(node,"status", &out_string);
	printk("out_string:%s\n",out_string);
	if(strcmp("okay",out_string)!=0)
	{
		printk("设备节点信息不可用\n");
		return -1;
	}
	gpio_request(gpio_values[0], "led1");
	gpio_request(gpio_values[1], "led2");
	gpio_direction_output(gpio_values[0], 1);
	gpio_direction_output(gpio_values[1], 1);	
	all=alloc_chrdev_region(&dev,0, 1,"led");
	if(all<0)
	{
		printk("alloc_chrdev_region error\n");
		printk("动态创建失败\n");
		return -1;
	}
	printk("主设备号:%d\n",MAJOR(dev));
	printk("次设备号:%d\n",MINOR(dev));
	cdev_init(&mydev,&myfops);
	cdev_add(&mydev,dev,1);
	myclass=class_create(THIS_MODULE,"class_led");//创建类
	if(myclass == NULL)
	{
		printk("class_create error\n");
		printk("class_create 类创建失败\n");
		return -1;
	}
	device_create(myclass,NULL,dev,NULL,"myqxjled");
	return 0;
}
static void __exit myled_exit(void)
{
	device_destroy(myclass,dev);
	class_destroy(myclass);
	cdev_del(&mydev);
	unregister_chrdev_region(dev,1);
	gpio_free(gpio_values[0]);
	gpio_free(gpio_values[1]);
}
module_init(myled_init);
module_exit(myled_exit);
MODULE_LICENSE("GPL");

应用层:

五、现象

代码运行状态:
在这里插入图片描述
在这里插入图片描述
灯现象:灯亮灭交替闪烁。
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2115092.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【0324】Postgres内核 Shared Buffer Access Rules (共享缓冲区访问规则)说明

0. 章节内容 1. 共享磁盘缓冲区访问机制 (shared disk buffers) 共享磁盘缓冲区有两套独立的访问控制机制:引用计数(a/k/a pin 计数)和缓冲区内容锁。(实际上,还有第三级访问控制:在访问任何属于某个关系表的页面之前,必须持有该关系表的适当类型的锁。这里不讨论关系…

[Linux Kernel Block Layer第一篇] block layer架构设计

目录 1. single queue架构 2. multi-queue架构&#xff08;blk-mq) 3. 问题 随着SSD快速存储设备的发展&#xff0c;内核社区越发发现&#xff0c;存储的性能瓶颈从硬件存储设备转移到了内核block layer&#xff0c;主要因为当时的内核block layer是single hw queue的架构&…

【C语言】插入排序、希尔排序——动图展示

目录 1. 插入排序1.1 基本概念1.2 实现思路1.3 代码部分 2. 希尔排序2.1 为什么会有希尔排序&#xff1f;2.2 基本概念2.3 实现思想1&#xff09;单组排序2&#xff09;多组排序 2.4 代码部分 3. 总结 1. 插入排序 1.1 基本概念 把待排序的记录逐个插入到一个已经排好序的有序…

PMP–一、二、三模–分类–14.敏捷–技巧–看板面板与燃尽图燃起图

文章目录 技巧一模14.敏捷--方法--看板&#xff08;类似卡片&#xff09;1、 [单选] 根据项目的特点&#xff0c;项目经理建议选择一种敏捷方法&#xff0c;该方法限制团队成员在任何给定时间执行的任务数。此方法还允许团队提高工作过程中问题和瓶颈的可见性。项目经理建议采用…

微软出品的一款管理多个远程桌面连接的工具

RDCMan&#xff08;Remote Desktop Connection Manager&#xff09;是微软官方出品的一款用于管理多个远程桌面连接的工具。它可以帮助用户集中管理和分类远程桌面&#xff0c;特别适用于需要同时管理大量服务器或在不同计算机间切换操作的场景。 RDCMan的主要功能包括&#x…

使用WebP解决网站加载速度问题,这些细节你需要了解

说到网页的图片格式,大家最常想到的可能是JPEG、PNG,毕竟这些老牌格式陪伴我们这么多年。然而,近几年,有一个格式悄悄崭露头角,那就是WebP。很多人可能听说过,但到底它好在哪?你的网站或者项目是不是也应该用WebP呢?别着急,今天咱们就来好好聊聊WebP这个图片格式的前世…

SOMEIP_ETS_095: SD_Check_subscribe_eventgroup_ttl_expired

测试目的&#xff1a; 验证DUT&#xff08;Device Under Test&#xff09;能够检测到测试器&#xff08;Tester&#xff09;的订阅已过期&#xff08;ttl 3秒&#xff09;&#xff0c;并且在TTL过期后不响应测试器触发的事件。 描述 本测试用例旨在确保DUT能够识别测试器的…

Kettle使用命令pan/kitchen执行任务时传参问题

在用windows任务执行kettle的kjb或ktr文件时&#xff0c;可通过bat命令传递参数&#xff0c;测试了很久&#xff0c;特此记录一下。 一、pan\kitchen 参数说明 Options: /rep : Repository name /user : Repository username /pass : Repository password…

【射频通信电路基础第二讲】射频通信电路基础知识——射频接插件、金属导线的趋肤效应、射频传输线及其特性、衰减电路等

一、射频接插件 参考https://blog.csdn.net/weixin_43813325/article/details/112340937 1、BNC&#xff1a;阻抗一般为50/75Ω&#xff0c;频带宽 2、SMA/SMB&#xff1a;损耗小&#xff0c;价格高昂 SMA接口有两种形式&#xff0c;分别如下所示&#xff0c;常规SMA“外螺纹…

AT32F415的OTA升级

AT32F415的OTA升级 项目简介IAP实现原理AT32中的内置FLASH分配情况AT32中的实现过程跳转到APP的程序代码删除APP区域的FLASH空间代码写APP的bin数据到FLASH空间代码 项目简介 在物联网应用开发过程中&#xff0c;不可避免的会需要用到软件升级&#xff0c;一般情况下&#xff…

C# Hash算法之MD5、SHA

MD5我们用的还是比较多的&#xff0c;一般用来加密存储密码。但是现在很多人觉MD5可能不太安全了&#xff0c;所以都用上了SHA256等来做加密&#xff08;虽然我觉得都差不多,MD5还是能玩&#xff09;。 还是跟上一篇说的一样&#xff0c;当一个算法的复杂度提高的同时肯定会带…

linux dlopen手册翻译

名称 dlclose, dlopen, dlmopen 打开和关闭一个共享对象 简介 #include <dlfcn.h> void *dlopen(const char*filename, int flags); int dlclose(void *handle);#define _GNU_SOURCE #include <dlfcn.h> void *dlmoopen(Lmid_t lmid, const char *filename, int…

【C++ Primer Plus习题】12.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "Stack.h"…

磁电偶极子天线学习1 一种60GHz 宽带圆极化口径耦合磁电偶极子天线阵列

摘要&#xff1a; 一种新型的圆极化口径耦合天线被提出。这种圆极化磁电偶极子天线由刻蚀在短路基片集成波导的一部分的宽臂上&#xff0c;并且很容易被集成基片。在工作频段内实现了宽于28.8%的阻抗带宽和宽带3-dB的25.9%的轴比和的增益。此外&#xff0c;因为圆极化辐射由两个…

稀有卡牌手游【植物大战僵尸】源码

稀有卡牌手游【植物大战僵尸】完整代码&#xff0c;画面精美&#xff0c;非常好玩。代码下载

机器学习1——手把手教你用Python跑一个线性回归模型

目录 一、前期准备 1.Scikit-learn 2.matplotlib 二、机器学习过程 三、代码框架 四、完整代码 1.导入所需库 2.准备训练数据 3.喂入训练数据 4.结果预测 5.输出模型中的w与b值 6.可视化 7.传入不规则数据 一、前期准备 在机器学习中我们使用Python居多&…

基于OMS构建OceanBase容灾双活架构的实践

在实际生产环境中&#xff0c;对于关键业务&#xff0c;往往会有容灾双活的需求。除了OceanBase提供的主备库能力&#xff0c;通过官方工具OMS也可以实现容灾双活架构。目前&#xff0c;通过OMS实现的双活架构仅支持OceanBase数据库之间的数据同步。 要通过OMS实现双活架构&am…

使用Node-API进行线程安全开发

一、Node-API线程安全机制概述 Node-API线程安全开发主要用于异步多线程之间共享和调用场景中使用&#xff0c;以避免出现竞争条件或死锁。 1、适用场景 异步计算&#xff1a;如果需要进行耗时的计算或IO操作&#xff0c;可以创建一个线程安全函数&#xff0c;将计算或IO操作放…

C#程序 Debugger,Release都没问题,但是,打包安装后:System.FormatException: 输入字符串的格式不正确

前言&#xff1a; 这是个问题解决&#xff0c;我们先谈问题&#xff1a; 这个问题不会再本地的调试机器上出现&#xff0c;但是&#xff0c;出现在你部署&#xff0c;或者说安装到其他的机器&#xff08;通过VS构建安装项目来做&#xff09; C#程序 Debugger&#xff0c;Relea…

javascript的模块化

1. 无模块化 script标签引入js文件&#xff0c;相互罗列&#xff0c;但是被依赖的放在前面&#xff0c;否则使用就会报错。如下&#xff1a; <script src"jquery.js"></script><script src"jquery_scroller.js"></script><scr…