IMX257实现GPIO-IRQ中断按键驱动程序

IMX257实现GPIO-IRQ中断按键驱动程序

2015-02-18 李海沿

????昨天我们已经实现了中断查询的方式实现GPIO按键驱动程序,但是,有一个缺点就是,当我们把应用程序放在后台执行时,即便没有按键,应用程序while循环中的read函数也不断的在运行,严重的导致了CPU资源的浪费。

????本文中,我们在前面按键查询驱动程序的基础上来修改。

????大概介绍一下设计思路吧:

????和前面的差不多,当我们加载驱动时,首先在init函数中,对GPIO功能进行模式设置,都设置为GPIO模式,然后申请GPIO引脚的内存,

接着,当我们应用程序使用ioctl函数的gpio_input命令时,将所有的GPIO引脚设置为输入,并且22K上拉模式,当应用程序使用read函数读取时,如果按键没有按下,则会在read函数中睡眠(可被中断唤醒),交出CPU的使用权,当按键按下时,首先会在中断程序中进行唤醒操作,在read函数中接着运行,读取GPIO引脚的电平,并且将数据从内核空间传递到用户空间中,并且打印出来。

????最后,当我们不要用驱动程序时,rsmod会调用exit函数,释放所有我们已经申请的GPIO资源。

????好了,大概的思路就是这样,和前面的查询驱动程序,差不多,只不过就加了一个中断,和睡眠而已。

附上驱动程序代码:

xxx

?

大概讲解一下中断的实现:

如上面的程序所示:

  1. 配置中断

当我们要使用中断时,第一步肯定是要配置中断。所以,在我们的ioctl函数的gpio_input命令中,如下代码主要的功能就是配置各个引脚为中断模式,下降沿触发,中断的名称为key_GPIOm_n。

还有一个就是注册中断函数,告诉内核,我们中断的处理函数为key_irq。


Request_irq(IOMUX_TO_IRQ(GPIO2_7), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_7", (void *)1);

request_irq(IOMUX_TO_IRQ(GPIO2_6), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_6", (void *)1);

request_irq(IOMUX_TO_IRQ(GPIO2_9), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_9", (void *)1);

request_irq(IOMUX_TO_IRQ(GPIO2_10), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_10", (void *)1);

request_irq(IOMUX_TO_IRQ(GPIO2_11), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_11", (void *)1);

request_irq(IOMUX_TO_IRQ(GPIO2_21), key_irq, IRQF_TRIGGER_FALLING, "key_GPIO2_21", (void *)1);

  1. read函数中睡眠

中断配置好后,就开始使用中断,当我们用户程序read函数到来,而我们的按键却并没有按下时,为了节省资源,我们就可以让程序睡眠SLEEP,


//如果按键没有按下,没有中断,休眠

wait_event_interruptible(key_interrupt_wait,ev_press);

ev_press = 0; //清除中断时设置的ev_pre = 1

?

  1. 中断唤醒程序

当中断到来时,由于前面我们的程序在read函数中已经处于睡眠态了,所以我们中断的作用就是把我们的程序唤醒,在read函数中继续运行,读取相应的数据


/* 中断程序key_irq */

static irqreturn_t key_irq(int irq, void *dev_id)

{

????//发生了中断

????printk("<0>function interrupt key_irq!\n\n");

????ev_press = 1;

????wake_up_interruptible(&key_interrupt_wait);

?

????return IRQ_RETVAL(IRQ_HANDLED);

}

?

?

接下来,附上应用程序源代码;

xxx

?

应用程序中,我们就不需要利用应用程序来检测是否按下,可以把检测的if判断语句去掉。

?

接下来的编译工作就不赘述:


Insmod

?

./test/key_test & (这里加 & 的意思是,在后台执行)

?

cat /proc/interrupts

?

结果如图所示:

?

查看中断,可以看到我们前面设置的中断名字。

?

当我们的按键按下,应用程序在后台检测到,就会打印出我们当前的引脚电平

?

?

?

?

?

程序编写过程中碰到的错误:

?


error: expected ‘=‘, ‘,‘, ‘;‘, ‘asm‘ or ‘__attribute__‘ before ‘{‘ token

?

  1. : 很难想象,当我们的函数名字与头文件中的函数发生冲突时,gcc报错报的不是名字冲突,而是告诉我们前面缺少了;或者括号,

因为这个问题,耗费了我足足一个下午加一个晚上的时间,事实证明,写程序时一定要仔细,否则查找错误的过程真的很痛苦,花的时间远比重新编写程序的时间多得多。

分析:

开始,我们的init函数名称为key_init,

头文件包含为linux/inerrupt.h

经过测试使用 linux/rtc.h 或者 linux/serial_reg.h 时效果一样。

编译后结果如图所示:

?

而当我们将函数名修改掉:

编译通过,如图所示

这里出现问题的原因时,我们的key_init函数,和我们内核中包含有free_irq的头文件中的函数发生冲突。

?

总结一下第一个问题:

首先,要声明并不是所有的这样的错误都是如上面的一样。

有的时候,可能真的是因为前面的代码的语法错误而导致的,具体的情况要看具体的代码,具体分析。

?

?


error: ‘TASK_INTERRUPTIBLE‘ undeclared

  1. :第二个问题就是典型的头文件未包含的问题。

因为在sched.h 头文件中包含了它的申明。

#include <linux/sched.h>

#include <linux/interrupt.h>

例外附上:

本人研究linux内核源代码时,发现很多文件中使用了 free_irq等中断申请和释放的函数,但是却未包含inrerrupt.h 的头文件,进过本人测试总结,

可以使用interrupt.h,rtc.h, seria_reg.h 达到同样的效果,因为这些头文件中包含了interrupt.h。

?

(ps:笔者认为,当我们碰到问题时,一定要有钻研精神,可能会花点时间,但这样当我们解决问题后,就会有一种豁然开朗的感觉,瞬间感觉自己又学到了知识,有助于自己的能力的提升,千万千万别一碰到问题就去问那些大神,大神会很无奈的,并且自己的查错能力也没法提升)

?

?

?

时间: 2025-01-16 09:35:44

IMX257实现GPIO-IRQ中断按键驱动程序的相关文章

7.自己写中断方式按键驱动程序

request_irq()和free_irq()分析完毕后,接下来开始编写上升沿中断的按键驱动 如下图,需要设置4个按键的EINT0, EINT2, EINT11, EINT19的模式为双边沿,且设置按键引脚为中断引脚 这里我们只需要使用request_irq函数就行了, 在request_irq函数里会初始chip->set_type(设置引脚和中断模式) 1.首先添加头文件 #include <linux/irq.h> //要用到IRQ_EINT0和IRQT_RISING这些变量 2

20150218【改进】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 一.使用struct pin_desc 管理按键的值 1.定义结构体 2.将前面我们申请中断时写的(void *)1修改为 &pins_desc[n] 在ioctl中,设置中断中修改 在key_release中释放中修改 3.在中断程序中利用我们定义的struc pins_desc判断并得到按键的值 4.得到按键键值后,唤醒程序,在read函数中返回键值 附上驱动源程序: 1 /***********

20150218【改进信号量】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进信号量]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 前面我们使用POLL查询方式来实现GPIO-IRQ按键中断程序 这里我们来使用信号量,让我们的驱动同时只能有一个应用程序打开. 一.首先在前面代码的基础上来一个简单的信号 1.定义一个全局的整形变量 2.在打开函数中,每次进入打开函数canopen都自减1, 3.当我们不使用时,在realease 中canopen自加1 4.这样就实现了一个简单的信号量,我们编译,测试 当我们使用两个应用程序来

20150218【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序

[改进Poll定时查询]IMX257实现GPIO-IRQ中断按键获取键值驱动程序 2015-02-18 李海沿 按键驱动程序中,如果不使用read函数中使程序休眠的,而是还是使用查询方式的话,可以使用Poll函数,来控制一定时间内,如果有按键发生,则立即返回键值. 同时,poll也可以同时监控多个(比如说按键,鼠标,等)一旦发生事件则立即返回. 我们在linux查看帮助: 从帮助中的说明得知, poll, ppoll - wait for some event on a file descrip

内核中断及按键驱动程序

寒假Linux学习笔记 2015年1月25日 晚 20:00 一.内核中断处理 进程上下文:应用程序主动调用内核驱动的程序的跳转 中断上下文:中断由硬件产生的,与应用程序无关 ? ? 1.注册中断 Int request_irq(unsigned int irq, ????????????//中断号 void (*handler)(int ,void *, struct pt_regs*),????//中断处理函数 unsigned long flags,????????????//与中断处理管

20150216 IMX257实现GPIO-查询按键驱动程序

20150216IMX257实现GPIO-查询按键驱动程序 2015-02-16 李海沿 前面我们介绍了简单的通用字符设备驱动程序,接下来,我们在它的基础上来实现GPIO的查询按键功能. 先附上驱动程序代码 1 /****************************** 2 linux key_query 3 *****************************/ 4 #include <linux/module.h> 5 #include <linux/init.h>

在Linux下的中断方式读取按键驱动程序

// 在Linux下的中断方式读取按键驱动程序 //包含外部中断 休眠 加入poll机制 // 采用异步通知的方式 // 驱动程序发 ---> app接收 (通过kill_fasync()发送) // 为了使设备支持异步通知机制,驱动程序中涉及以下3项工作: // 1. 支持F_SETOWN命令,能在这个控制命令处理中设置filp->f_owner为对应进程ID. // 不过此项工作已由内核完成,设备驱动无须处理. // 2. 支持F_SETFL命令的处理,每当FASYNC标志改变时,驱动程序

20150220【改进定时器】IMX257实现GPIO-IRQ定时器消抖驱动程序

[改进定时器]IMX257实现GPIO-IRQ定时器消抖驱动程序 2015-02-20 李海沿 前面我们的GPIO-IRQ按键的驱动程序实现了中断,阻塞,信号量,poll查询等功能,具体请进博客http://www.cnblogs.com/lihaiyan/ 本文,我们还是在前面的按键驱动程序的基础上,引入定时器,来消除抖动. 一.内核定时器详解 1.timer_list结构体 在/include/linux/timer.h中. struct timer_list { struct list_h

基于输入子系统的按键驱动程序

输入子系统框图: 基于输入子系统的按键驱动程序步骤: 1.分配input_dev结构体 2.设置这个结构体 3.注册 4.硬件相关操作(有数据产生时调用 input_event来上报). 1.分配input_dev结构体 首先要定义这个结构体:static struct input_dev *buttons_dev; 然后在init函数中进行以下操作:buttons_dev = input_allocate_device(); 2.设置这个结构体 使用set_bit来设置这一个位,能设置以下参数