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

2024-09-08 11:44

本文主要是介绍驱动(RK3588S)第七课时:单节点设备树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 需求
  • 一、设备树的概念
    • 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");

应用层:

五、现象

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

这篇关于驱动(RK3588S)第七课时:单节点设备树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1148017

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

如何编写Linux PCIe设备驱动器 之二

如何编写Linux PCIe设备驱动器 之二 功能(capability)集功能(capability)APIs通过pci_bus_read_config完成功能存取功能APIs参数pos常量值PCI功能结构 PCI功能IDMSI功能电源功率管理功能 功能(capability)集 功能(capability)APIs int pcie_capability_read_wo

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

JS和jQuery获取节点的兄弟,父级,子级元素

原文转自http://blog.csdn.net/duanshuyong/article/details/7562423 先说一下JS的获取方法,其要比JQUERY的方法麻烦很多,后面以JQUERY的方法作对比。 JS的方法会比JQUERY麻烦很多,主要则是因为FF浏览器,FF浏览器会把你的换行也当最DOM元素。 <div id="test"><div></div><div></div

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python

全英文地图/天地图和谷歌瓦片地图杂交/设备分布和轨迹回放/无需翻墙离线使用

一、前言说明 随着风云局势的剧烈变化,对我们搞软件开发的人员来说,影响也是越发明显,比如之前对美对欧的软件居多,现在慢慢的变成了对大鹅和中东以及非洲的居多,这两年明显问有没有俄语或者阿拉伯语的输入法的增多,这要是放在2019年以前,一年也遇不到一个人问这种需求场景的。 地图应用这块也是,之前的应用主要在国内,现在慢慢的多了一些外国的应用场景,这就遇到一个大问题,我们平时主要开发用的都是国内的地

OpenStack离线Train版安装系列—3控制节点-Keystone认证服务组件

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版

OpenStack离线Train版安装系列—2计算节点-环境准备

本系列文章包含从OpenStack离线源制作到完成OpenStack安装的全部过程。 在本系列教程中使用的OpenStack的安装版本为第20个版本Train(简称T版本),2020年5月13日,OpenStack社区发布了第21个版本Ussuri(简称U版本)。 OpenStack部署系列文章 OpenStack Victoria版 安装部署系列教程 OpenStack Ussuri版