树莓派4B采用设备树(DTS)提供硬件信息,编写platform驱动控制io(LED)

这篇具有很好参考价值的文章主要介绍了树莓派4B采用设备树(DTS)提供硬件信息,编写platform驱动控制io(LED)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.设备树

1.1设备树定义

设备树是一种描述硬件资源的数据结构,它通过bootloader将硬件资源传给内核,使得内核和硬件资源描述相对独立。

1.2 常用名词解释

<1>DT:Device Tree //设备树
<2>FDT:Flattened Device Tree //展开设备树|开放固件,设备树起源于OF,所以我们在设备树中可以看到很多有of字母的函数
<3>device tree source(dts) //设备树代码
<4>device tree source include(dtsi)//更通用的设备树代码,也就是相同芯片但不同平台都可以使用的代码
<5>device tree blob(dtb)//DTS编译后得到的DTB文件
<6>device tree compiler(dtc)//设备树编译器

1.3设备树基本框架

<1>设备树从根节点开始,每个设备都是一个节点。
<2>节点和节点之间可以互相嵌套,形成父子关系。
<3>设备的属性用key-value对(键值对)来描述,每个属性用分号结束

1.4设备树语法

1.4.1节点

节点就好比一颗大树,从树的主干开始,然后有一节一节的树枝。根节点就相当于大树的树干

/{
};

树枝就相当于设备树的子节点

/{		//根节点
		node1//子节点node1
		{
		};
		node2//子节点2
		{
		};
};//分号

树枝上的树枝就相当于设备树上的子子节点

/{ 		//根节点
		node1//子节点node1
		{
			child-node1//子子节点
			{
			};
		};
		node2//子节点node2
		{
		};
}

1.4.2节点名称

节点的命名有一个固定的格式

格式:<名称>[@<设备地址>]
<名称>节点的名称不是任意起的,一般要体现设备的类型,比如网口,应该命名为ethernet,
<设备地址>用来访问该设备的基地址。但并不是说在操作过程中来描述一个地址,他主要用来区分用。

注意事项:
<1>同一级的节点只要地址不一样,名字是可以不唯一的。
<2>设备地址是一个可选选项,可以不写。但为了容易区分和理解,一般是都写的。

1.4.3节点别名

给一个节点取小名,相当于 typedef unsigned int uint;
节点别名格式
节点名称别名:节点名称
例:

uart8:serial@02288000

uart8就是这个节点名称的别名,serial@02288000就是节点名称。

1.4.4节点引用

一般往一个节点里面添加内容的时候,不会直接把添加的内容写到节点里面,而是通过节点的引用来添加。
例:

&uart8{
			pinctrl-names = "default";
			pinctrl-0 = <&pinctrl_uart8>;
			status = "okay";
}

&uart8表示引用节点别名为uart8的节点,并往这个节点添加{}里面的内容。
注意事项
编译设备树的时候,相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写,使用引用可以避免移植者四处找节点。如dts和dtsi里面都有根节点,但最终会合并成一个根节点。

1.4.5属性

(1) reg属性
reg属性用来描述一个设备的地址范围。
格式:

reg=<add1 length1 [add2 length2]....>

例子:

serial@02288000{
					reg = <101F2000 0x1000>;
			};

其中101F2000就是起始地址,0x1000就是长度。
(2) #address-cells 和 #size-cells属性
#address-cells用来设置子节点中reg地址的数量
#size-cells 用来设置子节点中reg地址长度的数量。
举例:

cpu{
		#address-cells = <1>;
		#size-cells = <1>;
		serial@101F2000{
				compatible = "serial";
				reg = <0x101F2000 0x1000 
							0x101f3000  0x0010>;
			};
};

其中#address-cells 和#size-cells均为1,也就是说我们子节点里面的reg属性里这个寄存器组的起始地址只有一个,长度也只有一个。所以分配了2个地址范围,第一个101F2000是起始地址,0x1000是长度。第二个0x101f3000是起始地址,0x0010是长度
(3) compatible 属性
compatible 是一个字符串列表,可以在代码中进行匹配。
举例:

compatible = "led"

这个就相当于platform总线下的device.c里面编写进行匹配的属性。
(4) status 属性
status 属性的值类型是字符串,常用的一个是okay,表示设备可以正常使用,一个是disable,表示设备不能正常使用。

1.5在设备树中添加自定义节点

1.5.1节点查看

方法1

cd /proc/device-tree/
ls
//查看设备树的model、compatible
cat model
cat compatible 

方法二

cd /sys/firmware/devicetree/base/
ls

1.5.2在设备树中添加自定义节点

根目录位于/home/kun/build_new/linux_kernel/arch/arm/boot/dts
/home/kun/build_new是我存放linux内核的路径
打开bcm2711-rpi-4-b.dts
找到根节点,在根节点末尾添加节点
树莓派 设备树,linux,linux,驱动开发
节点代码如下

test1:test@0xfe200000{
		#address-cells = <1>;
		#size-cells = <1>;

		compatible = "test";

		reg = <0xfe200000 0x00000004>;
		status = "okay";
	};

树莓派 设备树,linux,linux,驱动开发

1.5.3 编译节点

在内核目录下执行指令
注:我是64位,所以ARCH=arm64,32位的话,ARCH=arm32,然后编译器我是给他重命名为了aarch64-linux-gnu- 这个编译器为编译内核时使用的编译器

make  -j5 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs

树莓派 设备树,linux,linux,驱动开发
编译后会给出修改后的bcm2711-rpi-4-b.dtb文件位置
(/home/kun/build_new/linux_kernel/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dts)

1.5.4运行编译生成的bcm2711-4-b.dtb

将编译生成的bcm2711-rpi-4-b.dtb拷贝到树莓派的/boot目录下
然后reboot即可。

1.5.5 查看节点是否创建成功

具体指令如下

cd /proc/device-tree
ls
cd test@0xfe200000/
ls
cat name
cat status

树莓派 设备树,linux,linux,驱动开发

2.bcm2711-rpi-4-b.dts文件修改内容

在根节点下增加以下内容
树莓派 设备树,linux,linux,驱动开发

gpio4:gpio4@0xfe200000{
		#address-cells = <1>;
		#size-cells = <1>;

		compatible = "test";
		reg = <0xfe200000 0x00000004
			   0xfe20001c 0x00000004
			   0xfe200028 0x00000004>;
		status = "okay";
	};

3编写driver.c

#include <linux/init.h>  
#include <linux/module.h> 
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h> //注册杂项设备头文件
#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>

unsigned int *vir_gpio4_dr=NULL;
unsigned int *vir_gpio4_h=NULL;
unsigned int *vir_gpio4_l=NULL;

u32 out_values[6]; //用于存储从设备树获取的reg数据

struct resource *gpio4_dir;
struct resource *gpio4_h;
struct resource *gpio4_l;


const struct of_device_id of_match_table_test[] = {
	{ .compatible = "test_led"},
	{}

};

ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
	char kbuf[64] = {0};
	if ( copy_from_user( kbuf, ubuf, size) != 0)
	{
		printk( "copy_from_user error\n ");
		return -1;
	}
	printk( "kbuf is %s\n ", kbuf);
	*vir_gpio4_dr |= (001<<(3*4));
	if( kbuf[0] == 1)
	{
		
		*vir_gpio4_h |=(1<<4);
	}
	else if( kbuf[0]==0)
	{
		*vir_gpio4_l |=(1<<4);
	}
	return 0;
}

int misc_release( struct inode *inode, struct file *file)
{
	printk( "hello misc_relaease bye bye \n ");
	return 0;
}

int misc_open( struct inode *inode, struct file *file)
{
	printk( "hello misc_open\n ");
	return 0;
}
//文件操作集
struct file_operations misc_fops = {
		.owner = THIS_MODULE, 
		.open = misc_open,
		.release = misc_release,
		.write = misc_write,
		};
//miscdevice 结构体
struct miscdevice misc_dev = {
	.minor = MISC_DYNAMIC_MINOR, 
	.name = "hello_misc",
	.fops = &misc_fops,
};


int led_probe( struct platform_device *pdev)
{
	//5匹配成功后进入probe函数
	int ret;

	printk( "led_probe\n");

	//注册杂项设备
	ret = misc_register( &misc_dev); 
	if (ret < 0)
	{
		printk( "misc registe is error \n");
	}
	printk( "misc registe is succeed \n");

	//获取设备树里面reg属性的值
	
	ret = of_property_read_u32_array( pdev->dev.of_node, "reg", out_values, 6);
	
	if( ret<0){
		printk("of_property_read_u32_array is error \n");
		return -1;
	}

	//对物理地址进行虚拟映射
	
	vir_gpio4_dr = ioremap( out_values[0],out_values[1]);
	if( vir_gpio4_dr== NULL )
	{
		printk( "gpio4dr ioremap error\n");
		return EBUSY;
	}
	
	vir_gpio4_h = ioremap( out_values[2],out_values[3]);
	if( vir_gpio4_h== NULL)
	{
		printk( "gpio4h ioremap error\n");
		return EBUSY;
	}

	vir_gpio4_l = ioremap( out_values[4],out_values[5]);
	if( vir_gpio4_l == NULL)
	{
		printk( "gpio4l ioremap error\n");
		return EBUSY;
	}
	printk( "gpio ioremap success\n");

	return 0;

}

int led_remove( struct platform_device *pdev)
{
	printk("led_remove\n");
	return 0;
}
struct platform_driver led_driver ={   
	//3.在led_driver结构体中完成了led_probe和led_remove

	.probe = led_probe,
	.remove = led_remove,

	//4.在driver结构体里面填写匹配名字,让他匹配设备树里面的led_test节点
	.driver = {
		.owner = THIS_MODULE,
		.name = "led_test",                //匹配名字,匹配成功后进入probe函数
		.of_match_table = of_match_table_test//优先匹配of_match_table
	},
};
  
static int led_driver_init( void)
{
	//1.看驱动文件先从init函数看
	int ret = 0;
	//2.在init函数里面注册了platform_driver
	ret = platform_driver_register( &led_driver);
	if( ret<0)
	{
		printk( "platform_driver_register error \n");
	}
	printk( "platform_driver_register ok \n");
	return 0;
}

static void led_driver_exit(void)
{
	misc_deregister( &misc_dev); //卸载杂项设备
	printk( "misc gooodbye! \n");
	iounmap( vir_gpio4_dr);
	iounmap( vir_gpio4_h);
	iounmap( vir_gpio4_l);

	// platform 驱动卸载
	platform_driver_unregister( &led_driver);
	printk( "goodbye! \n");
}

module_init( led_driver_init);
module_exit( led_driver_exit);

MODULE_LICENSE( "GPL");

4.app.c

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
	int fd;
	fd = open("/dev/hello_misc",O_RDWR);//打开设备节点
	if(fd < 0)
	{
		perror("open error \n");
		return fd;
	}
	buf[0]=atoi(argv[1]);
	write(fd,buf,sizeof(buf)); //向内核层写数据
	close(fd);
	return 0;
}

5.运行情况

树莓派 设备树,linux,linux,驱动开发
树莓派 设备树,linux,linux,驱动开发文章来源地址https://www.toymoban.com/news/detail-634341.html

到了这里,关于树莓派4B采用设备树(DTS)提供硬件信息,编写platform驱动控制io(LED)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于树莓派4B的智能家居

    本博文的智能家居使用的树莓派4B作为驱动板,当然也可以使用搭载了freeRtos的STM32驱动板,由于时间匆忙,没办法把从0到1的教程写到博文中,以后有时间的话会出一篇从0到1搭建这个智能家居的博文,到时候也会添加一些新的功能,如触摸屏、红外遥控、等等。 工厂模式就

    2024年02月14日
    浏览(28)
  • 在 树莓派 4B 中安装 Windows

    不过, Win11 应该也是可以的, 但是我在安装时, 因为路由器不带科学上网, 所以首先在欢迎页面就进不去, 给劝退了. 如果你的路由器可以科学上网的话, 那安装 Win11 的步骤也是相同的 目前仅支持网线, WiFi暂时无法使用, 等待更新 蓝牙可以正常使用 (看这个CPU调度感觉还蛮均衡的

    2024年02月02日
    浏览(31)
  • 树莓派4B(Raspberry Pi 4B)使用docker搭建springBoot/springCloud服务

    前提:本文基于Ubuntu,Java8,SpringBoot 2.6.13讲解 准备SpringBoot/SpringCloud项目jar包 用 maven 打包springBoot/springCloud项目,先在本地跑一跑,是否可以正常运行,特别注意哈!如果项目访问数据库,redis等运行在docker容器的服务,那么你的IP不能配置成树莓派IP,必须是docker network 内分

    2024年02月22日
    浏览(33)
  • 初始树莓派 + VMware17 安装树莓派(Raspberry Pi 4B/5)

    一年的考研生活过去了,充满了挑战与收获。如今,我又回到了编程的世界,准备以更新一期 树莓派 系列结合 人工智能/深度学习/计算机视觉/自然语言处理 作为我的毕业设计博客的主题。这一决定既是对过去学习的总结,也是对未来的展望。 树莓派(Raspberry Pi)是一款小

    2024年02月19日
    浏览(31)
  • 树莓派4B安装XRDP使用远程桌面

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 之前写了很多关于Ubuntu使用RDP或VNC的文章,最近在鼓捣树莓派4B,VNC我暂时没鼓捣成功,黑屏还未找到原因,XRDP可以使用,然后Windows远程桌面应用可以直接访问。 我的配置: OS:树莓派系统 64bits 这里

    2024年01月25日
    浏览(34)
  • Raspberry Pi 4B树莓派学习笔记

    这两天在学习 Raspberry Pi 4B树莓派, 这篇笔记就梳理一下目前学习到的一些知识,加强自己的记忆,整理一下思路,也希望能给大家带来帮助!感兴趣的小伙伴欢迎评论区留言或者私信博主! 目录 一、什么是树莓派 二、树莓派系统烧录 三、树莓派首次开机 四、树莓派连网

    2023年04月20日
    浏览(38)
  • 树莓派4B(Raspberry Pi 4B)使用docker搭建阿里巴巴sentinel服务

    由于国内访问不了docker hub,而国内镜像仓库又没有适配树莓派ARM架构的sentinel镜像,所以我们只能退而求其次——自己动手构建镜像。本文基于Ubuntu,Java8,sentinel-dashboard-1.8.7讲解 下载sentinel-dashboard-1.8.7.jar 到GitHub(Releases · alibaba/Sentinel (github.com))下载 下载jdk-8u391-linux-aar

    2024年02月20日
    浏览(34)
  • 【IMX6ULL驱动开发学习】01.编写第一个hello驱动+自动创建设备节点(不涉及硬件操作)

    目录 一、驱动程序编写流程 二、代码编写 2.1 驱动程序hello_drv.c 2.2 测试程序 2.3 编写驱动程序的Makefile 三、上机实验 3.1 NFS 挂载 3.2 测试示例 构造file_operations结构体 在里面填充open/read/write/ioctl成员 注册file_operations结构体 int major = register_chrdev(0, \\\"name\\\", fops); 入口函数:调用

    2024年02月13日
    浏览(30)
  • 树莓派4B从开箱到连接电脑(超级小白)

    官网链接:https://www.raspberrypi.com/ (1)点击“Software” (2)下拉,根据系统选择,笔者的是windows,所以 (3)\\\"install\\\"➡“finish” (4)点击\\\"选择操作系统\\\",笔者是超级小白,所以选择的是官方系统 (5)插入读卡器,点击\\\"选择SD卡\\\" (6)点击仅有的选择 (7)点击设置的图标

    2024年02月10日
    浏览(39)
  • 基于树莓派4B的智能无人巡逻小车设计

    计算机工程实训报告 题目                 智能警用无人巡逻小车                                视频演示地址:树莓派暑期工程实训-模拟警用无人巡逻小车_哔哩哔哩_bilibili 一、实验内容与要求 本实验使用 Yahboom 生产的树莓派 4B,需要组员对树莓派小车的各

    2024年02月11日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包