Linux_arm驱动之按键模拟脉冲实现定时器的精确计时 (实例)

[cpp] view plain copy
  1. /***************************************************************** 
  2.                        内核驱动部分button_ker.c 
  3. *****************************************************************/  
  4.   
  5. /* 
  6.  *应用内核定时器简单实现计时的功能 
  7.  *但是内核定时器精确度最小就为50ms 
  8.  *较4_button_timer完善功能:利用硬件的定时器计时 
  9.  *精确度提高 
  10.  *应用linux-2.6.32.2内核里arch/arm/plat_s3/timer.c 
  11.  *实现对定时器的精确提高问题 
  12.  */  
  13. #include <linux/module.h>  
  14. #include <linux/kernel.h>  
  15. #include <linux/fs.h>  
  16. #include <linux/init.h>  
  17. #include <linux/delay.h>  
  18. #include <asm/irq.h>  
  19. #include <linux/irq.h>  
  20. #include <linux/interrupt.h>  
  21. #include <asm/uaccess.h>  
  22. #include <linux/timer.h>  
  23. #include <linux/sched.h>  
  24.   
  25. //*****///  
  26. #include <linux/clk.h>  
  27. #include <plat/regs-timer.h>  
  28. #include <asm/io.h>  
  29. ///****///  
  30. #include <linux/miscdevice.h>  
  31. #include <mach/regs-irq.h>  
  32. //#include <linux/platform_device.h>  
  33. //#include <linux/miscdevice.h>  
  34. //#include <mach/regs-gpio.h>  
  35.   
  36. #include <linux/wait.h>  
  37. #define DEVICE_NAME "timer_test"  
  38. #define BUTTON_MAJOR 240  
  39.   
  40. #define TIMER_IOCTL_SET_FREQ  1  
  41. #define TIMER_IOCTL_STOP      0  
  42.   
  43. static struct semaphore lock;  
  44.   
  45. struct button_irq_desc{  
  46.     int irq;  
  47.     unsigned long flags;  
  48.     int num;  
  49.     char *name;  
  50. };  
  51. //用来指定按键所有的外部中断引脚以及中断出发方式和名字  
  52. static struct button_irq_desc button_irqs[] = {  
  53.     {IRQ_EINT0,IRQF_TRIGGER_FALLING,1,"KEY1"},  
  54.     {IRQ_EINT1,IRQF_TRIGGER_FALLING,2,"KEY2"},  
  55.     {IRQ_EINT2,IRQF_TRIGGER_FALLING,3,"KEY3"},  
  56.     {IRQ_EINT4,IRQF_TRIGGER_FALLING,4,"KEY4"},  
  57. };  
  58. static volatile char key_values[4]={'0','0','0','0'};  
  59. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  
  60. static volatile int ev_press =0;  
  61.   
  62. static void timer_open(void);  
  63. static void timer_stop(void);  
  64. static inline int timer_interrupt_pending(void);  
  65. static unsigned long get_timer_offset(void);  
  66. ///********************************////  
  67. static volatile bool value=false;  
  68. static volatile unsigned long count = 0;  
  69. static volatile unsigned long freq_value = 500;  
  70. static volatile unsigned long tcnt_value = 50625;  
  71. //定时器中断函数  
  72. static irqreturn_t timer_interrupt_function(int irq,void *dev_id)  
  73. {  
  74.     count++;  
  75.     //printk("timer_interrupt occur!\n");  
  76.     return IRQ_HANDLED;  
  77. }  
  78. //时间处理函数  
  79. static void timer_second_manage(unsigned long second_value)  
  80. {  
  81.     static volatile unsigned long ss_value1 = 0;  
  82.     static volatile unsigned long ms_value2 = 0;  
  83.     static volatile unsigned long us_value3 = 0;  
  84.       
  85.     us_value3 = //(second_value*10000/tcnt_value)*1000/freq_value/10;  
  86.                     (second_value*1000/freq_value)*10000/tcnt_value/10;  
  87.                   
  88.     ms_value2 = (count%freq_value)*1000/freq_value + us_value3/1000;  
  89.     ss_value1 = count/freq_value + ms_value2/1000;  
  90.   
  91.     printk("++++++++++++++++++++++++\n");  
  92.     printk("used time:%lu n\n",count);  
  93.     printk("the second_value :%lu n\n",second_value);  
  94.     printk("used time:%lu.%03lu %03lu s\n",ss_value1,  
  95.                                 ms_value2%1000,us_value3%1000);  
  96.     printk("++++++++++++++++++++++++\n");  
  97.   
  98. }  
  99. //外部中断函数  
  100. static irqreturn_t button_interrupt(int irq,void *dev_id){  
  101.     unsigned long second_value = 0;  
  102.     int num= ((struct button_irq_desc *)dev_id)->num;  
  103.     switch(num){  
  104.         case 2://17  
  105.             value=false;  
  106.             timer_stop();  
  107.             printk("key1 press\n");  
  108.             break;  
  109.         case 4://48  
  110.             if(!value) {  
  111.                 value=true; count=0;  
  112.                 timer_open();  
  113.             }else {  
  114.                 timer_stop();  
  115.                 second_value=get_timer_offset();  
  116.                 timer_second_manage(second_value);  
  117.                 value=false;  
  118.             }  
  119.             printk("key2 press\n");  
  120.             break;  
  121.         case 3://18  
  122.             value=false;  
  123.             timer_stop();  
  124.             printk("key3 press\n");  
  125.             break;  
  126.         case 1://16  
  127.             value=false;  
  128.             timer_stop();  
  129.             printk("key4 press\n");  
  130.             break;  
  131.         default:  
  132.             printk("num error,nothing to do!\n");  
  133.           
  134.     }  
  135.     //ev_press=1;  
  136.     //wake_up_interruptible(&button_waitq);  
  137.     return IRQ_HANDLED;  
  138. }  
  139.   
  140. //频率设置函数  
  141. //freq: pclk/50/16/65536~pclk/50/16  
  142. //if  : pclk=50mhz freq is 1Hz~62500Hz  
  143. //human ear : 20Hz~20000Hz  
  144. //  
  145. static void timer_set_freq(unsigned long freq)  
  146. {  
  147.     unsigned long tcon;  
  148.     unsigned long tcnt;  
  149.     unsigned long tcfg0;  
  150.     unsigned long tcfg1;  
  151.       
  152.     struct clk *clk_p;  
  153.     unsigned long pclk;  
  154.   
  155.     tcon  = __raw_readl(S3C2410_TCON);  
  156.     tcfg0 = __raw_readl(S3C2410_TCFG0);  
  157.     tcfg1 = __raw_readl(S3C2410_TCFG1);  
  158.   
  159.     tcfg0 &= ~(255<<0);  
  160.     //tcfg0 |= (50-1);  
  161.     tcfg0 |= 0;  
  162.   
  163.     tcfg1 &= ~(15<<0);  
  164.     tcfg1 |= (0<<0);  
  165.   
  166.     __raw_writel(tcfg0,S3C2410_TCFG0);  
  167.     __raw_writel(tcfg1,S3C2410_TCFG1);  
  168.   
  169.     clk_p = clk_get(NULL,"pclk");  
  170.     pclk  = clk_get_rate(clk_p);  
  171.     printk("the pclk is : %ld\n",pclk);  
  172.     //tcnt  = (pclk/50/16)/freq;  
  173.     tcnt  = (pclk/2)/freq;  
  174.     tcnt_value = tcnt;  
  175.     printk("the tcnt is %ld\n",tcnt);  
  176.      __raw_writel(tcnt,S3C2410_TCNTB(0));  
  177.      __raw_writel(0,S3C2410_TCMPB(0));  
  178.   
  179.     //tcon &= ~0x1f;  
  180.     tcon &= ~0x1e;  
  181.     tcon |=0xb;  
  182.   
  183.      __raw_writel(tcon,S3C2410_TCON);  
  184.     tcon &= ~2;  
  185.     __raw_writel(tcon,S3C2410_TCON);  
  186.   
  187. }  
  188. static void timer_open(void)  
  189. {  
  190.     unsigned long tcon = 0;  
  191.     //printk("***1>tcnto is :%u\n",__raw_readl(S3C2410_TCNTO(0)));  
  192.     tcon = __raw_readl(S3C2410_TCON);  
  193.     tcon |= 1;  
  194.     __raw_writel(tcon,S3C2410_TCON);  
  195.     //printk("***2>tcnto is :%u\n",__raw_readl(S3C2410_TCNTO(0)));  
  196.   
  197. }  
  198. static void timer_stop(void)  
  199. {  
  200.     unsigned long tcon;  
  201.     tcon = __raw_readl(S3C2410_TCON);  
  202.     tcon &= ~1;  
  203.     __raw_writel(tcon,S3C2410_TCON);  
  204.   
  205. }  
  206. #define SRCPND_TIMER0 (1<<(IRQ_TIMER0 - IRQ_TIMER0))  
  207. //中断识别函数 查看在按键产生中断时,定时器是否也在中断中  
  208. static inline int timer_interrupt_pending(void)  
  209. {  
  210.     return __raw_readl(S3C2410_SRCPND) & SRCPND_TIMER0;  
  211. }  
  212. //计算中断寄存器中TCNTO0中的偏移量  
  213. static unsigned long get_timer_offset (void)  
  214. {  
  215.     unsigned long tdone;  
  216.     unsigned long tval;  
  217.   
  218.     tdone = (tcnt_value -__raw_readl(S3C2410_TCNTO(0)));  
  219.     if(timer_interrupt_pending()) {  
  220.         tval = __raw_readl(S3C2410_TCNTO(0));  
  221.         tdone = tcnt_value - tval;  
  222.         if(!tval)  
  223.             tdone += tcnt_value;  
  224.     }  
  225.     return tdone;  
  226.   
  227. }  
  228. static struct irqaction timer_irq = {  
  229.     .name    = "S3C2410 Timer Tick",  
  230.     .flags   = IRQF_DISABLED |IRQF_TIMER|IRQF_IRQPOLL,  
  231.     .handler = timer_interrupt_function,  
  232.     .dev_id  = NULL  
  233. };  
  234.   
  235. static int button_open(struct inode *inode,struct file *file)  
  236. {  
  237.   
  238.     int i,err;  
  239.     if(down_trylock(&lock)){  
  240.         printk("down_trylock failed!\n");  
  241.         return -EBUSY;  
  242.     }  
  243.     if(setup_irq(IRQ_TIMER0,&timer_irq)){  
  244.         printk("setup_irq failed!\n");  
  245.         return -EBUSY;  
  246.     }  
  247.   
  248.     for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++) {  
  249.         err=request_irq(button_irqs[i].irq,button_interrupt,button_irqs[i].flags,  
  250.                 button_irqs[i].name,(void*)&(button_irqs[i]));  
  251.         if(err)  
  252.             break;  
  253.     }  
  254.     if(err) {  
  255.         for(--i;i>=0;i--)  
  256.             free_irq(button_irqs[i].irq,(void *)&button_irqs[i].num);  
  257.         printk("request_irq error!\n");  
  258.         return -1;  
  259.     }  
  260.   
  261.     disable_irq(IRQ_EINT0);  
  262.     disable_irq(IRQ_EINT1);  
  263.     disable_irq(IRQ_EINT2);  
  264.     disable_irq(IRQ_EINT4);  
  265.       
  266.     set_irq_type(IRQ_EINT0,IRQ_TYPE_LEVEL_LOW);//key4  
  267.     set_irq_type(IRQ_EINT1,IRQ_TYPE_EDGE_RISING);//key1  
  268.     set_irq_type(IRQ_EINT2,IRQ_TYPE_EDGE_FALLING);//key3  
  269.     //set_irq_type(IRQ_EINT4,IRQ_TYPE_EDGE_BOTH);//key2  
  270.     set_irq_type(IRQ_EINT4,IRQ_TYPE_EDGE_FALLING);//key2  
  271.   
  272.     enable_irq(IRQ_EINT0);  
  273.     enable_irq(IRQ_EINT1);  
  274.     enable_irq(IRQ_EINT2);  
  275.     enable_irq(IRQ_EINT4);  
  276.   
  277.     return 0;  
  278. }  
  279.   
  280. static int button_close(struct inode *inode,struct file *file)  
  281. {  
  282.     int i;  
  283.     for(i=0;i<sizeof(button_irqs)/sizeof(button_irqs[0]);i++) {  
  284.         free_irq(button_irqs[i].irq,(void *)&button_irqs[i]);  
  285.     }  
  286.     remove_irq(IRQ_TIMER0,&timer_irq);  
  287.     up(&lock);  
  288.     return 0;  
  289. }  
  290.   
  291. static int button_read(struct file *filp,char __user *buff,  
  292.                         size_t count,loff_t *offp)  
  293. {  
  294.     unsigned long err;  
  295.     if(filp->f_flags & O_NONBLOCK)  
  296.         return -EAGAIN;  
  297.     else {  
  298.         wait_event_interruptible(button_waitq,ev_press);  
  299.     }  
  300.     ev_press=0;  
  301.     err=copy_to_user(buff,(const void*)key_values,  
  302.                             min(sizeof(key_values),count));  
  303.     return err ? -EFAULT : min(sizeof(key_values),count);  
  304. }  
  305. static int timer_ioctl(struct inode *inode,struct file *file,  
  306.                         unsigned int cmd,unsigned long arg)  
  307. {  
  308.     switch (cmd) {  
  309.         case TIMER_IOCTL_SET_FREQ:  
  310.             printk("timer_ioctl_set_freq\n");  
  311.             if(arg==0)  
  312.                 return -EINVAL;  
  313.             timer_set_freq(arg);  
  314.             freq_value = arg;  
  315.             break;  
  316.         case TIMER_IOCTL_STOP:  
  317.             printk("timer_ioctl_stop\n");  
  318.             timer_stop();  
  319.             break;  
  320.     }  
  321.     return 0;  
  322. }  
  323.   
  324. static struct file_operations button_fops = {  
  325.     .owner      = THIS_MODULE,  
  326.     .open       = button_open,  
  327.     .read       = button_read,  
  328.     .release    = button_close,  
  329.     .ioctl      = timer_ioctl,  
  330. };  
  331. static struct miscdevice misc = {  
  332.     .minor = MISC_DYNAMIC_MINOR,  
  333.     .name  = DEVICE_NAME,  
  334.     .fops  = &button_fops,  
  335. };  
  336. //初始化函数  
  337. static int __init button_init(void)  
  338. {  
  339.     init_MUTEX(&lock);  
  340.       
  341.     /* 
  342.     if(register_chrdev(BUTTON_MAJOR,DEVICE_NAME,&button_fops)<0) { 
  343.         printk(DEVICE_NAME"can't register major number!\n"); 
  344.         return -1; 
  345.     } 
  346.     printk(DEVICE_NAME"register sucess!\n"); 
  347.     */  
  348.     if(misc_register(&misc)<0) {  
  349.         printk(DEVICE_NAME"can't register major number!\n");  
  350.         return -1;  
  351.     }  
  352.     printk(DEVICE_NAME"register sucess!\n");  
  353.       
  354.     return 0;  
  355. }  
  356. static void __exit button_exit(void)  
  357. {  
  358.     timer_stop();  
  359.     //unregister_chrdev(BUTTON_MAJOR,DEVICE_NAME);  
  360.     misc_deregister(&misc);  
  361. }  
  362.   
  363. module_init(button_init);  
  364. module_exit(button_exit);  
  365.   
  366. MODULE_LICENSE("GPL");  


[cpp] view plain copy
  1. /********************************************************************** 
  2.                      应用程序部分button_app.c 
  3. **********************************************************************/  
  4.   
  5. #include <stdio.h>  
  6. #include <stdlib.h>  
  7. #include <unistd.h>  
  8. #include <sys/ioctl.h>  
  9. #define msleep(x) usleep(x*1000);  
  10. #define TIMER_IOCTL_SET_FREQ 1  
  11. #define TIMER_IOCTL_STOP     0  
  12. int main(int argc,char **argv)  
  13. {  
  14.     int fd;  
  15.     int ioarg=500;  
  16.     int press_cnt[4]={0};  
  17.     if((fd=open("/dev/timer_test",0))<0){  
  18.         printf("Can't open /dev/timer_test~!");  
  19.         return -1;  
  20.     }  
  21.     printf("sleep begin...\n");  
  22.     ioctl(fd,TIMER_IOCTL_SET_FREQ,ioarg);  
  23.     //msleep(70000);  
  24.     while(1)  
  25.         usleep(11111);  
  26.     ioctl(fd,TIMER_IOCTL_STOP);  
  27.     printf("sleep end...\n");  
  28.     close(fd);  
  29.     return 0;  
  30.   
  31. }  

[cpp] view plain copy
  1. /*************************************************************** 
  2.                         makefile部分 
  3. ****************************************************************/  
  4. ifneq ($(KERNELRELEASE),)  
  5. obj-m := button_ker.o  
  6. else  
  7. KDIR :=/home/kernel/linux-2.6.32.2  
  8. all:  
  9.     make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-  
  10.   
  11.     arm-linux-gcc button_app.c -o button_app  
  12. clean:  
  13.     rm -f *.ko *.o *.mod.o *.mod.c *.symvers modul*  
  14. endif 

写的不错,收藏。
http://blog.csdn.net/chuchuanchuan/article/details/7011041

你可能感兴趣的:(Linux_arm驱动之按键模拟脉冲实现定时器的精确计时 (实例))