概念

Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离。相当于从驱动代码分离出来的配置文件,比如串口的波特率通过设备树配置,当需要改变波特率时,就不用修改驱动,直接修改配置文件则可。
设备树源文件扩展名为.dts(device tree source),一般放置在内核的"arch/arm/boot/dts/"目录内。设备树源文件的通用部分用.dtsi文件描述,一般用于描述SOC的内部外设信息,如CPU架构,主频等。差异部分用.dts文件描述,一般用于描述设备上的其它设备,如IIC设备,SPI设备。

dts基本语法

设备节点:dts文件中描述一个设备信息的内容。比如IIC0。
根节点:设备树文件开头会有’/’就是根节点,每个设备树文件只有一个根节点,
每个节点都有一堆属性,有的可以用户自定义,有的为标准属性。
compatible:“兼容性”属性,用于将设备和驱动绑定起来,一般驱动程序都会有一个OF匹配,匹配相等,则可使用这个驱动。
module:属性也是字符串,描述模块信息,如名字什么的。
status:设备状态,可以是“okey”、“disable”,“fail”、“fail-sss”
reg:一般reg都是和地址相关的内容,起始地址和地址长度。
#address-cells:描述reg属性中的起始地址占用字长。
#size-cells:描述reg属性中的地址长度所占用的字长。
举例:

apb {compatible = "simple-bus";#address-cells = <1>; //父节点的起始地址字长1,即uart0的reg属性中,第一个字为起始地址。#size-cells = <1>;//父节点的地址长度字长为1。ranges;uart0: serial@f0024000 {//节点标签:节点名@设备地址或者寄存器首地址compatible = "atmel,at91sam9260-usart";//<厂商,驱动名>reg = <0xf0024000 0x100>;//uart0寄存器的起始地址为0xf002c000,可以在SOC的datasheet中查看到。interrupts = <16 IRQ_TYPE_LEVEL_HIGH 5>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_uart0>;clocks = <&uart0_clk>;clock-names = "usart";status = "disabled";//状态为disable};

根节点中有两个特殊节点aliases(别名)和chosen。

设备树在系统中的体现

在根文件系统中/proc/device-tree目录下,包括根节点’/’的所有属性和子节点。

在设备树存放目录arch/arm/boot/dts/中搜索model内容,可以找到对应的.dts文件入口。可以看到model和compatible的属性值完全相同。

设备树和datasheet对应

以下以调试串口打印配置为例,学习如何查看设备树和datasheet如何对应的。
① 通过原理图,可以知道调试串口连接的PB30和PB31.
② 在datasheet中,引脚功能描述,可以看到PB30和PB31功能为调试打印DBGU。

③ 在datasheet的”Memory Mapping”中,可以看到DBGU的起始地址0Xffff ee00

④ 从上一章节知道设备树的入口文件为”sama5d34ek.dts”,在“sama5d34ek.dts”文件中#include了很多dtsi文件。


⑤ 进入相应的.dtsi文件,可以找到相关dbgu的设备节点。可以看到里面描述的内容与datasheet一致。


⑥ 在系统中,也可以找到dbgu的相关信息

基于设备树驱动LED

大致可以分为三个步骤:
① 在.dts文件中创建相应的设备节点
② 编写驱动,获取设备树中的属性值
③ 使用获取的属性值初始化LED所使用的GPIO。
一.根节‘/’下创建子节点
添加内容如下:

boyee_led{#address-cells = <1>;#size-cells = <1>;compatible = "boyee-led";status = "okay";reg = <0Xfffff600 0x200>;//PIOC的基地址};

二.编译.dts生成.dtb
在内核根目录下执行make dtbs,编译生成新的.dtb。或者执行make,也会对更改过的dtbs进行重新编译。然后使用新的.dtb启动linux内核。

三.驱动编写
提取设备节点的属性,linux内核中使用device_node结构体来描述一个节点,此结构体定义在文件include/linux/of.h中。
查找节点有关的OF函数(获取设备节点属性函数都以of_开头)有5个:
of_find_node_by_name:通过节点名字查找指定的节点。
of_find_nade_by_type:通过device_type属性查找指定的节点。
of_find_compatible_node:根据device_type和compatibe两个属性查找指定的节点。
of_find_matching_node_and_match:通过of_device_id查找指定节点。
of_find_node_by_path:通过路径来查找指定的节点。

#include <linux/fs.h> /*包含file_operation结构体*/
#include <linux/init.h>/* 包含module_init module_exit */
#include <linux/module.h>/* 包含LICENSE的宏 */
#include <linux/miscdevice.h>/*包含miscdevice结构体*/
#include <linux/io.h>/*包含ioremap等操作函数*/
#include <linux/kernel.h>/*包含printk等操作函数*/
#include <linux/of.h>/*设备树操作相关的函数*//**************宏定义***************/
#define PIO_SODR    (*(volatile unsigned long *)(virt_addr +0x0030))
#define PIO_CODR    (*(volatile unsigned long *)(virt_addr +0x0034))
#define PIO_PER     (*(volatile unsigned long *)(virt_addr +0x0000))
#define PIO_MDDR    (*(volatile unsigned long *)(virt_addr +0x0054))
#define PIO_OER     (*(volatile unsigned long *)(virt_addr +0x0010))
#define PIO_OWDR    (*(volatile unsigned long *)(virt_addr +0x00A4))/*
#define PIO_PDSR    (*(volatile unsigned long *)(virt_addr +0x003C))
#define PIO_ODR     (*(volatile unsigned long *)(virt_addr +0x0014))
#define PIO_PUER    (*(volatile unsigned long *)(virt_addr +0x0064))
#define PIO_PUDR    (*(volatile unsigned long *)(virt_addr +0x0060 ))
#define PIO_PPDER   (*(volatile unsigned long *)(virt_addr +0x0094))
*/#define   LED2        1 << 29
#define     LED1        1 << 26
#define     LED_ON      1
#define     LED_OFF     0
#define     LED1_CTL    5
#define     LED2_CTL    6
/**************内部变量***************/
unsigned long virt_addr;/* 定义一个打开设备的,open函数 */
static int led_open(struct inode *inode,struct file *file)
{return 0;
}/* 定义一个打开设备的,ioctl函数 */
static long led_ioctl(struct file *file,unsigned int data,unsigned long arg)
{switch(data){case LED1_CTL:if(arg == LED_ON){PIO_SODR |= LED1;/*对芯片寄存器IO操作*/}else{PIO_CODR |= LED1;}break;case LED2_CTL:if(arg == LED_ON){PIO_SODR |= LED2;}else{PIO_CODR |= LED2;}break;default:break;}return 0;
}
/*字符设备驱动程序就是为具体硬件的file_operations结构编写各个函数*/
static const struct file_operations led_ctl={.owner          = THIS_MODULE,.unlocked_ioctl = led_ioctl,.open           = led_open,
};/*杂项设备,主设备号为10的字符设备,相对普通字符设备,使用更简单*/
static struct miscdevice led_miscdev = {.minor          = 255,.name           = "led_ctl",.fops           = &led_ctl,
};static int __init led_init(void)
{int res;struct device_node *led_nd;//设备节点struct property *proper;unsigned int regdata[2];char str[30];/*获取设备树中的属性数据*//*1.获取设备节点:boyee_led*/led_nd = of_find_node_by_path("/boyee_led");if(led_nd == NULL){printk("boyee_led node not find\r\n");}else{printk("boyee_led node find\r\n");}/*2.获取compatible属性内容*/proper =  of_find_property(led_nd,"compatible",NULL);if(proper == NULL){printk("compatible property find failed\r\n");}else{printk("compatible =%s\r\n",(char *)proper->value);}/*3.获取status属性内容*/res = of_property_read_string(led_nd,"status",&str);if(res < 0){printk("status read failed\r\n");}else{printk("status =%s\r\n",str);}/*4.获取reg属性内容*/res = of_property_read_u32_array(led_nd,"reg",regdata,2);if(res <0 ){printk("reg property read failed\r\n");}else{printk("regdata[0]=%x\r\n",regdata[0]);printk("regdata[1]=%x\r\n",regdata[1]);}/*注册杂项设备驱动*/res = misc_register(&led_miscdev);printk(KERN_ALERT"led_init %d\n",res);/*通过物理地址,得到寄存器的虚拟地址*/virt_addr =(volatile unsigned long )ioremap(regdata[0],regdata[1]); /*对芯片寄存器操作,输出IO使能*/PIO_PER  |= LED1 | LED2;PIO_MDDR |= LED1 | LED2;PIO_OER  |= LED1 | LED2;PIO_OWDR |= LED1 | LED2;PIO_CODR |= LED1 | LED2;return res;
}static void __exit led_exit(void)
{/*释放杂项设备*/misc_deregister(&led_miscdev);/*取消虚拟地址映射*/iounmap((unsigned long *)virt_addr);printk(KERN_ALERT"led_exit\r\n");
}/*驱动模块的加载和卸载入口*/
module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("boyee");
MODULE_DESCRIPTION("control output led");

四.编译测试
编译驱动生成xx.ko,insmod驱动,编写测试APP、Makefile,运行测试APP,查看现象。

Linux驱动之设备树(设备树下的LED驱动实验)相关推荐

  1. 【正点原子Linux连载】第四十四章 设备树下的LED驱动实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  2. linux uart寄存器 代替 printk,Linux驱动学习之设备树(设备树下的LED驱动实验),...

    Linux驱动学习之设备树(设备树下的LED驱动实验), 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.相当于从驱动代码分离出来的配置文件,比如串口的波特率通过设 ...

  3. 【正点原子MP157连载】第二十四章 设备树下的LED驱动实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  4. firefly-rk3288j开发板--设备树下的 LED 驱动

    firefly-rk3288j开发板–设备树下的 LED 驱动 1 准备工作 开发板:aio-rk3288j SDK版本:rk3288_linux_release_20210304 下载工具:Linu ...

  5. STM32MP157驱动开发——设备树下的LED驱动

    STM32MP157驱动开发--设备树下的LED驱动 主要内容:将之前章节中使用新设备设备驱动编写的LED驱动改成设备树形式 文章目录 STM32MP157驱动开发--设备树下的LED驱动 一.主要步 ...

  6. <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的LED驱动

    <Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的LED驱动 交叉编译环境搭建: <Linux开发> linux开发工具-之-交叉编译环境搭建 uboot移 ...

  7. 韦东山 IMX6ULL和正点原子_「正点原子Linux连载」第四十四章设备树下的LED驱动实验...

    1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南> 关注官方微信号公众号,获取更多资料:正点原子 上一章我们详细的讲解了设备树语法以及在驱 ...

  8. I.MX6ULL ARM驱动开发---设备树下的LED驱动实验

    一.什么是设备树?   设备树(Device Tree),将这个词分开就是"设备"和"树",描述设备树的文件叫做 DTS(Device Tree Source) ...

  9. linux显卡驱动安全模式,Win7怎么在安全模式下安装显卡驱动?

    什么是显卡驱动?它是一种硬件所对应的软件,支持计算机与设备之间的通信,没有驱动程序,计算机的硬件就无法工作.下面我们就Win7系统下安装显卡驱动的一个案例与大家详细地分析一下. 案例分析: 最近安装了 ...

  10. 驱动技巧:如何在Win7下安装SATA驱动开启AHCI模式

    问题描述:装win7的时候没有在AHCI模式下安装,而是在IDE模式下安装的,后来安装完毕以后想更改成AHCI模式,可是更改以后启动电脑蓝屏并重启. 解决方法: 如果是在IDE模式下安装的系统,由于在 ...

最新文章

  1. mesos+marathon平台搭建
  2. 【直播回放】中外大厂奇葩说:谁是技术圈的嘴炮王者?
  3. Linux环境变量中PS1
  4. java几点钟_实现 Java 本地缓存,该从这几点开始
  5. python 控件叠加_Python3 tkinter基础 Checkbutton anchor for生成多个控件并西对齐
  6. 快速迭代的开发方式中的QA实践方法
  7. html定义不同的类,定义不同的节点类型.html
  8. 时间复杂度o(n^0.5)_算法基础1.1:算法复杂度计算(二)
  9. ffmpeg屏幕推流
  10. Vue 之 下载本地资源文件
  11. 病毒周报(081208至081214)
  12. select用法详解
  13. 现在润新加坡是个好主意吗?
  14. 设计模式之策略模式(Strategy)
  15. 爱普生荣膺第十届制博会机器人类唯一奖项
  16. [1]: the default discovery settings are unsuitable for production use; at least one of [discovery.se
  17. 2022年在中国大陆通过Azure的学生认证方法指北
  18. 2021江西高考成绩查询入口已开通,2021年江西省高考成绩查询系统入口【官网】...
  19. 微信小程序input弹出键盘挡住文字的解决办法
  20. 计算机组装与维护课程课程介绍,有关计算机组装与维护课程的教学改革与实践...

热门文章

  1. 14. Zigbee应用程序框架开发指南 - 睡眠设备
  2. VScode中使用platformIO开发,编译时找不到自己的源文件(报错信息:undefined reference to )
  3. DEVC++安装后编程运行时老是提示“源文件未编译”
  4. 最新最全的前端面试题集锦之 微信小程序 篇(从基础到高级)
  5. python语言的开题报告怎么写_开题报告怎么写
  6. 2022国开中国现代文学专题阶段作业2-4答案
  7. Android 多语言对照表
  8. Android 自动朗读TT
  9. C语言 --- sizeof() 7种使用详解
  10. 10年老司机倾囊相授,贴片晶振的PCB layout需要注意哪些?