Linux_arm驱动之按键模拟脉冲实现定时器的精确计时
- /*****************************************************************
- 内核驱动部分button_ker.c
- *****************************************************************/
- /*
- *应用内核定时器简单实现计时的功能
- *但是内核定时器精确度最小就为50ms
- *较4_button_timer完善功能:利用硬件的定时器计时
- *精确度提高
- *应用linux-2.6.32.2内核里arch/arm/plat_s3/timer.c
- *实现对定时器的精确提高问题
- */
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/init.h>
- #include <linux/delay.h>
- #include <asm/irq.h>
- #include <linux/irq.h>
- #include <linux/interrupt.h>
- #include <asm/uaccess.h>
- #include <linux/timer.h>
- #include <linux/sched.h>
- //*****///
- #include <linux/clk.h>
- #include <plat/regs-timer.h>
- #include <asm/io.h>
- ///****///
- #include <linux/miscdevice.h>
- #include <mach/regs-irq.h>
- //#include <linux/platform_device.h>
- //#include <linux/miscdevice.h>
- //#include <mach/regs-gpio.h>
- #include <linux/wait.h>
- #define DEVICE_NAME "timer_test"
- #define BUTTON_MAJOR 240
- #define TIMER_IOCTL_SET_FREQ 1
- #define TIMER_IOCTL_STOP 0
- static struct semaphore lock;
- struct button_irq_desc{
- int irq;
- unsigned long flags;
- int num;
- char *name;
- };
- //用来指定按键所有的外部中断引脚以及中断出发方式和名字
- static struct button_irq_desc button_irqs[] = {
- {IRQ_EINT0,IRQF_TRIGGER_FALLING,1,"KEY1"},
- {IRQ_EINT1,IRQF_TRIGGER_FALLING,2,"KEY2"},
- {IRQ_EINT2,IRQF_TRIGGER_FALLING,3,"KEY3"},
- {IRQ_EINT4,IRQF_TRIGGER_FALLING,4,"KEY4"},
- };
- static volatile char key_values[4]={'0','0','0','0'};
- static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
- static volatile int ev_press =0;
- static void timer_open(void);
- static void timer_stop(void);
- static inline int timer_interrupt_pending(void);
- static unsigned long get_timer_offset(void);
- ///********************************////
- static volatile bool value=false;
- static volatile unsigned long count = 0;
- static volatile unsigned long freq_value = 500;
- static volatile unsigned long tcnt_value = 50625;
- //定时器中断函数
- static irqreturn_t timer_interrupt_function(int irq,void *dev_id)
- {
- count++;
- //printk("timer_interrupt occur!\n");
- return IRQ_HANDLED;
- }
- //时间处理函数
- static void timer_second_manage(unsigned long second_value)
- {
- static volatile unsigned long ss_value1 = 0;
- static volatile unsigned long ms_value2 = 0;
- static volatile unsigned long us_value3 = 0;
- us_value3 = //(second_value*10000/tcnt_value)*1000/freq_value/10;
- (second_value*1000/freq_value)*10000/tcnt_value/10;
- ms_value2 = (count%freq_value)*1000/freq_value + us_value3/1000;
- ss_value1 = count/freq_value + ms_value2/1000;
- printk("++++++++++++++++++++++++\n");
- printk("used time:%lu n\n",count);
- printk("the second_value :%lu n\n",second_value);
- printk("used time:%lu.%03lu %03lu s\n",ss_value1,
- ms_value2%1000,us_value3%1000);
- printk("++++++++++++++++++++++++\n");
- }
- //外部中断函数
- static irqreturn_t button_interrupt(int irq,void *dev_id){
- unsigned long second_value = 0;
- int num= ((struct button_irq_desc *)dev_id)->num;
- switch(num){
- case 2://17
- value=false;
- timer_stop();
- printk("key1 press\n");
- break;
- case 4://48
- if(!value) {
- value=true; count=0;
- timer_open();
- }else {
- timer_stop();
- second_value=get_timer_offset();
- timer_second_manage(second_value);
- value=false;
- }
- printk("key2 press\n");
- break;
- case 3://18
- value=false;
- timer_stop();
- printk("key3 press\n");
- break;
- case 1://16
- value=false;
- timer_stop();
- printk("key4 press\n");
- break;
- default:
- printk("num error,nothing to do!\n");
- }
- //ev_press=1;
- //wake_up_interruptible(&button_waitq);
- return IRQ_HANDLED;
- }
- //频率设置函数
- //freq: pclk/50/16/65536~pclk/50/16
- //if : pclk=50mhz freq is 1Hz~62500Hz
- //human ear : 20Hz~20000Hz
- //
- static void timer_set_freq(unsigned long freq)
- {
- unsigned long tcon;
- unsigned long tcnt;
- unsigned long tcfg0;
- unsigned long tcfg1;
- struct clk *clk_p;
- unsigned long pclk;
- tcon = __raw_readl(S3C2410_TCON);
- tcfg0 = __raw_readl(S3C2410_TCFG0);
- tcfg1 = __raw_readl(S3C2410_TCFG1);
- tcfg0 &= ~(255<<0);
- //tcfg0 |= (50-1);
- tcfg0 |= 0;
- tcfg1 &= ~(15<<0);
- tcfg1 |= (0<<0);
- __raw_writel(tcfg0,S3C2410_TCFG0);
- __raw_writel(tcfg1,S3C2410_TCFG1);
- clk_p = clk_get(NULL,"pclk");
- pclk = clk_get_rate(clk_p);
- printk("the pclk is : %ld\n",pclk);
- //tcnt = (pclk/50/16)/freq;
- tcnt = (pclk/2)/freq;
- tcnt_value = tcnt;
- printk("the tcnt is %ld\n",tcnt);
- __raw_writel(tcnt,S3C2410_TCNTB(0));
- __raw_writel(0,S3C2410_TCMPB(0));
- //tcon &= ~0x1f;
- tcon &= ~0x1e;
- tcon |=0xb;
- __raw_writel(tcon,S3C2410_TCON);
- tcon &= ~2;
- __raw_writel(tcon,S3C2410_TCON);
- }
- static void timer_open(void)
- {
- unsigned long tcon = 0;
- //printk("***1>tcnto is :%u\n",__raw_readl(S3C2410_TCNTO(0)));
- tcon = __raw_readl(S3C2410_TCON);
- tcon |= 1;
- __raw_writel(tcon,S3C2410_TCON);
- //printk("***2>tcnto is :%u\n",__raw_readl(S3C2410_TCNTO(0)));
- }
- static void timer_stop(void)
- {
- unsigned long tcon;
- tcon = __raw_readl(S3C2410_TCON);
- tcon &= ~1;
- __raw_writel(tcon,S3C2410_TCON);
- }
- #define SRCPND_TIMER0 (1<<(IRQ_TIMER0 - IRQ_TIMER0))
- //中断识别函数 查看在按键产生中断时,定时器是否也在中断中
- static inline int timer_interrupt_pending(void)
- {
- return __raw_readl(S3C2410_SRCPND) & SRCPND_TIMER0;
- }
- //计算中断寄存器中TCNTO0中的偏移量
- static unsigned long get_timer_offset (void)
- {
- unsigned long tdone;
- unsigned long tval;
- tdone = (tcnt_value -__raw_readl(S3C2410_TCNTO(0)));
- if(timer_interrupt_pending()) {
- tval = __raw_readl(S3C2410_TCNTO(0));
- tdone = tcnt_value - tval;
- if(!tval)
- tdone += tcnt_value;
- }
- return tdone;
- }
- static struct irqaction timer_irq = {
- .name = "S3C2410 Timer Tick",
- .flags = IRQF_DISABLED |IRQF_TIMER|IRQF_IRQPOLL,
- .handler = timer_interrupt_function,
- .dev_id = NULL
- };
- static int button_open(struct inode *inode,struct file *file)
- {
- int i,err;
- if(down_trylock(&lock)){
- printk("down_trylock failed!\n");
- return -EBUSY;
- }
- if(setup_irq(IRQ_TIMER0,&timer_irq)){
- printk("setup_irq failed!\n");
- return -EBUSY;
- }
- for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++) {
- err=request_irq(button_irqs[i].irq,button_interrupt,button_irqs[i].flags,
- button_irqs[i].name,(void*)&(button_irqs[i]));
- if(err)
- break;
- }
- if(err) {
- for(--i;i>=0;i--)
- free_irq(button_irqs[i].irq,(void *)&button_irqs[i].num);
- printk("request_irq error!\n");
- return -1;
- }
- disable_irq(IRQ_EINT0);
- disable_irq(IRQ_EINT1);
- disable_irq(IRQ_EINT2);
- disable_irq(IRQ_EINT4);
- set_irq_type(IRQ_EINT0,IRQ_TYPE_LEVEL_LOW);//key4
- set_irq_type(IRQ_EINT1,IRQ_TYPE_EDGE_RISING);//key1
- set_irq_type(IRQ_EINT2,IRQ_TYPE_EDGE_FALLING);//key3
- //set_irq_type(IRQ_EINT4,IRQ_TYPE_EDGE_BOTH);//key2
- set_irq_type(IRQ_EINT4,IRQ_TYPE_EDGE_FALLING);//key2
- enable_irq(IRQ_EINT0);
- enable_irq(IRQ_EINT1);
- enable_irq(IRQ_EINT2);
- enable_irq(IRQ_EINT4);
- return 0;
- }
- static int button_close(struct inode *inode,struct file *file)
- {
- int i;
- for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++) {
- free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);
- }
- remove_irq(IRQ_TIMER0,&timer_irq);
- up(&lock);
- return 0;
- }
- static int button_read(struct file *filp,char __user *buff,
- size_t count,loff_t *offp)
- {
- unsigned long err;
- if(filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- else {
- wait_event_interruptible(button_waitq,ev_press);
- }
- ev_press=0;
- err=copy_to_user(buff,(const void*)key_values,
- min(sizeof(key_values),count));
- return err ? -EFAULT : min(sizeof(key_values),count);
- }
- static int timer_ioctl(struct inode *inode,struct file *file,
- unsigned int cmd,unsigned long arg)
- {
- switch (cmd) {
- case TIMER_IOCTL_SET_FREQ:
- printk("timer_ioctl_set_freq\n");
- if(arg==0)
- return -EINVAL;
- timer_set_freq(arg);
- freq_value = arg;
- break;
- case TIMER_IOCTL_STOP:
- printk("timer_ioctl_stop\n");
- timer_stop();
- break;
- }
- return 0;
- }
- static struct file_operations button_fops = {
- .owner = THIS_MODULE,
- .open = button_open,
- .read = button_read,
- .release = button_close,
- .ioctl = timer_ioctl,
- };
- static struct miscdevice misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = DEVICE_NAME,
- .fops = &button_fops,
- };
- //初始化函数
- static int __init button_init(void)
- {
- init_MUTEX(&lock);
- /*
- if(register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&button_fops)<0) {
- printk(DEVICE_NAME"can't register major number!\n");
- return -1;
- }
- printk(DEVICE_NAME"register sucess!\n");
- */
- if(misc_register(&misc)<0) {
- printk(DEVICE_NAME"can't register major number!\n");
- return -1;
- }
- printk(DEVICE_NAME"register sucess!\n");
- return 0;
- }
- static void __exit button_exit(void)
- {
- timer_stop();
- //unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);
- misc_deregister(&misc);
- }
- module_init(button_init);
- module_exit(button_exit);
- MODULE_LICENSE("GPL");
- /**********************************************************************
- 应用程序部分button_app.c
- **********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #define msleep(x) usleep(x*1000);
- #define TIMER_IOCTL_SET_FREQ 1
- #define TIMER_IOCTL_STOP 0
- int main(int argc,char **argv)
- {
- int fd;
- int ioarg=500;
- int press_cnt[4]={0};
- if((fd=open("/dev/timer_test",0))<0){
- printf("Can't open /dev/timer_test~!");
- return -1;
- }
- printf("sleep begin...\n");
- ioctl(fd,TIMER_IOCTL_SET_FREQ,ioarg);
- //msleep(70000);
- while(1)
- usleep(11111);
- ioctl(fd,TIMER_IOCTL_STOP);
- printf("sleep end...\n");
- close(fd);
- return 0;
- }
- /***************************************************************
- makefile部分
- ****************************************************************/
- ifneq ($(KERNELRELEASE),)
- obj-m := button_ker.o
- else
- KDIR :=/home/kernel/linux-2.6.32.2
- all:
- make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
- arm-linux-gcc button_app.c -o button_app
- clean:
- rm -f *.ko *.o *.mod.o *.mod.c *.symvers modul*
Linux_arm驱动之按键模拟脉冲实现定时器的精确计时的更多相关文章
- Delphi驱动方式WINIO模拟按键 可用
http://www.delphitop.com/html/yingjian/152.html Delphi驱动方式WINIO模拟按键 作者:admin 来源:未知 日期:2010/2/1 1:14: ...
- 字符设备驱动(六)按键poll机制
title: 字符设备驱动(六)按键poll机制 tags: linux date: 2018-11-23 18:57:40 toc: true --- 字符设备驱动(六)按键poll机制 引入 在字 ...
- Linux驱动之按键驱动编写(中断方式)
在Linux驱动之按键驱动编写(查询方式)已经写了一个查询方式的按键驱动,但是查询方式太占用CPU,接下来利用中断方式编写一个驱动程序,使得CPU占有率降低,在按键空闲时调用read系统调用的进程可以 ...
- 驱动开发:内核枚举DpcTimer定时器
在笔者上一篇文章<驱动开发:内核枚举IoTimer定时器>中我们通过IoInitializeTimer这个API函数为跳板,向下扫描特征码获取到了IopTimerQueueHead也就是I ...
- 蜕变成蝶~Linux设备驱动之按键设备驱动
在上述的驱动系列博客中,我们已经了解了关于阻塞和非阻塞.异步通知.轮询.内存和I/O口访问.并发控制等知识,按键设备驱动相对来说是比较简单的,本章内容可以加深我们对字符设备驱动架构.阻塞与非阻塞.中断 ...
- Unity问答——NGUI怎么使用按键模拟鼠标点击?
这篇博客源自我在泰课在线的回答.链接:http://www.taikr.com/group/1/thread/248 问:NGUI怎么模拟用代码模拟控制点击 答: 1. 这个问题问得好.因为在使用按键 ...
- Linux驱动之按键驱动编写(查询方式)
在Linux驱动之LED驱动编写已经详细介绍了一个驱动的编写过程,接着来写一个按键驱动程序,主要是在file_operations结构中添加了一个read函数.还是分以下几步说明 1.查看原理图,确定 ...
- Python键盘按键模拟
有时候我们需要使用python执行一些脚本,可能需要让程序自动按键或自动点击鼠标,下面的代码实现了对键盘的模拟按键, 需要安装pypiwin32,当然也可以直接用ctypes来实现. 输入:pip i ...
- python 模拟按键模拟键盘按键按下放开
python模拟按键 pip install pypiwin32安装库 import win32conimport win32apiimport time 导入 打个比方模拟A win32api.ke ...
随机推荐
- 最全面的 C++ 资源、框架大全
转载自 http://www.codeceo.com/article/cpp-resource-framework.html#0-tsina-1-99850-397232819ff9a47a7b7 ...
- python字符串及其方法详解
首先来一段字符串的基本操作 str1="my little pony" str2="friendship is magic" str3=str1+", ...
- java工程或web工程项目上出现红色感叹号
最近在新公司重新搭建mybatis3+spring4框架的时候出现的问题.确定这个问题是出现在项目的build path里面,但是如果jar包上没出现红X就不知道哪个jar包有问题了,最笨的办法是删除 ...
- OpenGL 矩阵变换
Overview 几何数据--顶点位置,和标准向量(normal vectors),在OpenGL 管道raterization 处理过程之前可通过顶点操作(Vertex Operation)和基本组 ...
- 使用Eclipse上传/下载Git项目
使用Eclipse上传/下载Git项目 前提: Eclipse已安装EGit插件 已拥有GitLab / GitHub / 其它Git托管服务账号 SSH方式 配置 配置Git信息 配置用户信息 Ec ...
- Html5知识
<!DOCTYPE> 声明 <!DOCTYPE>声明有助于浏览器中正确显示网页. 网络上有很多不同的文件,如果能够正确声明HTML的版本,浏览器就能正确显示网页内容. doct ...
- Opencl 并行求和
上周尝试用opencl求极大值,在网上查到大多是求和,所谓的reduction算法.不过思路是一样的. CPP: ; unsigned ; ; ; int nGroup = nGroupSize / ...
- CSS动画与GPU
写在前面 满世界的动画性能优化技巧,例如: 只允许改变transform.opacity,其它属性不要动,避免重新计算布局(reflow) 对动画元素应用transform: translate3d( ...
- Host 'XXX' is not allowed to connect to this MySQL server 解决方案/如何开启MySQL的远程帐号
www.cnblogs.com/zhangzhu/archive/2013/08/22/3274831.html 如何开启MySQL的远程帐号-1)首先以 root 帐户登陆 MySQL 在 Wind ...
- swt controls里的控件list
swt controls里的控件list,怎么显示滚动条,并且滚动条自动移动到最下边时,显示最新内容 package com.jokul; import org.eclipse.swt.widgets ...