• 正点原子嵌入式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 };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    第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”这个节点,结果如下图所示:
    stm32mp1_led节点
    如果没有“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 //加载驱动

    加载成功后会出现如下信息:
    驱动加载成功后输出信息
    从上图中可以看出,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的相关寄存器。

  • 相关阅读:
    facechain人物写真生成工业级开源
    5款堪称变态的AI神器,焊死在电脑上永不删除!
    二、ROS2基本操作
    新型BI解决方案:SaaS BI,在浏览器上分析数据
    T-SQL——批量刷新视图
    腾讯云服务器按带宽计费与使用流量计费有什么区别?如何选择?
    7.7亿参数,超越5400亿PaLM!UW谷歌提出「分步蒸馏」,只需80%训练数据|ACL 2023
    Linux基础(三)
    elasticsearch 安装教程
    面试经典150题——Day33
  • 原文地址:https://blog.csdn.net/xhj12138/article/details/133903344