手把手带你写一个中断输入设备驱动

今天群里有人问,要开始驱动开发的话从什么开始比较好。

我说,应该开始去摸索触摸屏驱动,现在我想了下,触摸屏驱动可能会难了些,但是从一个GPIO开始,我觉得一定是一件很容易的事情。

所以这篇文章就来了。

b17801fb34dee8632d276ee241cbd72a.png

大家好,这是我的朋友逸珺。

首先说声抱歉,最近迷上钓鱼了,有时候晚上出去夜钓大板鲫了,停更了一段时间。来几张鱼获图片:

d7a87e58ec2edd8cd257c4b1869842ac.png

技术还是不太到家,遇到几次大鲤鱼都给溜了,心有不甘,所以最近花了比较多的时间。

言归正传,今天来分享一下以前写一个中断输入设备驱动案例,希望对有需要的朋友能有所帮助。

背景介绍

在一个项目中,有这样一个需求:

6bfc7fced8e60fa0f5c414d39f8df9c0.png

主控芯片采用ZYNQ,需要采集外部一个脉冲编码输入信号,这个信号是一个脉冲波形,脉冲数量代表测量结果。比如这有可能是一个电机的霍尔信号输出,代表电机的转速,也有可能是一个光栅编码器的脉冲输出,是什么并不重要。

这个电路本身,利用光耦实现了输入测设备信号与采集端的电气隔离。由于PS端该Bank的电平为3.3V,所以光耦的另一侧也是3.3V。

ZYNQ的PS端运行Linux程序,所以在这个场景下,要从应用程序的角度将外部输入信号用起来,就需要实现这样一个设备驱动程序:

c567cfe2e4065204e1aefa8b316f1b86.png

创建设备

在ZYNQ下,使用petalinux工具链,当然本文中对于写这个驱动程序本身换成其他的处理器从代码的角度是类似的。

1.先运行一下工具链环境变量脚本:

source /opt/pkg/petalinux/settings.sh

当然也可以不用手动这样运行,设置成linux开发主机开机自动运行,这里就不赘述怎么设置了,网上很多介绍。

2.创建设备

petalinux-create -t modules --name di-drv

这样在现有的工程下,就自动创建设备文件:

./project-spec/meta-user/recipes-modules/di-drv/files/di-drv.c

修改设备树

./project-spec/meta-user/recipes-bsp/device-tree/files/system-user.dtsi 

中添加

/include/ "system-conf.dtsi"
/ {   amba {pinctrl_di_default: di-default {   mux {   groups = "gpio0_0_grp";   function = "gpio0";   };   conf {   pins = "MIO0";   io-standard = <1>;   bias-high-impedance;   slew-rate = <0>;   };   };           };di {compatible = "di-drv";pinctrl-names = "default";pinctrl-0 = <&pinctrl_di_default>;di-gpios = <&gpio0 0 0>;   };      
};

本文中,假定使用的IO引脚为PS_MIO0。

驱动代码

修改上面生成的代码di-drv.c

#include <linux/module.h>  
#include <linux/kernel.h>
#include <linux/init.h>  
#include <linux/ide.h>  
#include <linux/types.h>  
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>
#include <asm/io.h>/* 设备节点名称 */  
#define DEVICE_NAME       "di-drv"
/* 设备号个数 */  
#define DEVID_COUNT       1
/* 驱动个数 */  
#define DRIVE_COUNT       1
/* 主设备号 */
#define MAJOR_U
/* 次设备号 */
#define MINOR_U           0struct di_dev {/* 字符设备框架 */dev_t         devid; //设备号struct cdev     cdev;  //字符设备struct class    *class;  //类struct device    *device; //设备struct device_node *nd;   //设备树的设备节点spinlock_t      lock; //自旋锁变量int          di_gpio; //DI gpio号__u32         di_pulses;//DI counter    unsigned int     di_irq; //DI 中断号
};static struct di_dev di_char = {.cdev = {.owner = THIS_MODULE,},
};/* 中断服务函数 */
static irqreturn_t di_handler(int irq, void *dev)
{di_char.di_pulses++;return IRQ_RETVAL(IRQ_HANDLED);
}/* open函数实现, 对应到Linux系统调用函数的open函数 */  
static int di_drv_open(struct inode *inode_p, struct file *file_p)  
{  printk("di_drv module opened\n");  file_p->private_data = &di_char; return 0;  
}  /* read函数实现, 对应到Linux系统调用函数的read操作 */  
static ssize_t di_drv_read(struct file *file_p, char __user *buf, size_t len, loff_t *loff_t_p)  
{  unsigned long flags;int ret;union e_int_conv{__u8  buf[8];__u32 di_raw;};  /* 获取锁 */spin_lock_irqsave(&di_char.lock, flags);union e_int_conv di;di.di_raw.di = di_char.di_pulses;ret  = copy_to_user(buf, di.buf, 8);/* 释放锁 */spin_unlock_irqrestore(&di_char.lock, flags);return ret ? ret : 4;
}  /* release函数实现, 对应到Linux系统调用函数的close函数 */  
static int di_drv_release(struct inode *inode_p, struct file *file_p)  
{  printk("di_drv module release\n");return 0;  
}  /* file_operations结构体声明 */  
static struct file_operations di_fops = {  .owner   = THIS_MODULE,  .open   = di_drv_open,  .read   = di_drv_read,     .release = di_drv_release,   
};  /* 模块加载时会调用的函数 */  
static int __init di_drv_init(void)  
{u32 ret = 0;/* 初始化自旋锁 */spin_lock_init(&di_char.lock);/** gpio框架 **/   /* 获取设备节点 */di_char.nd = of_find_node_by_path("/di");if(di_char.nd == NULL){printk("di node not foundr\r\n");return -EINVAL;}/* 获取节点中gpio标号 */di_char.di_gpio = of_get_named_gpio(di_char.nd, "di-gpios", 0);if(di_char.di_gpio < 0){printk("Failed to get di-gpios from device tree\r\n");return -EINVAL;}printk("di-gpio num = %d\r\n", di_char.di_gpio);/* 申请gpio标号对应的引脚 */ret = gpio_request(di_char.di_gpio, "di-drv");if(ret != 0){printk("Failed to request di_gpio\r\n");return -EINVAL;}/* 把这个io设置为输入 */ret = gpio_direction_input(di_char.di_gpio);if(ret < 0){printk("Failed to set di_gpio as input\r\n");return -EINVAL;}/* 获取中断号 */di_char.di_irq = gpio_to_irq(di_char.di_gpio);printk("di_irq number is %d \r\n", di_char.di_irq);/* 申请中断 */ret = request_irq(di_char.di_irq,di_handler,IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,"di-drv", NULL);if(ret < 0){printk("di_irq %d request failed\r\n", di_char.di_irq);return -EFAULT;}    /* 注册设备号 */alloc_chrdev_region(&di_char.devid, MINOR_U, DEVID_COUNT, DEVICE_NAME);/* 初始化字符设备结构体 */cdev_init(&di_char.cdev, &di_fops);/* 注册字符设备 */cdev_add(&di_char.cdev, di_char.devid, DRIVE_COUNT);/* 创建类 */di_char.class = class_create(THIS_MODULE, DEVICE_NAME);if(IS_ERR(di_char.class)) {return PTR_ERR(di_char.class);}/* 创建设备节点 */di_char.device = device_create( di_char.class, NULL, di_char.devid, NULL, DEVICE_NAME );if(IS_ERR(di_char.device)) {return PTR_ERR(di_char.device);}di_char.di_pulses = 0;    return 0;  
}/* 卸载模块 */  
static void __exit di_drv_exit(void)  
{  /* 释放gpio */gpio_free(di_char.di_gpio);/* 释放中断 */free_irq(di_char.di_irq, NULL);/* 注销字符设备 */cdev_del(&di_char.cdev);/* 注销设备号 */unregister_chrdev_region(di_char.devid, DEVID_COUNT);/* 删除设备节点 */device_destroy(di_char.class, di_char.devid);/* 删除类 */class_destroy(di_char.class);printk("DI dev exit ok\n");  
}  /* 标记加载、卸载函数 */  
module_init(di_drv_init);  
module_exit(di_drv_exit);  /* 驱动描述信息 */  
MODULE_AUTHOR("Embinn");  
MODULE_ALIAS("DI input");  
MODULE_DESCRIPTION("DIGITAL INPUT driver");  
MODULE_VERSION("v1.0");  
MODULE_LICENSE("GPL");

这是一个字符驱动的实现,在真实项目中,大部分驱动基本已经被芯片厂商给实现了,但是一些特殊项目的自定义需求,往往就需要去实现自己的驱动。

编译部署

运行以下命令:

petalinux-config -c rootfs

1ff1b9972fe9ed41419471fa57731933.png

进入modules,使能刚刚创建的模块,退出保存。

运行下面的命令进行编译:

petalinux-build

最终在工程目录下,搜索di-drv.ko,就得到这个驱动的内核模块文件了,拷贝到目标板的某个文件夹下,运行下面的命令装载就完成了:

insmod di-drv.ko

这样在/dev下就会发现新增一个di-drv设备。

当然也可以直接将该驱动放进内核里,这就需要在内核代码树里,添加文件了,这个思路之前有分享过。

总结一下

字符设备是做驱动开发比较容易掌握的驱动类型,也是大多数项目中,需要自己动手写的最多的驱动类型。所以还是应该掌握它。才能实现不同的项目需求。至于用户空间怎么访问这个设备,这里就不赘述了,一个文件打开操作,再来一个读取操作就完事了。


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

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

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

相关文章

驱动调试神器printk你掌握了吗?

[导读] 刚刚开始做Linux相关开发工作时&#xff0c;深感Linux内核代码庞大&#xff0c;要加些自己的驱动进内核代码树&#xff0c;常常深陷bug的泥沼难以自拔&#xff0c;今天来分享一下内核调试利器printk的使用心得。前面一段时间很忙&#xff0c;后期更文频率会渐渐回归正常…

腾讯云技术专家卢萌凯手把手教你Demo一个人脸识别程序!

欢迎大家前往腾讯云社区&#xff0c;获取更多腾讯海量技术实践干货哦~ 本文来自腾讯云技术沙龙&#xff0c;本次沙龙主题为Serverless架构开发与SCF部署实践 卢萌凯&#xff1a;毕业于东南大学&#xff0c;曾就职于华为&#xff0c;熟悉云行业解决方案。目前负责腾讯云中间件产…

二十世纪最伟大的算法,你了解哪个?

导读&#xff1a;作者July总结了一篇关于计算方法的文章《 细数二十世纪最伟大的10大算法 》。一、1946 蒙特卡洛方法[1946: John von Neumann, Stan Ulam, and Nick Metropolis, all at the Los Alamos Scientific Laboratory, cook up the Metropolis algorithm, also known …

桌面计算机恢复出厂设置,windows7电脑怎么恢复出厂设置

我们使用电脑一段时间&#xff0c;由于各种问题&#xff0c;希望将电脑恢复出厂设置&#xff0c;那么windows7电脑怎么恢复出厂设置呢&#xff1f;下面跟着学习啦小编来一起了解下windows7电脑恢复出厂设置的方法吧。windows7电脑恢复出厂设置方法一按下开机键&#xff0c;启动…

关于Exchange管理控制台报“您的权限不足,无法此查看数据”的解决办法

今天朋友突然来电话&#xff0c;说自己的Exchange 2010 EMC突然报“you dont have sufficient permissions to view this data”&#xff08;您的权限不足&#xff0c;无法查看此数据&#xff09;&#xff0c;同时所有的cmdlet命令也不可以执行。询问我解决办法&#xff0c;出错…

内存为什么还有管理?

本文作者&#xff1a;度白嵌入式任何程序运行起来都需要分配内存空间存放该进程的资源信息的&#xff0c;C程序也不例外。C程序中的变量、常量、函数、代码等等的信息所存放的区域都有所不同&#xff0c;不同的区域又有不同的特性。C语言学习者、尤其是在学习嵌入式的朋友&…

旧手机别扔,手把手教你DIY一台Linux服务器

作者&#xff1a;Hannah Lee编译&#xff1a;弯月 欧阳姝黎来源&#xff1a;CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;本文将向你展示如何使用 UrBackup 和 Linux Deploy在一台 Android 旧手机上搭建一台备份服务器。旧手机的污染问题众所周知&#xff0c;我有一台旧…

学计算机买电脑显卡1605ti够吗,GTX1650和GTX1050Ti哪个好?GTX1050ti和GTX1650性能差距对比评测...

GTX1650显卡在2019年4月22日进行发售&#xff0c;不少用户认为GTX1650是智商检测卡&#xff0c;真的是吗&#xff1f;从命名上来看&#xff0c;GTX1650应该是GTX1050的升级产品&#xff0c;不过根据英伟达的说法&#xff0c;GTX1650相比GTX1050提升幅度达到了70%&#xff0c;但…

Gamma的传说

Gamma校正对于图形和图像来说是个常提的概念&#xff0c;但对于gamma的缘由和使用方法&#xff0c;却存在着很多传说。本文将尽可能解析gamma校正来源&#xff0c;破解各种迷思。Gamma校正从何而来 有一种常见的说法&#xff0c;gamma来源于眼睛对光感受。我也曾经错误地采用了…

心急吃不了热豆腐

良好的焊接是保证电路稳定持久工作的前提。下面给出了常见到的焊接缺陷。看看你遇到过多少种&#xff1f;▲ 图1 焊接中的常见问题▲ 图2 锡珠▲ 图3 扰动的焊接&#xff1a;在焊接点冷却过程中焊锡移动&#xff0c;造成焊接表面起雾、结晶、粗糙▲ 图4 立碑▲ 图5 冷结&…

给电子类大学生一点求职建议

‍读大学的时候应该想清楚以后要干嘛&#xff0c;不然很可能要面对毕业即失业的窘境。每年近千万毕业生涌向社会&#xff0c;这个数字多少会给你点压力吧。因为我是专业对口的&#xff0c;所以我就从对口的角度&#xff0c;说下我们电子信息类专业学的啥以及怎么学。有很多人在…

Silverlight三维柱状图3D饼图的Silverlight图表组件案例

Silverlight三维柱状图3D饼图的Silverlight图表组件案例 开发环境&#xff1a;Visual Studio 2010 Silverlight 4 SQL2005 Silverlight开发的3D图表组件与及应用的项目截图&#xff1a; 本Silverlight开发的图表控件程序架构简洁清淅&#xff0c;是做二次开发的良好项目框架和核…

oppo专用计算机,OPPO手机助手

OPPO手机助手是OPPO官方最安全的手机助手&#xff0c;将OPPO手机和电脑连接后&#xff0c;可通过“OPPO手机助手”在电脑上管理手机中的应用程序、短信、通讯录(含通话记录)和图片等&#xff0c;还能在电脑上备份手机中的资料。OPPO手机助手是oppo手机的贴心管家。华军软件园提…

EDG牛逼

不管EDG有多牛&#xff0c;明天的早餐可以加个馒头&#xff01;EDG&#x1f42e;&#x1f37a;

[LeetCode][Python][C#]刷题记录 26. 删除排序数组中的重复项

这道题我真的纠结好久&#xff0c;因为没注意那个原地的题目要求&#xff0c;所以很奇怪怎么我电脑运行成功&#xff0c;但是LeetCode上运行就是不对。气哭。 感谢群友lino的帮助。他试了set方法不行&#xff0c;直接喂给我的答案了。。。 题目&#xff1a;26. 删除排序数组中的…

IE9给我带来的惊喜和不解(For Silverlight不解)

今天兴致冲冲的装上了IE9&#xff0c;发现IE9装好后不能打开我的Silverlight。提示我需要安装Silverlight插件 如图 后面深蓝色群里得朋友说他们没有这个问题&#xff0c;但是在64位的情况下会有这个问题&#xff0c;我查看了 我的Silverlight是好的&#xff0c;并且重新安装ru…

不要怕

昨晚很晚没有睡&#xff0c;一个原因是看比赛&#xff0c;一个原因是因为收到一个读者的留言&#xff0c;不是一般的留言&#xff0c;是很长的一段留言。有很多感同深受的地方&#xff0c;所以想着怎么开导他&#xff0c;就写了很多东西给他&#xff0c;一个是希望给他支持&…

H3C交换机设置DHCP中继,配合Linux 服务器为多VLAN提供DHCP地址分配服务

H3C交换机设置DHCP中继&#xff0c;配合Linux 服务器为多VLAN提供DHCP地址分配服务 wanghaoqd 最近在单位用Linux做了一台DHCP服务器&#xff0c;使用H3C S7506R交换机做中继&#xff0c;为两个VLAN提供DHCP服务&#xff0c;经过两个月的测试效果很好。在这里把服务器和交换机的…

图灵书单 双十一超低优惠来袭

大家好&#xff0c;我是写代码的篮球球痴&#xff0c;最近当当网的运营争取了一波小福利&#xff0c;5折买书&#xff0c;如果最近想买书的朋友可以看看&#xff0c;使用下面的优惠码买书可以享受5折优惠。ON SALE又到了双十一购物狂欢节。大家有没有想要的好书一直等到双十一打…

8.在idea中配置maven

1.在IntelliJ IDEA中配置maven 打开-File-Settings 2.我们还可以在勾选一些其他选项 3.我们可以更新一下本地仓库和远程仓库,这个样在pom.xml文件中添加依赖jia包的坐标时就可以很好的提示出来 转载于:https://www.cnblogs.com/holly8/p/9585777.html