Linux驱动学习之设备树(设备树下的LED驱动实验),

概念

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 = ;

clocks = ;

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 /*包含file_operation结构体*/

#include /* 包含module_init module_exit */

#include /* 包含LICENSE的宏 */

#include /*包含miscdevice结构体*/

#include /*包含ioremap等操作函数*/

#include /*包含printk等操作函数*/

#include /*设备树操作相关的函数*/

/**************宏定义***************/

#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 LED21 << 29

#define LED11 << 26

#define LED_ON1

#define LED_OFF0

#define LED1_CTL5

#define LED2_CTL6

/**************内部变量***************/

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,查看现象。

文章最后发布于: 2019-10-24 17:10:57

http://www.htsjk.com/shujukunews/37966.html

www.htsjk.Com

true

http://www.htsjk.com/shujukunews/37966.html

NewsArticle

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

本站文章为和通数据库网友分享或者投稿,欢迎任何形式的转载,但请务必注明出处.

同时文章内容如有侵犯了您的权益,请联系QQ:970679559,我们会在尽快处理。

相关文章

暂无相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

  7. Linux设备与驱动学习之----什么是设备

    [ 声明:版权所有,欢迎转载,转载请注明出处,请勿用于商业用途] [ 声明:本文属于作者个人理解,如有错误,欢迎大家指正] 在学习Linux设备驱动的过程中我们用到也是看到最多的就是设备和驱动了,接下 ...

  8. 【嵌入式环境下linux内核及驱动学习笔记-(11-设备树)】

    目录 1.设备树体系 1.1 DTS /DTSI / DTC / DTB 2.基础语法 2.1 节点语法 2.1.1 通用名称建议 2.2 属性语法 2.2.1 属性值 2.3 关于label 2.4 ...

  9. Linux uart寄存器读写,Linux下读写UART串口的代码

    Linux下读写UART串口的代码,从IBM Developer network上拿来的东西,操作比較的复杂,就直接跳过了,好在代码能用,记录一下- 两个实用的函数- /** *@brief 设置串口 ...

最新文章

  1. HTML5--sessionStorage、localStorage、manifest
  2. Mesos Framework开发指南 一
  3. 洛谷 P1206 [USACO1.2]回文平方数 Palindromic Squares
  4. window.onload 和 body.onload 相互覆盖的本质
  5. Flask爱家租房--订单支付(支付过程)
  6. html boot设置列宽,html - Bootstrap 4:设置列宽固定位置内容的宽度 - SO中文参考 - www.soinside.com...
  7. python寻找1000以内的阿姆斯特朗数
  8. 微软:确实存在另一枚 print spooler 0day,目前尚未修复
  9. 三星 s9 android 9,美国V版三星S9/S9+迎来安卓9更新
  10. 彻底卸载2345系列
  11. 开发微信“自动抢红包”软件,被罚400多万
  12. Day9学习记录 2021Python面向对象基础(下)(属性和方法的私有化、Property属性、__new__方法、单例模式 、异常处理、动态添加属性和方法、__slots__属性限制 )
  13. ios控制视图切换方向
  14. 算法学习之贪心法(会议安排)
  15. ubuntu禁用guest账户
  16. 【Unity】 ios游戏开发中登陆 GameCenter的问题和脚本
  17. 人工智能实验---MNIST图像识别
  18. 文件函数python_Python 基础之文件 函数
  19. 测试java实现继承接口案例
  20. MySQL字典表的意思_数据库字典表什么意思

热门文章

  1. 如何在百度通过关键词搜索自己的网站
  2. 从ftp、tftp自动获取文件的脚本
  3. FPGA----关于延迟的用法
  4. 黑人抬棺用计算机演奏的乐谱,原神乐谱黑人抬棺怎么演奏_乐谱黑人抬棺_3DM手游...
  5. 网络客户/服务器程序
  6. 《Mysql是怎样运行的》读书笔记之成本的优化
  7. 各类会议分析(Conference、workshop等,转载)
  8. Java面试大全(2020年版)101-200
  9. 应届生面试紧张试试这几个方法
  10. 临时牙冠为何选择用3D打印来制作?