初入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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <mach/gpio.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/wait.h>
#include <linux/sched.h>

#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
#include <plat/gpio-cfg-helpers.h>

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_irq\n");
	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_open\n");
	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_read\n");
	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_init\n");

    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_exit\n");
	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   ,可查看到你申请成功的中断。

时间: 2024-08-25 15:06:50

初入android驱动开发之字符设备(四-中断)的相关文章

初入android驱动开发之字符设备(五-定时器)

这个字符设备系列,主要借助较容易上手的字符设备实例,去讲解linux的一些机制,以及驱动中比较常用到的中断.定时器.信号量等一些知识,由于本人自身的知识有限,对于arm的架构体系不太了解,这里,一般这里只讲,如何去用,对于一些原理性的东西不会深究,以后的文章会慢慢的加深. 想想我们当初玩51单片机的时候,那时候按键防抖是一个硬件.软件都需要处理的地方.软件一般就是加延时检测判断.当然,这里我们也可以用到定时器的这个机制,做按键驱动,这里主要还是以按键为例,但不是讲的按键防抖. 1. 定时器的一些

初入android驱动之字符设备(三)

回想当初在大学玩51单片机的时候,实验室的老师第一个任务,就是设计一个基于51单片机的LED流水灯设计,并实现几种样式.第二个任务,就是设计一个基于51单片机的按键控制LED流水灯样式的设计.需要自己设计硬件图.画protel电路图,并设计出PCB,实现keil和proteus的联调,然后焊接电路板,实现其功能.那时候什么都不懂,秉这一股冲劲,各种百度.看书,那时候郭天祥的51单片机视频超火,所以那时候基本以他的书和视频学得,牛人,膜拜. 所以,这主要讲关于按键最简单的字符驱动,通过设置连接该引

驱动开发--【字符设备、块设备简介】【sky原创】

驱动开发   字符设备,块设备,网络设备 字符设备 以字节流的方式访问, 不能随机访问 有例外,显卡.EEPROM可以随机访问 EEPROM可以擦写1亿次,是一种字符设备,可以随机访问 读写是直接访问硬件的 flash 擦写次数有限,一百万次,容易有坏块 块设备 能随机访问 以”块“为单位进行访问 块大小一般为512字节 块的大小由硬件决定 是内核进行数据传输的基本单位 硬盘结构: 格式化分区是以柱面为单位的,即硬盘的柱面 如果有10个盘面,就有十个柱面 对于嵌入式设备 如果是flash的话,结

Linux驱动开发之字符设备模板

/***************************** ** 驱动程序模板* 版本:V1* 使用方法(末行模式下):* :%s/xxx/"你的驱动名称"/g********************************/ #include <linux/mm.h>#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/vmalloc.h>#includ

android驱动开发第三、四章读书笔记

第三章讲解了git及git操作的基本命令 1.git是一款免费.开源的分布式版本控制系统,符合linux的开源思想,且相对于svn cvs等,git有自己的优势,且广受开发者欢迎 2.git的安装: apt-get install git apt-get install git-doc git-svn apt-get install git-email git-gui gitk 3.常见命令: man git—checkout   /  git help git-checkout    查看gi

从Linux内核LED驱动来理解字符设备驱动开发流程

目录 博客说明 开发环境 1. Linux字符设备驱动的组成 1.1 字符设备驱动模块加载与卸载函数 1.2 字符设备驱动的file_operations 结构体中的成员函数 2. 字符设备驱动--设备号注册卸载 2.1 设备号注册 2.2 设备号注销 3. 字符设备驱动--文件操作 参考资料 示例代码 @(从Linux内核LED驱动来理解字符设备驱动开发流程) 博客说明 撰写日期 2018.12.08 完稿日期 2019.10.06 最近维护 暂无 本文作者 multimicro 联系方式 [

Android驱动开发5-8章读书笔记

Android驱动开发读书笔记                                                              第五章 S5PV210是一款32位处理器,具有低功耗的的特点,可为移动设备和一般应用提高性能的微处理器解决方案.它集成了ARM CORTEX-A8核心.实现了ARM架构V7且支持外围设备.他的关键功能是“以带有NEON的cpu子系统为基础的arm”,32/32kb i/d缓存,512kb l2缓存,操作频率800hz为1.1v,1ghz为1.2

【视频】嵌入式Linux/Android驱动开发揭秘(1)触摸屏驱动开发

嵌入式Linux/Android驱动开发揭秘(1)触摸屏驱动开发 专题简介:自1971年,美国人SamHurst发明了世界上第一个触摸传感器以来,触摸屏技术不断革新,给了程序设计师和UI工程师无限的想象空间,它极大改善了终端用户对各种设备的操作方便程度,现在我们的日常生活如手机.平板等,已经很大程度上依赖于和习惯于使用和操作触摸屏.做为工程师,我们很有必要掌握触摸屏的工作原理和软件驱动方法,如果您对一窥如何在嵌入式中操控和使用触摸屏这一司空见惯却又神奇的技术感兴趣,敬请关注! 1.LINUX驱动

Android驱动开发前的准备

最近看了一些Android驱动开发前需要知道的资料,收获很多,接下来就谈谈我自己的一些心得体会. Android在近几年时间发展迅速,已经成为智能手机操作系统的老大.不过,因为Android原生的代码支持的设备并不多,所以我们要想在自己的设备上完美地运行Android就需要另外地开发一些程序,从而可以让Android识别相应设备的硬件,这个过程就成为Android移植. Android移植可以分为两部分:应用移植和系统移植.其中,应用移植是指将Android系统架构的第四层应用程序移植到某一个特