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

发布者:SparklingEyes最新更新时间:2024-08-16 来源: cnblogs关键字:GPIO  IRQ  中断按键 手机看文章 扫描二维码
随时随地手机看文章

161             break;

162         default:

163               printk('<0>command error n');

164             printk('<0>ioctl(fd, (unsigned int)command, (unsigned long) arg;n');

165             printk('<0>command: nn');

166             return -1;

167     }

168     return 0;    

169 }

170 

171 /* 这个结构是字符设备驱动程序的核心

172  * 当应用程序操作设备文件时所调用的open、read、write等函数,

173  * 最终会调用这个结构中指定的对应函数

174  */

175 static struct file_operations key_fops = {

176     .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

177     .open   =   key_open,     

178     .read    =    key_read,       

179     .write    =    key_write,       

180     .release=   key_release,

181     .ioctl  =   key_ioctl,    

182 };

183     

184 /*

185  * 执行insmod命令时就会调用这个函数 

186  */

187 static int __init  key_irq_init(void)

188 {

189     printk('<0>nHello,this is %s module!nn',Driver_NAME);

190     //register and mknod

191     major = register_chrdev(0,Driver_NAME,&key_fops);

192     drv_class = class_create(THIS_MODULE,Driver_NAME);

193     drv_class_dev = device_create(drv_class,NULL,MKDEV(major,0),NULL,DEVICE_NAME);    /*/dev/key_query*/

194 

195     //set all pins to GPIO mod  ALF5

196     mxc_request_iomux(GPIO2_21, MUX_CONFIG_ALT5);

197     mxc_request_iomux(GPIO3_15, MUX_CONFIG_ALT5);

198     mxc_request_iomux(GPIO2_10, MUX_CONFIG_ALT5);

199     mxc_request_iomux(GPIO2_11, MUX_CONFIG_ALT5);

200     mxc_request_iomux(GPIO2_8, MUX_CONFIG_ALT5);

201     mxc_request_iomux(GPIO2_9, MUX_CONFIG_ALT5);

202     mxc_request_iomux(GPIO2_6, MUX_CONFIG_ALT5);

203     mxc_request_iomux(GPIO2_7, MUX_CONFIG_ALT5);

204     //request IOMUX GPIO

205     gpio_request(IOMUX_TO_GPIO(GPIO2_21), 'GPIO2_21');

206     gpio_request(IOMUX_TO_GPIO(GPIO3_15), 'GPIO3_15');

207     gpio_request(IOMUX_TO_GPIO(GPIO2_10), 'GPIO2_10');

208     gpio_request(IOMUX_TO_GPIO(GPIO2_11), 'GPIO2_11');

209     gpio_request(IOMUX_TO_GPIO(GPIO2_8), 'GPIO2_8');

210     gpio_request(IOMUX_TO_GPIO(GPIO2_9), 'GPIO2_9');

211     gpio_request(IOMUX_TO_GPIO(GPIO2_6), 'GPIO2_6');

212     gpio_request(IOMUX_TO_GPIO(GPIO2_7), 'GPIO2_7');

213     

214 

215     return 0;

216 }

217 

218 /*

219  * 执行rmmod命令时就会调用这个函数 

220  */

221 static void __exit key_irq_exit(void)

222 {

223     printk('<0>nGoodbye,%s!nn',Driver_NAME);

224 

225     unregister_chrdev(major,Driver_NAME);

226     device_unregister(drv_class_dev);

227     class_destroy(drv_class);

228 

229     /* free gpios */

230     mxc_free_iomux(GPIO2_21, MUX_CONFIG_ALT5);

231     mxc_free_iomux(GPIO3_15, MUX_CONFIG_ALT5);

232     mxc_free_iomux(GPIO2_10, MUX_CONFIG_ALT5);

233     mxc_free_iomux(GPIO2_11, MUX_CONFIG_ALT5);

234     mxc_free_iomux(GPIO2_8, MUX_CONFIG_ALT5);

235     mxc_free_iomux(GPIO2_9, MUX_CONFIG_ALT5);

236     mxc_free_iomux(GPIO2_6, MUX_CONFIG_ALT5);

237     mxc_free_iomux(GPIO2_7, MUX_CONFIG_ALT5);

238 

239     gpio_free(IOMUX_TO_GPIO(GPIO2_21));

240     gpio_free(IOMUX_TO_GPIO(GPIO3_15));

241     gpio_free(IOMUX_TO_GPIO(GPIO2_10));

242     gpio_free(IOMUX_TO_GPIO(GPIO2_11));

243     gpio_free(IOMUX_TO_GPIO(GPIO2_8));

244     gpio_free(IOMUX_TO_GPIO(GPIO2_9));

245     gpio_free(IOMUX_TO_GPIO(GPIO2_6));

246     gpio_free(IOMUX_TO_GPIO(GPIO2_7));

247 

248 }

249 

250 /* 这两行指定驱动程序的初始化函数和卸载函数 */

251 module_init(key_irq_init);

252 module_exit(key_irq_exit);

253 

254 /* 描述驱动程序的一些信息,不是必须的 */

255 MODULE_AUTHOR('Lover雪');

256 MODULE_VERSION('0.1.0');

257 MODULE_DESCRIPTION('IMX257 key Driver');

258 MODULE_LICENSE('GPL');


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


如上面的程序所示:


配置中断

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


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


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

 2 

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

 4 

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

 6 

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

 8 

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

10 

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


read函数中睡眠

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


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

3 wait_event_interruptible(key_interrupt_wait,ev_press);

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

 

中断唤醒程序

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


 1 /* 中断程序key_irq */

 2 

 3 static irqreturn_t key_irq(int irq, void *dev_id)

 4 {

 5     //发生了中断

 6     printk('<0>function interrupt key_irq!nn');

 7 

 8     ev_press = 1;

 9 

10     wake_up_interruptible(&key_interrupt_wait);

11     return IRQ_RETVAL(IRQ_HANDLED);

12 }



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


 1 #include

 2 #include

 3 #include

 4 #include

 5 #include

 6 #include

 7 #include

 8 #include

 9 #include

10 #include

11 #include

12 #include

13 

14 #include 'mx257_gpio.h'

15 

16 #define key_input     0

17 #define version       1

18 

19 

20 int main(int argc, char **argv)

21 {

22     int fd;

23     int i=0,cnt=0;

24     unsigned char key_vals[8];

25     

26     fd = open('/dev/key_interrupt',O_RDWR);

27     if(fd < 0){

28         printf('can't open !!!n');

29     }

30     ioctl(fd,version,NULL);

31     ioctl(fd,key_input,NULL);

32     while(1){

33         read(fd, key_vals,sizeof(key_vals));

34         printf('%04d key pressed: %d %d %d %d %d %d %d %dn',cnt++,key_vals[0],key_vals[1],key_vals[2],key_vals[3],key_vals[4],key_vals[5],key_vals[6],key_vals[7]);    

35     }

36     return 0;

37 }

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


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


Insmod


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


cat /proc/interrupts

 

结果如图所示:

 

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

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

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


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


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

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


分析:


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

头文件包含为linux/inerrupt.h


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


编译后结果如图所示:

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

编译通过,如图所示

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


总结一下第一个问题:


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


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


error: 'TASK_INTERRUPTIBLE' undeclared


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

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


#include


#include

例外附上:


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


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


[1] [2]
关键字:GPIO  IRQ  中断按键 引用地址:IMX257实现GPIO-IRQ中断按键驱动程序

上一篇:【改进】IMX257实现GPIO-IRQ中断按键获取键值驱动程序
下一篇:IMX257实现GPIO-查询按键驱动程序

推荐阅读最新更新时间:2024-11-10 20:24

gpio
GPIO(英语:General-purpose input/output),通用型之输入输出的简称,功能类似 8051 的P0—P3,其接脚可以供使用者由程控自由使用,PIN脚依现实考量可作为通用输入(GPI)或通用输出(GPO)或通用输入与输出(GPIO),如当clk generator, chip select等。 既然一个 引脚 可以用于输入、输出或其他特殊功能,那么一定有 寄存器 用来选择这些功能。对于输入,一定可以通过读取某个寄存器来确定引脚电位的高低;对于输出,一定可以通过写入某个寄存器来让这个引脚输出高电位或者低电位;对于其他特殊功能,则有另外的寄存器来控制它们。 优点 GPIO的优点(端口扩展器)
[嵌入式]
STM32——GPIO的CRL、CRH和CNF与MODE的关系
GPIO的CRL、CRH和CNF与MODE的关系 STM32的CRL控制着每个IO端口的位占用CRL的4个位,高两位为CNF,低两位为MODE。 CRH的作用和CRL完全一样,只是CRL控制的是低8位输出口,而CRH控制的是高8位输出口。
[单片机]
STM32F10x GPIO引脚说明
此篇文章重点讨论STM32的GPIO的配置种类以及上拉输入、下拉输入、浮空输入、模拟输入的区别 经过学习STM32发现,GPIO有8种工作方式 输入模式:输入浮空、输入上拉、输入下拉、模拟输入 输出模式:开漏输出、开漏复用功能、推挽式输出、推挽式复用功能 输入模式参照图片来讲 浮空输入:浮空输入状态下上拉电阻和下拉电阻都是断开的,信号经过I/O端口——施密特触发器——输入数据寄存器——CPU读取 上拉输入:相比浮空输入状态,就是上拉电阻闭合(下拉电阻仍然处于断开状态) 下拉输入:相比浮空输入状态,就是下拉电阻闭合(上拉电阻仍然处于断开状态) 模拟输入:上拉电阻和下拉电阻都处于断开状态,并且信号不是经过施密特触发器,而是直接进入
[单片机]
STM32F10x <font color='red'>GPIO</font>引脚说明
ARM-Linux下的GPIO中断程序
为了调试ARM板上的GPIO引脚中断效果,以便在后续项目使用ARM与ZLG7290按键LED中断芯片连接中随意选择空闲的GPIO引脚来作为ZLG7290的中断信号线,特意编写了一个小的Linux GPIO中断驱动程序下载到开发板上做实验。经验证,这种软件中断方式也还差强人意。下面贴出自己编写的不成熟的代码,见笑( 实验的硬件电路为ARM GPIO的PB17连接一个共阴LED,PB18与PB19连接,PB18由中断驱动设置为低电平触发,PB19由GPIO驱动程序控制,上层应用程序通过驱动控制PB19高低电平变化,从而引发PB18发生中断,中断程序中控制PB17的LED亮和灭。 Linux中断驱动部分: /*
[单片机]
LPC2478的GPIO使用详解
GPIO使用 LPC2478的GPIO是不能断开时钟的,上电就连接.处理GPIO主要就下面几步 1. 设置为普通IO模式 2. 设置输入输出方向 3. 设置值 以下寄存器 用于选择管脚是基本输入输出还是复用功能 设置管脚是否具有上拉电阻 其中,LPC的管脚分为两种,一种是传统GPIO还有一种是高速GPIO,其实严格来说,所有的管脚都是高速管脚,但是为了兼容之前的软件和程序,可以使用之前的访问模式访问GPIO,说明如下 设置管脚方向 这个寄存器只能写1有效,写1将对应管脚高电平,写0不会将对应管脚低电平 需要将对应管脚低电平靠这个寄存器,但是这个寄存器不能控制管脚高电平
[单片机]
LPC2478的<font color='red'>GPIO</font>使用详解
stm32.cube(三)——HAL.GPIO
一、总览 HAL层里的库函数和大家熟悉的stm32lib基本上是一致的。一般来说一个cpu外设的操作函数分成两部分,分别是init和operation。 来看一个cube里的例子: static GPIO_InitTypeDef GPIO_InitStruct; int main(void) { /* This sample code shows how to use GPIO HAL API to toggle LED2 IO in an infinite loop. */ /* STM32F103xB HAL library initialization: - Configure the Flash p
[单片机]
关于STM32F4xx的GPIO
STM32F4xx的GPIO可以分为GPIOA到GPIOK个端口,每个端口有16个IO口。 对每个GPIO端口,STM32F4xx安排了4个32位配置寄存器(GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR、GPIOx_PUPDR)用于对端口内的每个IO口进行配置,安排2个32位数据寄存器(GPIOx_IDR、GPIOx_ODR)用于每个端口的数据输入输出存储,此外,还安排了1个32位置位/复位寄存器(GPIOx_BSRR),1个32位锁定寄存器(GPIOx_LCKR)和2个32位复用功能选择寄存器(GPIOx_AFRH、GPIOx_AFRL)。 对每一个IO口而言,用户可以根据需要将其配置为通
[单片机]
怎样用STM32单片机的GPIO控制LED显示状态
用STM32 的配置GPIO 来控制LED 显示状态,可用ODR,BSRR,BRR 直接来控制引脚输出状态。 ODR寄存器可读可写:既能控制管脚为高电平,也能控制管脚为低电平。 管脚对于位写1 gpio 管脚为高电平,写 0 为低电平 BSRR 只写寄存器:[color=Red]既能控制管脚为高电平,也能控制管脚为低电平。 对寄存器高 16bit 写1 对应管脚为低电平,对寄存器低16bit写1对应管脚为高电平。写 0 ,无动作BRR 只写寄存器:只能改变管脚状态为低电平,对寄存器 管脚对于位写 1 相应管脚会为低电平。写 0 无动作。 刚开始或许你跟我一样有以下疑惑: 1.既然ODR 能控制管脚高低电平为什么还需
[单片机]
怎样用STM32单片机的<font color='red'>GPIO</font>控制LED显示状态
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved