I.MX6ULL内核开发10:设备树
目录
一、设备树简介
二、设备树源码
三、获取设备树信息
1、增加设备节点
2、内核编译设备树
3、替换设备树文件
4、查看设备树节点
5、在驱动中获取节点的属性
6、编译驱动模块
7、加载模块
一、设备树简介
设备树的作用是描述一个硬件平台的硬件资源。这个“设备树”可以被bootloader(uboot)传递到内核,内核可以从设备树中获取硬件信息。
几个常见的文档缩写符号:
- DTS:是指.dts格式的文件,是一种ASII文本格式的设备树描述,设备树源码,一般一个.dts文件对应一个硬件平台。
- DTC:是指编译设备树源码的工具,一般情况下需要手动安装。
- DTB:是设备树源码编译生成的文件,类似于C语言中的“.bin”文件,可以被硬件识别。
二、设备树源码
文件定位:内核源码/arch/arm/boot/dts/imx6ull-mmc-npi.dts
/*----------------------头文件--------------------------*/
#include <dt-bindings/input/input.h>
#include "imx6ull.dtsi"/*----------------------中间部分--------------------------*// {model = "Embedfire i.MX6ULL Board";compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";aliases {pwm0 = &pwm1;pwm1 = &pwm2;pwm2 = &pwm3;pwm3 = &pwm4;};chosen {stdout-path = &uart1;};memory {reg = <0x80000000 0x20000000>;};reserved-memory {#address-cells = <1>;#size-cells = <1>;ranges;linux,cma {compatible = "shared-dma-pool";reusable;size = <0x14000000>;linux,cma-default;};};/*-------------以下内容省略--------------------*/
};
/*------------------追加部分--------------------------*/
&cpu0 {/*dc-supply = <®_gpio_dvfs>;*/clock-frequency = <800000000>;
};&clks {assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;assigned-clock-rates = <786432000>;
};/*------------------以下内容省略--------------------------*/
文件位置:内核源码/arch/arm/boot/dts/imx6ull.dtsi
cpus {#address-cells = <1>;#size-cells = <0>;cpu0: cpu@0 {compatible = "arm,cortex-a7";device_type = "cpu";/*----------以下内容省略-----------------*/};};
设备树源码分为3部分:
- 第1-2行:头文件。头文件的引用有两种,一种为“.h”文件,一种为“.dtsi文件”。imx6ull.dtsi由NXP官方提供,是一个imx6ull平台“共用”的设备树文件。
- 中间部分:设备树节点。由{}组成,每一个设备树都只有一个“/”节点。
- 追加部分:&的意思是像原有的节点中追加内容。
三、获取设备树信息
1、增加设备节点
在ebf_linux_kernel/arch/arm/boot/dts/imx6ull-mmc-npi.dts这个设备树中,尝试增加一个新的设备节点。
led_test{#address-cells = <1>;#size-cells = <1>;rgb_led_red@0x0209C000{compatible = "fire,rgb_led_red";reg = <0x0209C000 0x00000020>;status = "okay";};
};
- 以上节点中,#address-cells = <1>,#size-cells = <1>,意味着它的子节点的reg属性里的数据是“地址”、“长度”交替的。
- 第二部分led的子节点,定了三种属性,分别为compatible、reg、status。由于在父节点设置了#address-cells = <1>,#size-cells = <1>,所以0x0209C000表示的是地址(这里填写的GPIO1控制寄存器的首地址),0x00000020表示的是地址长度。
2、内核编译设备树
编译内核时会自自动编译设备树,到那时编译内核非常耗时,所以可以用以下命令只编译设备树。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- npi_v7_defconfig
make ARCH=arm -j4 CROSS_COMPILE=arm-linux-gnueabihf- dtbs
执行结果如下:
编译成功后生成的设备树文件(.dtb)位于源码目录下/arch/arm/boot/dts/,文件名为“imx6ull-mmc-npi.dtb”
3、替换设备树文件
将上位机上生成的.dtb文件替换掉开发板中的.dtb文件,替换/usr/lib/linux-image-4.19.35-imx6/imx6ull-mmc-npi.dtb。
uboot在启动的时候负责将该目录的设备我呢见加载到内存,供内核使用。
4、查看设备树节点
设备树的设备节点在文件系统中有与之相对应的文件,位于/proc/device-tree目录,进入目录查看如下:
接着进入led_test文件夹,可以发现led_test节点中定义的属性以及它的子节点,如下所示。
在节点属性中多了一个name,我们在led节点中并没有定义name属性,这是自己生成的,保存节点名。
这里的属性是一个文件,而子系欸但是一个文件夹,再次进入“rgb_led_red@0x0209C000”文件夹。里面有compatible name regs status四个属性文件。我们可以使用“cat”命令查看这些属性文件,如下所示:
至此,成功的在设备树中添加了一个名为“led_test”的节点。
5、在驱动中获取节点的属性
实验是一个简化的字符设备驱动,在驱动中没有实际操作硬件,仅在.open函数中调用of函数获取设备树节点中的属性,获取成功后打印获取到的内容。
代码:get_dts_info.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/io.h>#include <linux/of.h>
#include <linux/of_address.h>#define DEV_NAME "get_dts_info"
#define DEV_CNT (1)
//定义字符设备的设备号
static dev_t led_devno;
//定义字符设备结构体chr_dev
static struct cdev led_chr_dev;
//创建类
struct class *led_chrdev_class;struct device_node *led_device_node; //led的设备树节点
struct device_node *rgb_led_red_device_node; //rgb_led_red 红灯节点
struct property *rgb_led_red_property; //定义属性结构体指针
int size = 0 ;
unsigned int out_values[18]; //保存读取得到的REG 属性值/*.open 函数*/
static int led_chr_dev_open(struct inode *inode, struct file *filp)
{int error_status = -1;printk("\n open form device \n");/*获取DTS属性信息*/led_device_node = of_find_node_by_path("/led_test");if(led_device_node == NULL){printk(KERN_ALERT "\n get led_device_node failed ! \n");return -1;}/*根据 led_device_node 设备节点结构体输出节点的基本信息*/printk(KERN_ALERT "name: %s",led_device_node->name); //输出节点名printk(KERN_ALERT "child name: %s",led_device_node->child->name); //输出子节点的节点名/*获取 rgb_led_red_device_node 的子节点*/ rgb_led_red_device_node = of_get_next_child(led_device_node,NULL); if(rgb_led_red_device_node == NULL){printk(KERN_ALERT "\n get rgb_led_red_device_node failed ! \n");return -1;}printk(KERN_ALERT "name: %s",rgb_led_red_device_node->name); //输出节点名printk(KERN_ALERT "parent name: %s",rgb_led_red_device_node->parent->name); //输出父节点的节点名/*获取 rgb_led_red_device_node 节点 的"compatible" 属性 */ rgb_led_red_property = of_find_property(rgb_led_red_device_node,"compatible",&size);if(rgb_led_red_property == NULL){printk(KERN_ALERT "\n get rgb_led_red_property failed ! \n");return -1;}printk(KERN_ALERT "size = : %d",size); //实际读取得到的长度printk(KERN_ALERT "name: %s",rgb_led_red_property->name); //输出属性名printk(KERN_ALERT "length: %d",rgb_led_red_property->length); //输出属性长度printk(KERN_ALERT "value : %s",(char*)rgb_led_red_property->value); //属性值/*获取 reg 地址属性*/error_status = of_property_read_u32_array(rgb_led_red_device_node,"reg",out_values, 2);if(error_status != 0){printk(KERN_ALERT "\n get out_values failed ! \n");return -1;}printk(KERN_ALERT"0x%08X ", out_values[0]);printk(KERN_ALERT"0x%08X ", out_values[1]);return 0;
}/*.release 函数*/
static int led_chr_dev_release(struct inode *inode, struct file *filp)
{printk("\nrelease\n");return 0;
}/*字符设备操作函数集*/
static struct file_operations led_chr_dev_fops =
{.owner = THIS_MODULE,.open = led_chr_dev_open,.release = led_chr_dev_release,
};/*
*驱动初始化函数
*/
static int __init led_chrdev_init(void)
{int ret = 0;printk("led chrdev init\n");//第一步//采用动态分配的方式,获取设备编号,次设备号为0,//设备名称为EmbedCharDev,可通过命令cat /proc/devices查看//DEV_CNT为1,当前只申请一个设备编号ret = alloc_chrdev_region(&led_devno, 0, DEV_CNT, DEV_NAME);if(ret < 0){printk("fail to alloc led_devno\n");goto alloc_err;}led_chrdev_class = class_create(THIS_MODULE, "led_chrdev");//第二步//关联字符设备结构体cdev与文件操作结构体file_operationscdev_init(&led_chr_dev, &led_chr_dev_fops);//第三步//添加设备至cdev_map散列表中ret = cdev_add(&led_chr_dev, led_devno, DEV_CNT);if(ret < 0){printk("fail to add cdev\n");goto add_err;}//创建设备device_create(led_chrdev_class, NULL, led_devno, NULL,DEV_NAME);return 0;add_err://添加设备失败时,需要注销设备号unregister_chrdev_region(led_devno, DEV_CNT);
alloc_err:return ret;
}/*
*驱动注销函数
*/
static void __exit led_chrdev_exit(void)
{printk("chrdev exit\n");device_destroy(led_chrdev_class, led_devno); //清除设备cdev_del(&led_chr_dev); //清除设备号unregister_chrdev_region(led_devno, DEV_CNT); //取消注册字符设备class_destroy(led_chrdev_class); //清除类
}module_init(led_chrdev_init);
module_exit(led_chrdev_exit);MODULE_LICENSE("GPL");
- 使用“of_find_node_by_path”函数勋章“led_test”设备节点。参数是“led_test”的设备节点路径。
- 获取成功后得到的是一个device_node类型的结构体指针,然后就可以从这个结构体中获得想要的数据。获取完整的属性可能还需要使用其他of函数。
- 获取rgb_led_red_device_node的子节点,在上一部分中获取的“led”节点的“设备节点结构体”,这里就可以使用“of_get_next_child”函数获取它的子节点。也可以从“led”节点的“设备节点结构体”中直接读取它的第一个子节点。
- 使用“of_find_property”函数获取“rgb_led_red”节点的“compatiable”属性
- 使用“of_property_read_u32_array”函数获取reg属性
6、编译驱动模块
命令:make
生成get_dts_info.ko驱动模块
7、加载模块
将ko文件拷贝到开发板,使用insmod安装模块然后可以在/dev/目录找到get_dts_info
向模块中随便输入一个字符
sudo sh -c "echo '1' >> /dev/get_dts_info"
可以看出已经成功打印出led节点属性和rgb_led_red字节点属性。
相关文章:

I.MX6ULL内核开发10:设备树
目录 一、设备树简介 二、设备树源码 三、获取设备树信息 1、增加设备节点 2、内核编译设备树 3、替换设备树文件 4、查看设备树节点 5、在驱动中获取节点的属性 6、编译驱动模块 7、加载模块 一、设备树简介 设备树的作用是描述一个硬件平台的硬件资源。这个“设备树…...

【大数据】记一次hadoop集群missing block问题排查和数据恢复
问题描述 集群环境总共有2个NN节点,3个JN节点,40个DN节点,基于hadoop-3.3.1的版本。集群采用的双副本,未使用ec纠删码。 问题如下: bin/hdfs fsck -list-corruptfileblocks / The list of corrupt files under path…...

国产音质好的蓝牙耳机有哪些?国产音质最好的耳机排行
随着时间的推移,真无线蓝牙耳机逐渐占据耳机市场的份额,成为人们日常生活中必备的数码产品之一。蓝牙耳机品牌也多得数不胜数,哪些国产蓝牙耳机音质好?下面,我们从音质出来,来给大家介绍几款国产蓝牙耳机&a…...

CTFer成长之路之XSS的魔力
XSS的魔力CTF XSS闯关 题目描述: 你能否过关斩将解决所有XSS问题最终获得flag呢? docker-compose.yml version: "3.2"services:xss:image: registry.cn-hangzhou.aliyuncs.com/n1book/web-xss:latestports:- 3000:3000启动方式 docker-compose up -…...

行锁、表锁、主键外键、表之间的关联关系
Java知识点总结:想看的可以从这里进入 目录2.4、行锁、表锁2.5、主键、外键2.5.1、主键2.5.2、外键2.6、表的关联关系2.4、行锁、表锁 MyISAM默认采用表级锁,InnoDB默认采用行级锁。 表锁:开销小,加锁快,不会出现死锁…...

JavaScript 进阶(面试必备)--charater4
文章目录前言一、深浅拷贝:one: 浅拷贝:two:深拷贝二、异常处理:one: throw 抛异常:two: try /catch 捕获异常:three:debugger三、处理thisthis指向 :one:普通函数this指向this指向 :two: 箭头函数this指向3.2 改变this:one: call():two: apply():three: bind()四、性能优化:on…...

ARM+FPGA架构开发板PCIE2SCREEN示例分析与测试-米尔MYD-JX8MMA7
本篇测评由电子发烧友的优秀测评者“zealsoft”提供。 本次测试内容为米尔MYD-JX8MMA7开发板其ARM端的测试例程pcie2screen并介绍一下FPGA端程序的修改。 01. 测试例程pcie2screen 例程pcie2screen是配合MYD-JX8MMA7开发板所带的MYIR_PCIE_5T_CMOS 工程的测试例&#…...

51单片机入门 - SDCC / Keil_C51 会让没有调用的函数参与编译吗?
Small Device C Compiler(SDCC)是一款免费 C 编译器,适用于 8 位微控制器。 不想看测试过程的话可以直接划到最下面看结论:) 关于软硬件环境的信息: Windows 10STC89C52RCSDCC (构建HEX文件&…...

OpenCV只含基本图像模块编译
编译OpenCV4.5.5只含基本图像模块,环境为Windows10 x64CMake3.23.3VS2019。默认编译选项编译得到的OpenCV库往往大几百MB甚至上GB,本文配置下编译得到的库压缩后得到的zip包大小仅6.25MB,适合使用OpenCV基本图像功能模块的项目移植而不牵涉其…...

Java实现阴历日历表(附带星座)
准备工作 1.无敌外挂(GitHub直达源码) Nobb 直击灵魂 https://github.com/xuyishanBD/Java_create_calendar.git2.maven配置(如果没有走上面的捷径) <dependencies><dependency><groupId>net.sourceforge.javacsv</groupId><artifactId>javac…...

Python入门之最基础
Python入门之最基础 IDLE有两种模式,一种是交互模式,通俗讲就是写一个代码,会得到相应的反馈,另一种为编辑模式. 注意事项: 标点符号一定要用英文符号 要注意缩进 dir(builtins)可以看到python所有的内置函数&#…...

浏览器缓存策略
先走强缓存,再走协商缓存 强缓存 不发送请求,直接使用缓存的内容 状态码200 当前会话没有关闭的话就是走memory cache,否则就是disk cache 由响应头的 Pragma(逐渐废弃,优先级最高),catch-…...

高清无码的MP4如何采集?python带你保存~
前言 大家早好、午好、晚好吖 ❤ ~ 又是我,我又来采集小姐姐啦~ 这次我们采集的网站是(看下图): 本文所有模块\环境\源码\教程皆可点击文章下方名片获取此处跳转 话不多少,我们赶快开始吧~ 第三方模块: requests >>> pip install requests 如果安装python第三方模块…...

python+pytest接口自动化(1)-接口测试基础
接口定义一般我们所说的接口即API,那什么又是API呢,百度给的定义如下:API(Application Programming Interface,应用程序接口)是一些预先定义的接口(如函数、HTTP接口),或…...

go单元测试
接着上一篇中的go module创建项目calc为例,在simplemath包中,是使用在命令行中使用交互式的方式进行测试,现在可以为这几个函数实现单元测试, go test,这个测试工具来自于 Go 官方的 gc 工具链。 运行 go test 命令将执…...

Mybatis之一级缓存二级缓存
介绍 缓存,就是将经常访问的数据,放到内存中,减少对数据库的访问,提高查询速度。Mybatis中也有缓存的概念,分为一级缓存和二级缓存。 一级缓存 一级缓存是Mybatis中SqlSession对象的缓存。当我们执行查询以后&#x…...

人脸考勤机项目
文章内容如下: 1)项目简介 2)开发环境和使用的技术知识 3)功能实现 4)项目源码 一。项目简介 此项目是基于HOG和Dlib开发的一套实时无感考勤系统。首先是待考勤人员的个人信息录入。然后在过道或者入口处装置人脸…...

Python编程自动化办公案例(3)
作者简介:一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页 目录 前言 一.前几章代码 1.获取到第一题的选项单元格 2.实现批量获取文件 二. 批…...

Linux-MYSQL 登录数据库(命令行,图形化) 及 远程登录
命令行登录 :mysql 命令登录数据库语法 : mysql -u用户名 -p密码 -h 连接的数据库服务器的ip [-D] 数据库名 -p 端口注 : 上面的 mysql 命令是指的是 客户端的指令 ~!!-h : 指的就是 连接数据库服务器的 ip…...

electron网络环境在线/离线事件探测
electron判断网络环境问题,可以说在任何桌面应用都可以使用到,处理方式有很多种,我介绍几种办法第一种HTML5 API navigator.onLine:官方案例给的,这边为直接贴出地址了,有兴趣的同学可自行查看https://www.…...

UE 项目导航数据生成配置
WP构建及常规构建操作WP构建方式 :https://docs.unrealengine.com/5.0/zh-CN/world-partitioned-navigation-mesh/常规构建方式针对WP的构建方式特殊配置项关闭就好:取消勾选RecastNavMesh-XXX下的IsWorldPartitioned执行n.bNavMeshAllowPartitionedBuil…...

494.目标和
1. 回溯算法 这题和之前做的那些排列、组合的回溯稍微有些不同,你不需要每次选数据时都是for遍历去选择,很明显这是顺序选择的 比如 数组[0,1],target1; 递归数组,每个元素都 或者 - ,然后取最后结果为0…...

滑台模组的应用有哪些?
在自动化生产中,我们常常会看到滑台模组的身影,那么,滑台模组究竟在自动化生产设备中起着怎样的作用呢? 简单点说,滑台模组由滑块、滚珠丝杆、导轨、主体等其它传动零件组成的自动化晋级单元,经过各单元的组…...

CS224W课程学习笔记(四):node2vec算法原理与说明
引言 什么是图嵌入? 我想从上节的deepwalk中已经有一个十分完整的轮廓了,这里引出deepwalk论文中的一张很形象的图(当然,上节的一些实战演练,也将这种嵌入关系进行了模拟与可视化,前文为:&…...

扩展lucas定理
前置知识: lucas定理中国剩余定理 介绍 当正整数n,mn,mn,m很大,且质数ppp较小的时候,要求CnmC_n^mCnm对ppp取模后的值,可以用lucas定理。 但如果ppp不是质数,那该怎么办呢?如果mmm较小,则…...

医疗影像工具LEADTOOLS 入门教程: 从 PDF 中提取附件 - 控制台 C#
LEADTOOLS 是一个综合工具包的集合,用于将识别、文档、医疗、成像和多媒体技术整合到桌面、服务器、平板电脑、网络和移动解决方案中,是一项企业级文档自动化解决方案,有捕捉,OCR,OMR,表单识别和处理&#…...

【LVGL】学习笔记--(1)Keil中嵌入式系统移植LVGL
一 LVGL简介最近emwin用的比较烦躁,同时被LVGL酷炫的界面吸引到了,所以准备换用LVGL试试水。LVGL(轻量级和通用图形库)是一个免费和开源的图形库,它提供了创建嵌入式GUI所需的一切,具有易于使用的图形元素,美丽的视觉效…...

Transformer学习笔记
Transformer学习笔记1. 参考2. 模型图3.encoder部分3.1 Positional Encoding3.2 Muti-Head Attention3.3 ADD--残差连接3.4 Norm标准化3.5 单个Transformer Encoder流程图4.decoder部分4.1 mask Muti-Head Attention4.2 Muti-Head Attention5 多个Transformer Encoder和多个Tra…...

vue-cli引入wangEditor、Element,封装可上传附件的富文本编辑器组件(附源代码直接应用,菜单可调整)
关于Element安装引入,请参考我的另一篇文章:vue-cli引入Element Plus(element-ui),修改主题变量,定义全局样式_shawxlee的博客-CSDN博客_chalk variables 1、安装wangeditor npm i wangeditor --savewangE…...

移动办公时代,数智化平台如何赋能企业管理升级?
在传统的办公模式下,企业组织办公不仅时效低,周期长、成本高,且各办公系统相互独立。随着社会经济的发展,人们的工作生活变得多样化,对于办公的需求也越来越多,存在明显弊端的传统办公模式已不能满足企业对…...