码迷,mamicode.com
首页 > 移动开发 > 详细

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

时间:2015-08-27 18:54:49      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:字符设备 android驱动开发   内核   定时器   软件   

这个字符设备系列,主要借助较容易上手的字符设备实例,去讲解linux的一些机制,以及驱动中比较常用到的中断、定时器、信号量等一些知识,由于本人自身的知识有限,对于arm的架构体系不太了解,这里,一般这里只讲,如何去用,对于一些原理性的东西不会深究,以后的文章会慢慢的加深。

想想我们当初玩51单片机的时候,那时候按键防抖是一个硬件、软件都需要处理的地方。软件一般就是加延时检测判断。当然,这里我们也可以用到定时器的这个机制,做按键驱动,这里主要还是以按键为例,但不是讲的按键防抖。

1. 定时器的一些概念:

节拍率(HZ):它是通过静态预处理定义的,在系统启动时,按照HZ值对硬件进行设置。体系结构不同,HZ值不同。

jiffies:全局变量jiffies用来记录自系统启动以来产生的节拍的总数。启动时内核将它设为0。系统运行时间以秒为单位,等于jiffies/HZ。

定时器: 它是管理内核流逝的时间的基础。内核常需要推后执行某些代码,也就是说,不在当前时间执行。定时器使用简单,一般做一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以。指定的函数将在定时器到期时自动执行。执行结束后,定时器自行撤销。所以,定时器不断的创建和撤销,而且它的运行次数不受限制。

备注:部分neir来自于《linux内核设计与实现》


2. 驱动demo:

#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 struct timer_list button_timer;
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},
};
struct pins_desc *irq_temp;
static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>buttons_irq\n");
	irq_temp = (struct pin_desc *)dev_id;
	mod_timer(&button_timer, jiffies+HZ/100);

	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;
//	wait_event_interruptible(button_waitq, ev_press);
	copy_to_user(buf, &key_val, 1);
	key_val=0;
	ev_press = 0;
	return 1;

}

static void button_timer_function(unsigned long data)
{
	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_timer_function\n");
	struct pin_desc *pindesc = irq_temp;
	unsigned int pinval;
	pinval = gpio_get_value(pindesc->pin);
	printk("irq >>>>>>>>>>>>>>>>>>>>>>>>>>>>pinval =%d \n",pinval);
	if (pinval)
	{	
		key_val = 0x80 | pindesc->key_val;
	}
	else
	{
		key_val = pindesc->key_val;
		
	}
    ev_press = 1;               
 // wake_up_interruptible(&button_waitq);  
}


static struct file_operations button_drv_fops = {
    .owner  =   THIS_MODULE,   
    .open   =   button_drv_open,       
    .read	=	button_drv_read,
    .release =  button_drv_close,
};
unsigned long test=0;
static int button_drv_init(void){
	printk(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>button_drv_init\n");
	
	button_timer.function = button_timer_function;
	button_timer.data=test;
	init_timer(&button_timer);
	add_timer(&button_timer); 
//	setup_timer(&button_timer,button_timer_function,test);  //before 4 method  instead of the one
    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");

2.1 代码简单解析:

定时器操作的步骤:

1.定义一个timer_list结构体:static struct timer_list button_timer;

      2.定时器超时调用的函数:button_timer.function = button_timer_function;

给定时器操作函数传的参数:button_timer.data=test;

根据该定义该timer_list的参数初始化定时器:init_timer(&button_timer);

激活定时器:add_timer(&button_timer); 

   注:setup_timer(&button_timer,button_timer_function,test); 这个可代替上面的2步。

    3. 在中断处理函数中,mod_timer(&button_timer, jiffies+HZ/100); //10ms

注:动态定时器不需要手动释放,mod_timer超时执行之后,就会自动释放。

版权声明:本文为博主原创文章,未经博主允许不得转载。

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

标签:字符设备 android驱动开发   内核   定时器   软件   

原文地址:http://blog.csdn.net/yanleizhouqing/article/details/48027289

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!