初入android驱动开发之字符设备(四-中断)

发布者:BlissfulBliss最新更新时间:2025-02-10 来源: cnblogs关键字:android  驱动开发  中断 手机看文章 扫描二维码
随时随地手机看文章

上一篇讲到android驱动开发中,应用是怎样去操作底层硬件的整个流程,实现了按键控制led的亮灭。当然,这是一个非常easy的实例,只是略微演变一下,就能够得到广泛的应用。


如开发扫描头,应用透过监听上报的按键的键值,监听到,则调用扫描头的模块。成功,则点亮LED灯,并把扫描头解码后的条码信息。通过广播的形式发出。又扯到其他地方,这里主要说说中断。


1. 中断的一些概念


中断,是什么?


中断。能够看成是cpu对特殊事件的一种处理的机制,这类特殊事件一般指紧急事件或者说异常事件。非常easy的一个样例,你拿你手机正在看视频,来了一个电话。你接完电话,还是停在视频。本来你的cpu正在运行看视频这一系列的指令处理。但当接收到电话,会产生一个中断,cpu依据优先级推断。优先级高于当前则停止当前工作。并保存,然后运行中断的处理函数,其中断这一系列的事件处理完成以后。再运行保存在暂停队列中的工作。这是一个外部中断的样例。


那么中断,是指 CPU 在运行程序的过程中,出现了某些突发事件时 CPU 必须暂停运行当前的程序,转去处理突发事件,处理完成后 CPU 又返回原程序被中断的位置并继续运行。依据中断的来源,中断可分为内部中断和外部中断,内部中断的中断源来自 CPU内部(软件中断指令、溢出、除法错误等,比如,操作系统从用户态切换到内核态需借助 CPU 内部的软件中断),外部中断的中断源来自 CPU 外部,由外设提出请求。


中断,实现它的机制?


中断。当外设发出一个中断信号,cpu则依据中断信号,来进行分析处理,依据中断信号所对于的地址。去调用中断处理函数。所以。中断处理函数。是值该中断产生后,cpu应该去紧急运行的事件。


那么,这里主要解说一下中断处理函数的机制。


s5pv210是arm架构的芯片,当中断的资源很的丰富,这里有32个外部中断和其余的gpio中断。一般。实际开发中,中断主要由外设发出。所以,这里我们基本都是用的外部中断。採用外部中断的 CPU 通常为不同的中断分配不同的中断号,当检測到某中断号的中断到来后,就自己主动跳转到与该中断号相应的地址运行。


不同中断号的中断有不同的入口地址。


中断处理机制,,Linux 将中断处理程序分解为两个半部:顶半部(top half)和底半部(bottom half)。


在这两者重要的差别,顶半部,不可被中断,而底半部,能够被新的中断打开。那么,这两者之前的差别,就认为了它们各自独特的特性。顶半部,不可被打断,所以注定它的运行时间要很很的高速,所以一般它仅仅是简单的读取寄存器的中断状态并清楚中断标志,然后就把底半部处理程序挂究竟半部运行队列中。而这样,中断处理的大部分工作就落究竟半部了。由于可被打断,相对来说,时间就比較充足。运行一些耗时的任务。


底半部的三种方式:软中断、tasklet、工作队列。


这里有个博文链接。主要将三种机制以及之间的差异。http://blog.chinaunix.net/uid-20768928-id-5077401.html


中断,当中关键的一些函数?


int request_threaded_irq(unsigned int irq, irq_handler_t handler,


irq_handler_t thread_fn, unsigned long irqflags,


const char *devname, void *dev_id)


irq:中断号,这里由gpio_to_irq()方法得到。

handler:发生中断时首先要运行的硬中断处理函数,这个函数能够通过返回 IRQ_WAKE_THREADED唤醒中断线程,也可返回IRQ_HANDLE不运行中断线程

thread_fn : 中断线程,类似于中断下半部,若传參为null,则和request_irq()一样

qflags:中断标志。备注:IRQF_SHARED 共享中断时,dev_id不能为空。由于释放irq时要区分哪个共享中断。

devname:中断名

dev_id: 传给中断处理函数的參数。



2.简单的实例: 



#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#include

#include

#include


static struct class *buttondrv_class;

static struct device *buttondrv_class_dev;

int major;

volatile unsigned long *GPCCON;

volatile unsigned long *GPCDAT;

//static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

static unsigned char key_val;

static volatile int ev_press = 0;

struct pin_desc{

unsigned int pin;

unsigned int key_val;

};

struct pin_desc pins_desc[2] = {

{S5PV210_GPH3(7), 0x01},

};

static irqreturn_t buttons_irq(int irq, void *dev_id)

{

printk('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>buttons_irqn');

struct pin_desc *pindesc = (struct pin_desc *)dev_id;

unsigned int pinval;

pinval = gpio_get_value(pindesc->pin);

printk('irq >>>>>>>>>>>>>>>>>>>>>>>>>>>>pinval =%d n',pinval);

if (pinval)

{

key_val = 0x80 | pindesc->key_val;

printk('1111 >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d n',key_val);

}

else

{

key_val = pindesc->key_val;

printk('0000 >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d n',key_val);

}

    ev_press = 1;               

//    wake_up_interruptible(&button_waitq);  

return IRQ_RETVAL(IRQ_HANDLED);

}


static int button_drv_open(struct inode *inode, struct file *file)

{

printk('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_openn');

int ret=-1;

s3c_gpio_setpull(S5PV210_GPH3(7), S3C_GPIO_PULL_NONE);

ret = request_threaded_irq(gpio_to_irq(S5PV210_GPH3(7)), NULL,

buttons_irq,

IRQF_TRIGGER_RISING,

's2', &pins_desc[0]);

printk('ret=%d irq=%d >>>>>>>>>>>>>>>>>>>>>>>>>n ',ret,gpio_to_irq(S5PV210_GPH3(7)));

return 0;

}


int button_drv_close(struct inode *inode, struct file *file)

{

free_irq(gpio_to_irq(S5PV210_GPH3(7)), &pins_desc[0]);

return 0;

}


static int button_drv_read(struct file *filp, char __user *buf, 

                                         size_t count, loff_t *offp)

{

printk('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_readn');

if (count != 1)

return -EINVAL;

printk('read >>>>>>>>>>>>>>>>>>>>>>>>>>>key_val =%d n',key_val);

// wait_event_interruptible(button_waitq, ev_press);

copy_to_user(buf, &key_val, 1);

key_val=0;

ev_press = 0;

return 1;


}


static struct file_operations button_drv_fops = {

    .owner  =   THIS_MODULE,   

    .open   =   button_drv_open,       

    .read = button_drv_read,

    .release =  button_drv_close,

};


static int button_drv_init(void){

printk('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_initn');


    GPCCON = (volatile unsigned long *)ioremap(0xE0200C60, 8);

GPCDAT= GPCCON + 1;

if (!GPCCON) {

return -EIO;

}

major = register_chrdev(0, 'button_drv', &button_drv_fops); 

buttondrv_class = class_create(THIS_MODULE, 'buttondrv');

buttondrv_class_dev = device_create(buttondrv_class, NULL, MKDEV(major, 0), NULL, 'button'); 

return 0;

}


static void button_drv_exit(void){

printk('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_exitn');

unregister_chrdev(major, 'button_drv'); 

device_unregister(buttondrv_class_dev);

class_destroy(buttondrv_class);

iounmap(GPCCON);


}


module_init(button_drv_init);

module_exit(button_drv_exit);

MODULE_LICENSE('GPL');


关于代码一些简单的说明:

static DECLARE_WAIT_QUEUE_HEAD(button_waitq)


wake_up_interruptible(&button_waitq)


wait_event_interruptible(button_waitq, ev_press)


这个是等待队列的机制,当有中断的时候。唤醒。把事件增加工作队列中,处理完事件后。继续休眠,直到下次中断。


3.关于一些调试方法:


一般在编写中断的程序,最基本的是要看,gpio口的中断号是否申请成功。这里主要依据打印语句进行调试了。


若驱动程序不报错误了,则可进入android系统下,cat proc/interrupts   ,可查看到你申请成功的中断。


关键字:android  驱动开发  中断 引用地址:初入android驱动开发之字符设备(四-中断)

上一篇:android2.3 -添加自定义按键:作唤醒功能 .
下一篇:安装交叉编译工具链

推荐阅读最新更新时间:2026-03-25 11:21

字符设备驱动程序按键驱动---中断方式
中断函数:包含#include linux/irq.h request_irq(irq,handle,irqflag,name,dev_id) { 1,分配一个irqaction结构体 2、把这个结构体放到irq_desc (action链表)中 3、设置引脚 4、使能中断 } free_irq(irq,dev_id) { 1、irqaciton出链 2、禁止中断 } ----------------------------------------------------------------------------------------------------------------------
[单片机]
字符设备驱动-高级篇按键中断程序驱动
驱动源码: #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include linux/irq.h #include asm/uaccess.h #include asm/irq.h #include asm/io.h #include asm/arch/regs-gpio.h #include asm/hardware.h int major = 0; static struct class *keyd
[单片机]
Android驱动开发5-8章读书笔记
S5PV210是一款32位处理器,具有低功耗的的特点,可为移动设备和一般应用提高性能的微处理器解决方案。它集成了ARM CORTEX-A8核心。实现了ARM架构V7且支持外围设备。他的关键功能是“以带有NEON的cpu子系统为基础的arm”,32/32kb i/d缓存,512kb l2缓存,操作频率800hz为1.1v,1ghz为1.2v。 基于s5pv210处理器,控制寄存器,大多数引脚是有多用途的,每一个引脚要求定义一个功能,控制定义每一个引脚的功能。 数据寄存器,如果引脚配置为输出,输出可以被写到引脚在数据寄存器对应的位中,如果引脚配置为输入,可以从数据寄存器对应的位中读出数据。 Gpio接口应用举例:通过gpio接口的gp
[单片机]
LED字符设备驱动实例及测试代码
驱动代码如下: #include linux/kernel.h //内核头文件 #include linux/init.h //__init等 #include linux/module.h //模块加载的头文件 #include linux/fs.h //file_operations #include linux/errno.h //错误状态常数 #include linux/types.h //size_t,ssize_t等 //--------------cdev---------------- #include linux/cdev.h //-------------class_create,device_c
[单片机]
字符设备驱动(1)代码分析---之register_chrdev
/***************************************************************************** 简 述:简单字符型驱动程序,手动静态分配设备号,手动创建设备节点 ******************************************************************************/ #include linux/module.h #include linux/fs.h #include mach/gpio.h #include linux/irq.h #include linux/kdev_t.h #include li
[单片机]
<font color='red'>字符</font><font color='red'>设备</font><font color='red'>驱动</font>(1)代码分析---之register_chrdev
07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-LED字符设备驱动
一、嵌入式linux字符设备驱动框架 写应用程序的人 不应该去看电路图,但是如何操作硬件呢:调用驱动程序里的open,read,write等来实现。 C库里实现了 open 、read、write上层函数 调用open等:swi val—引发一个异常中断,进入内核异常处理函数。 系统调用接口:根据发生中断的原因,调用处理函数(sys_open,sys_read等sys_open等函数会执行与open相关各种初始化函数,通知调用自己写好的open函数,这里注意应用程序的open不仅仅是调用驱动中的open,其他函数类似,是调用sys_open,sys_open里包含了驱动中实现的open)。 sys_open:根据调
[单片机]
07-S3C2440<font color='red'>驱动</font>学习(一)嵌入式linux<font color='red'>字符</font><font color='red'>设备</font><font color='red'>驱动</font>-LED<font color='red'>字符</font><font color='red'>设备</font><font color='red'>驱动</font>
4412开发板Linux系统编程实战-字符设备控制
在 linux 驱动中字符驱动是必须掌握的,本章主要介绍字符设备应用的程序,无论是学习了后面的知识自己写的字符驱动,还是已有的字符驱动,都需要能够写一些简单的应用程序。 即使从事 linux 驱动的工作,linux 驱动写出来之后,也需要由驱动程序员编写简单的应用进行测试的。 另外,关于驱动部分,迅为电子有专门的驱动实验教程提供给大家学习,大家有了这些基础之后再去学习底层的知识就会很容易了。 在使用手册的第八章,大家可以看到这些 c 程序也是可以在 Android 下面运行的,只不过没有图形界面。 硬件工具 4412开发板PC 机;U 盘或者 TF 卡 软件工具 Ubuntu12.04.2 以及虚拟机;Arm-
[单片机]
4412<font color='red'>开发</font>板Linux系统编程实战-<font color='red'>字符</font><font color='red'>设备</font>控制
1_5.5.4_字符设备驱动程序之LED驱动程序_操作LED_P
在上一节的基础上修改代码,点亮led。 目的:写一个点灯的驱动。 框架; 完善硬件的操作 a.看原理图(确定引脚); b.看2440手册(确定配置); c.写代码:单片机:物理地址;驱动:虚拟地址(使用ioremap映射) 配置:GPFCON open 设置:GPFDAT write 1.建立两个变量 2.在加载时进行ioremap 3.卸载时再unmap 4.在open函数里面配置引脚 5.在write函数里面设置引脚 根据输入的数据控制引脚,如果是1就点灯,是0就关闭。 这里有一个用户空间向内核空间传递数据的函数。 这里buf和count就对应测试程序里面write函数的
[单片机]
1_5.5.4_<font color='red'>字符</font><font color='red'>设备</font><font color='red'>驱动</font>程序之LED<font color='red'>驱动</font>程序_操作LED_P
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

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