【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十五章 Pinctrl和GPIO子系统实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺,提供更快的速度和更高的电源效率;四核Cortex-A53,单核Cortex-M4,多达五个内核 ,主频高达1.8GHz,2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT、4G模块、CAN、RS485等接口一应俱全。H264、VP8视频硬编码,H.264、H.265、VP8、VP9视频硬解码,并提供相关历程,支持8路PDM接口、5路SAI接口、2路Speaker。系统支持Android9.0(支持获取root限)Linux4.14.78+Qt5.10.1、Yocto、Ubuntu20、Debian9系统。适用于智能充电桩,物联网,工业控制,医疗,智能交通等,可用于任何通用工业和物联网应用、

【公众号】迅为电子

【粉丝群】258811263


第五十五章 Pinctrl和GPIO子系统实验

本章导读

本章节将以实践课的方式讲解LED驱动例程。

55.1章节对实验需求进行分析

55.2章节修改设备树文件

55.3章节编写驱动文件

55.4章节编写测试APP

55.5章节运行测试,实现了控制LED亮灭

本章内容对应视频讲解链接(在线观看):

pinctl和gpio子系统 ( https://www.bilibili.com/video/BV1Vy4y1B7ta?p=30

pinctl和gpio子系统 ( https://www.bilibili.com/video/BV1Vy4y1B7ta?p=31

程序源码在网盘资料“iTOP-i.MX8MM开发板\02-i.MX8MM开发板网盘资料汇总(不含光盘内容)\嵌入式Linux开发指南(iTOP-i.MX8MM)手册配套资料\2.驱动程序例程\012-Pinctrl和GPIO子系统实验”路径下。

55.1 需求分析

通过第54章的学习,我们已经明白什么是pinctrl子系统和GPIO子系统,pinctrl子系统就是设置引脚的复用关系和电气属性的,GPIO子系统就是当pinctrl子系统将复用关系设置为GPIO以后,我们使用GPIO子系统来操作我们的GPIO。那么本章节我们来用pinctrl子系统和GPIO子系统来控制我们的引脚。第55章我们学习了在设备树下的平台总线模型,当匹配成功以后会在设备树文件中拿资源,然后我们再进行相关的操作。

本章节我们要编写pinctrl子系统和GPIO子系统,我们可以在以前代码的基础上进行编写,框架并没有变,我们也是让驱动和设备进行匹配,匹配成功之后将相关的操作,唯一变的地方是之前使用的寄存器操作我们的GPIO,现在我们换成了GPIO子系统提供的API函数来操作我们的GPIO,比原来的方法更先进了一些。

 我们以iTOP-IMX8MM开发板为例来控制LED,本章节内容会将以前学习的驱动理论融会贯通,学以致用。LED 设备注册的流程:

  • 硬件原理图分析,确定控制LED的GPIO信息,参考42.2硬件分析章节,蜂鸣器复用GPIO11_IO13
  • 根据GPIO信息在设备树文件中添加pinctrl信息
  • 在设备树文件中创建蜂鸣器的节点,并加入GPIO信息,修改完设备树编译烧写新的设备树
  • 编写LED设备驱动,加载驱动模块
  • 编写应用程序测试LED

55.2 修改设备树文件

我们修改设备树文件/home/topeet/linux/linux-imx/arch/arm64/boot/dts/freescale/itop8mm-evk.dtsi,修改test节点如下图所示:

	test:test{#address-cells = <1>;#size-cells = <1>;compatible = "test";//reg = <4 0x30200000 4 0x30200004>;pinctrl-names = "default";pinctrl-0 = <&led_gpio>;gpios = <&gpio1 13 0>;};
&test{compatible = "test1234";status = "okay";
};

 

在&pinctrl里面追加pinctrl_beep内容,如下图所示: 

修改完后保存文件,参考开发板的使用手册编译源码,然后重新烧写编译好的镜像。

55.3 LED驱动程序编写

这里我们以iTOP-IMX8MM开发板为例。我们在Ubuntu的/home/topeet/imx8mm/12下新建driver文件,如下图所示。 

/** @Author: topeet* @Description: LED驱动*/#include <linux/init.h>            //初始化头文件
#include <linux/module.h>          //最基本的文件,支持动态添加和卸载模块。
#include <linux/platform_device.h> //platform平台设备相关的头文件
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/miscdevice.h> //包含了miscdevice结构的定义及相关的操作函数。
#include <linux/fs.h>         //文件系统头文件,定义文件表结构(file,buffer_head,m_inode等)
#include <linux/uaccess.h>    //包含了copy_to_user、copy_from_user等内核访问用户进程内存地址的函数定义。
#include <linux/io.h>         //包含了ioremap、iowrite等内核访问IO内存等函数的定义。
#include <linux/gpio.h>
#include <linux/of_gpio.h>
int size;
int led_gpio = 0;
int ret = 0;
u32 out_values[2] = {0};
const char *str;
struct device_node *test_device_node;
struct property *test_node_property;ssize_t misc_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{printk("misc_read\n ");return 0;
}
ssize_t misc_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{/*应用程序传入数据到内核空间,然后控制led的逻辑,在此添加*/// kbuf保存的是从应用层读取到的数据char kbuf[64] = {0};// copy_from_user 从应用层传递数据给内核层if (copy_from_user(kbuf, ubuf, size) != 0){// copy_from_user 传递失败打印printk("copy_from_user error \n "); return -1;}//打印传递进内核的数据printk("kbuf is %d\n ", kbuf[0]); //如果传递进的数据是1,则led亮if (kbuf[0] == 1){gpio_set_value(led_gpio, 1);}//如果传递进的数据是0,则led不亮else if (kbuf[0] == 0)gpio_set_value(led_gpio, 0);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,.read = misc_read,.write = misc_write,
};
//杂项设备结构体
struct miscdevice misc_dev = {.minor = MISC_DYNAMIC_MINOR,.name = "hello_misc",.fops = &misc_fops,
};
/*** @description: platform 驱动的 probe 函数,当驱动与设备匹配以后此函数就会执行* @param {*}pdev : platform 设备* @return {*}0,成功;其他负值,失败*/
int led_probe(struct platform_device *pdev)
{printk("led_probe\n");//获得设备节点test_device_node = of_find_node_by_path("/test");if (test_device_node == NULL){printk("of_find_node_by_path is error \n");return -1;}/*******我们要使用我们的GPIO就要从设备树来获取**********//*  of_get_named_gpio函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio1 13 1>的属性信息转换为对应的 GPIO 编号 */led_gpio = of_get_named_gpio(test_device_node, "gpios", 0);if (led_gpio < 0){printk("of_get_named_gpio is error \n");return -1;}printk("led_gpio is %d \n", led_gpio);//申请一个 GPIO 管脚ret = gpio_request(led_gpio, "led");if (ret < 0){printk("gpio_request is error \n");return -1;}//设置某个GPIO为输出,并且设置默认输出值gpio_direction_output(led_gpio, 1);//注册杂项设备ret = misc_register(&misc_dev);if (ret < 0){printk("misc registe is error \n");}printk("misc registe is succeed \n");return 0;
}int led_remove(struct platform_device *pdev)
{gpio_free(led_gpio);printk("led_remove\n");return 0;
}
const struct platform_device_id led_idtable = {.name = "led_test",
};
const struct of_device_id of_match_table_test[] = {{.compatible = "test1234"},{},
};
struct platform_driver led_driver = {//第三步 在led_driver结构体中完成了led_probe和led_remove.probe = led_probe,.remove = led_remove,.driver = {.owner = THIS_MODULE,.name = "led_test",.of_match_table = of_match_table_test },//第四步 .id_table的优先级要比driver.name的优先级要高,优先与.id_table进行匹配.id_table = &led_idtable
};static int led_driver_init(void)
{//第一步 我们看驱动文件要从init函数开始看int ret = 0;//第二步 在init函数里面注册了平台设备驱动platform_driverret = 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)
{printk("gooodbye! \n");misc_deregister(&misc_dev);platform_driver_unregister(&led_driver);
}
module_init(led_driver_init);
module_exit(led_driver_exit);MODULE_LICENSE("GPL");

编译驱动代码为驱动模块,如下图所示:


 

55.4 编写测试APP

编写测试APP程序,完整代码如下所示:

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <stdlib.h>

int main(int argc,char *argv[])

{

    int fd;

    char buf[64] = {0};//定义buf缓存

    //打开设备节点

    fd = open("/dev/hello_misc",O_RDWR);

    if(fd < 0)

    {

        //打开设备节点失败

        perror("open error \n"); 

        return fd;

    }

    // atoi()将字符串转为整型,这里将第一个参数转化为整型后,存放在buf[0]中

    buf[0] = atoi(argv[1]);

    //把缓冲区数据写入文件中

    write(fd,buf,sizeof(buf));  

    printf("buf is %d\n",buf[0]); 

    close(fd);

    return 0;

}

我们将app.c文件拷贝到Ubuntu的/home/topeet/imx8mm/12目录下,输入以下命令编译app.c

 

55.5 运行测试

我们将55.2章节新编译的镜像烧写进开发板以后,启动开发板。

我们来查看一下添加的设备树节点,请参考本手册51.1查看设备树节点方法章节,如下图所示:

我们进入共享目录,加载驱动模块,如下图所示:

insmod driver.ko

 

我们再运行应用程序,输入命令“./app 1”LED亮;输入命令“./app 0”LED灭,如下图所示:

./app 0

./app 1

 

至此,我们已经学会了在设备树中使用pinctrl子系统和GPIO子系统。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/383624.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于opencv的答题卡识别

文章目录 一、背景需求二、处理步骤图片预处理检测到答题卡轮廓透视变换找每个圆圈的轮廓轮廓排序判断是否答题正确 一、背景需求 传统的手动评分方法耗时且容易出错&#xff0c;自动化评分可以可以显著提高评分过程的速度和准确性、减少人工成本。 答题卡图片处理效果如下&am…

dockerfile部署wordpress

1.将容器直接提交成镜像 [rootlocalhost ~]# docker commit 8ecc7f6b9c12 nginx:1.1 sha256:9a2bb94ba6d8d952527df616febf3fbc8f842b3b9e28b7011b50c743cd7b233b [rootlocalhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx …

javafx的ListView代入项目的使用

目录 1. 创建一个可观察的列表&#xff0c;用于存储ListView中的数据,这里的User是包装了用户的相关信息。 2.通过本人id获取friendid&#xff0c;及好友的id&#xff0c;然后用集合接送&#xff0c;更方便直观一点。 3.用for遍历集合&#xff0c;逐个添加。 4.渲染器&…

【我的养猪日记】区块链游戏

剧情介绍 年少无知留给了故乡&#xff0c;谦卑有礼送给了远方&#xff0c;有工作的地方没家&#xff0c;有家的地方没工作&#xff0c;他乡留不下灵魂&#xff0c;故乡安不了肉身&#xff0c;从此便有了漂泊。在外漂泊数年的你每天过着&#xff0c;挤不完的公交地铁、交不完的房…

面试场景题系列--(2)短 URL 生成器设计:百亿短 URL 怎样做到无冲突?--xunznux

文章目录 面试场景题&#xff1a;短 URL 生成器设计&#xff1a;百亿短 URL 怎样做到无冲突&#xff1f;1. 需求分析2. 短链接生成算法2.1 自增法2.2 散列函数法2.3 预生成法 3. 部署模型3.1 其他部署方案 4. 设计4.1 重定向响应码4.2 短 URL 预生成文件及预加载4.3 用户自定义…

EtherNet/IP转Profinet协议网关(经典配置案例)

怎么样才能把EtherNet/IP和Profinet网络连接起来呢?这几天有几个朋友问到了这个问题&#xff0c;作者在这里统一为大家详细说明一下。其实有一个设备可以很轻松地解决这个问题&#xff0c;名为JM-PN-EIP&#xff0c;下面是详细介绍。 一&#xff0c;设备主要功能 1、捷米特J…

AnyMP4 Data Recovery for Mac v1.5.8免激活版:高效数据恢复新选择

AnyMP4 Data Recovery for Mac是一款专为Mac用户设计的高效数据恢复软件&#xff0c;凭借其强大的功能和简洁的操作界面&#xff0c;为用户提供了快速、安全的数据恢复体验。 该软件支持恢复多种文件类型&#xff0c;包括照片、视频、音频、文档等&#xff0c;无论是常见的图片…

前端学习7——自学习梳理

​​​​​​jQuery 教程 | 菜鸟教程jQuery 教程 jQuery 是一个 JavaScript 库。 jQuery 极大地简化了 JavaScript 编程。 jQuery 很容易学习。 本章节的每一篇都包含了在线实例 通过本站的在线编辑器&#xff0c;你可以在线运行修改后的代码&#xff0c;并查看运行结果。 实例…

【Python正则表达式】:文本解析与模式匹配

文章目录 1.正则表达式2. re模块3.修饰符3.元字符3-1 字符匹配元字符3-2 重复次数限定元字符3-3 字符集合匹配元字符3-4 分组元字符3-5 边界匹配元字符3-6 字符类别匹配元字符 4.技巧4-1 贪婪与非贪婪 5.案例 1.正则表达式 正则表达式面向什么样的问题&#xff1f; 1、判断一个…

uniapp引入自定义图标

目录 一、选择图标&#xff0c;加入购物车 二、下载到本地 三、导入项目 四、修改字体引用路径 五、开始使用 这里以扩展iconfont图标为例 官网&#xff1a;iconfont-阿里巴巴矢量图标库 一、选择图标&#xff0c;加入购物车 二、下载到本地 直接点击下载素材&#xff0…

2019数字经济公测大赛-VMware逃逸

文章目录 环境搭建漏洞点exp 环境搭建 ubuntu :18.04.01vmware: VMware-Workstation-Full-15.5.0-14665864.x86_64.bundle 这里环境搭不成功。。patch过后就报错&#xff0c;不知道咋搞 发现可能是IDA加载后的patch似乎不行对原来的patch可能有影响&#xff0c;重新下了patch&…

【Kettle实现神通(数据库)MPP增量、全量数据ETL,同步任务Linux运行(通用)】

1、背景介绍 具体Kettle操作步骤不做过多介绍&#xff0c;主要技术方案说明&#xff0c;Kettle8.2版本放在底部链接提取&#xff0c;本次采用Kettle实现源端&#xff1a;神通数据通用库、目标端&#xff1a;神通MPP增量数据同步&#xff0c;并在服务器端运行Job。 2、windows…

鸿蒙OpenHarmony Native API【支持的标准库+Node_API】

Native API中支持的标准库 简介 表1 OpenHarmony支持的标准库 名称简介标准C库[libc、libm、libdl]组合实现C11标准C库。标准C库[libc]是C标准库的一种实现。OpenSL ES[OpenSL ES]是一个嵌入式跨平台的音频处理库。zlib[Zlib]是基于C/C语言实现的一个通用的数据压缩库。EGL[…

VMare centos 7 设置固定ip

第一步获取网关 查看虚拟机的网关-》编辑-》虚拟网络编辑器 NAT模式-》NAT设置 获取网关IP 192.168.70.2 第二步获取主机dns1 在本地主机获取dns1&#xff0c;本地主机调出cmd输入ipconfig dns1为192.168.31.1 用管理员权限的账号进入需要设置固定ip的虚拟机&#xff0c;在t…

零基础学习Python(四)

1. __getitem__、__setitem__、__iter__、__next__魔法方法 __index__方法是对象被作为索引访问时调用的魔法方法&#xff0c;那么当对象要进行索引访问时&#xff0c;调用什么魔法方法呢&#xff1f;答案是__getitem__魔法方法。 class C:def __getitem__(self, index):prin…

vscode回退不显示了,不方便操作

一、后退前进按钮 顶部显示&#xff0c;方便调试 <—— ——> 文件-> 首选项 -> 设置->commandcenter->勾选 Window: Title Bar Style->custom 将native —>custom

MongoDB教程(二十二):MongoDB固定集合

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、固定集…

单片机学习历程

学习单片机的过程可以分为几个主要阶段&#xff0c;每个阶段都涉及不同的学习内容和技能提升。下面我将以一个典型的学习历程为例进行介绍&#xff1a; 初学阶段 1.入门理论学习&#xff1a; 开始接触单片机的基础知识&#xff0c;学习其工作原理、体系结构和常见的芯片类型…

昇思25天学习打卡营第20天|CV-ResNet50图像分类

打卡 目录 打卡 图像分类 ResNet网络介绍 数据集准备与加载 可视化部分数据集 残差网络构建 Building Block 结构 代码实现 Bottleneck结构 代码实现 构建ResNet50网络 代码定义 模型训练与评估 可视化模型预测 重点&#xff1a;通过网络层数加深&#xff0c;感知…

vue3前端开发-小兔鲜项目-路由拦截器增加token的携带

vue3前端开发-小兔鲜项目-路由拦截器增加token的携带&#xff01;实际开发中&#xff0c;很多业务接口的请求&#xff0c;都要求必须是登录状态&#xff01;为此&#xff0c;这个token信息就会频繁的被加入到了请求头部信息中。request请求头内既然需要频繁的携带这个token.我们…