正点原子嵌入式linux驱动开发——设备树下LED驱动

经过对设备树的学习以及驱动开发中常用的OF函数介绍,本篇笔记将之前的新字符设备驱动的LED,换成设备树形式

设备树LED驱动原理

在之前的新字符设备驱动实验中,直接在驱动文件newchrled.c中定义有关寄存器物理地址,然后使用io_remap函数进行内存映射,得到对应的虚拟地址,最后操作寄存器对应的虚拟地址完成对GPIO的初始化。现在使用设备树来向Linux内核传递相关的寄存器物理地址,Linux驱动文件使用上一篇笔记中重点学习讲解的OF函数从设备树中获取所需的属性值,然后使用获取到的属性值来初始化相关的IO。本章实验重点内容如下:

  1. 在stm32mp157d-atk.dts文件中创建相应节点设备。
  2. 编写驱动程序,获取设备树种相关属性值。
  3. 使用获取的有关属性值来初始化LED使用的GPIO。

硬件原理图

这个就是之前的LED灯的原理图,没有区别,这里不再展示。

实验程序

修改设备树文件

在根节点“/”下创建一个名为“stm32mp1_led”的子节点,打开stm32mp157d-atk.dts文件,在根节点“/”最后面输入如下所示内容:

示例代码24.3.1.1 stm32mp1_led节点 
1 stm32mp1_led { 
2     compatible = "atkstm32mp1-led"; 
3     status = "okay"; 
4     reg = <0X50000A28 0X04 /* RCC_MP_AHB4ENSETR */ 
5            0X5000A000 0X04 /* GPIOI_MODER */ 
6            0X5000A004 0X04 /* GPIOI_OTYPER */ 
7            0X5000A008 0X04 /* GPIOI_OSPEEDR */ 
8            0X5000A00C 0X04 /* GPIOI_PUPDR */ 
9            0X5000A018 0X04 >; /* GPIOI_BSRR */ 
10 };

第2行,属性compatible设置stm32mp1_led节点兼容为“atkstm32mp1-led”。

第3行,属性status设置状态为“okay”。

第4-9行,reg属性,非常重要!reg属性设置了驱动里面所要使用的寄存器物理地址,比如第4行的“0X50000A28 0X04”表示STM32MP1的RCC_MP_AHB4ENSETR寄存器,其中寄存器地址为0X50000A28,长度为4个字节。

设备树修改完成以后输入如下命令重新编译一下
stm32mp157d-atk.dts:

make dtbs

编译完成后得到stm32mp157d-atk.dtb,使用新的stm32mp157d-atk.dtb启动Linux内核。Linux启动成功以后进入到/proc/device-tree/目录中查看是否有“stm32mp1_led”这个节点,结果如下图所示:
正点原子嵌入式linux驱动开发——设备树下LED驱动_第1张图片
如果没有“stm32mp1_led”节点的话可以重点检查下面两点:

  1. 检查设备树修改是否成功,也就是stm32mp1_led节点是否为根节点“/”的子节点。
  2. 检查是否使用新的设备树启动的Linux内核。

可以进入到stm32mp1_led的目录中,使用cat查看各个属性值。

LED灯驱动编写

在之前已经编写好的LED驱动基础上,在dtsled_dev结构体中,加上struct device_node* nd的设备节点;然后需要在驱动的led_init函数中,加上获取设备树属性的操作:主要是通过dtsled.nd(之前的dtsled_dev结构体)来接住of_find_node_by_path(“/stm32mp1_led”)的返回值,从而获得LED节点;而后通过property*的proper来接住of_find_property返回值,获取compatible属性;int ret来接住of_property_read_string返回值,获取status属性值;再用ret接住of_property_read_u32_array返回值,获取reg属性值,存放到regdata数组中;以上属性值全部存到了dtsled.nd之中就获得了LED的相关寄存器,之后通过of_iomap来获取dtsled.nd的reg属性以及内存映射,从而获得了要操作的寄存器地址。

编写测试APP

这个可以直接用之前的ledApp.c文件。

编译驱动程序和测试APP

编译驱动

在Makefile文件中,将obj-m的值改为dtsled.o即可,然后通过“make -j8”就可以编译,最终得到dtsled.ko文件。

编译测试APP

可以通过如下命令编译:

arm-none-linux-gnueabihf-gcc ledApp.c -o ledApp

运行测试

将之前编译得到的dtsled.ko和ledApp拷贝到rootfs/lib/modules/5.4.31目录中,然后重启开发板,进入/lib/modules/5.4.31目录,输入如下命令加载dtsled.ko:

depmod //第一次加载驱动的时候需要运行此命令
modprobe dtsled //加载驱动

加载成功后会出现如下信息:
正点原子嵌入式linux驱动开发——设备树下LED驱动_第2张图片
从上图中可以看出,stm32mp1_led这个节点找到了,并且compatible属性值为“atkstm32mp1-led”,status属性值为“okay”,reg属性的值为“0X50000A28 0X4 0X5000A000 0X4 0X5000A004 0X4 0X5000A008 0X4 0X5000A00C 0X4 0X5000A018 0X4”,这些都和设置的设备树一致。

加载成功后可以通过如下命令打开和关闭LED:

./ledApp /dev/dtsled 1 //打开LED灯
./ledApp /dev/dtsled 0 //关闭LED灯

可以通过如下命令卸载驱动:

rmmod dtsled.ko

总结

这一篇笔记中,主要的区别就是在stm32mp157d-atk.dts文件中,在"/"根节点下添加了LED的设备树节点,然后在驱动程序中增加了对应了结构体成员device_node* nd,然后在led_init中通过OF函数获取属性值,主要是reg属性值来读取LED的相关寄存器。

你可能感兴趣的:(linux学习,linux,驱动开发,stm32,学习,笔记)