内核定时器
定时器就是闹钟,到一定时间就做某些事。时间、做的事情==>超时时间、函数
在includelinuxtimer.h中涉及这些函数:
复制代码
1
2
3
4
5
6
7
8
9
10//设置定时器,主要初始化timer_list结构体,设置其中的函数、参数 #define setup_timer(timer, fn, data) __setup_timer((timer), (fn), (data), 0) //向内和添加定时器timer->expires表示超时时间 extern void add_timer(struct timer_list *timer); //修改定时器的超时时间,等同于del_timer(timer);timer->expires = expires; add_timer(timer);但更高效 extern int mod_timer(struct timer_list *timer, unsigned long expires); //删除定时器 extern int del_timer(struct timer_list * timer);
定时器时间单位
在内核源码目录下的.config文件中定义了内核每秒钟发生的系统滴答(tick)中断次数,这是Linux系统的心跳。
每发生一次tcik中断,全局变量jiffies就会增加1.
CONFIG_HZ=100意味着每个滴答是10ms发生一次。
定时器的时间就是基于jiffies的,设置定时器的超时时间,一般使用这2中方法:
复制代码
1
2
3
4
5
6
7//1.在add_timer之前修改 timer.expires = jiffies + xxx; //xxx表示多少个滴答后超时,也就是xxx*10ms timer.expires = jiffies + 2*HZ; //HZ表示CONFIG_HZ,2*HZ就相当于2秒 //2.在add_timer之前,使用mod_timer修改 mod_timer(&timer, jiffies + xxx); //xxx表示多少个滴答后超时,也就是xxx*10ms mod_timer(&timer, jiffies + 2*HZ); //HZ表示CONFIG_HZ,2*HZ就相当于2秒
使用定时器处理按键防抖
一个按键在开关接触时,它的GPIO电平会反复变化,最后才稳定。一般是几十毫秒才会稳定。
- 在按键中断处理程序中,可以循环判断几十毫秒,发现电平稳定之后再上报。
- 使用定时器
显然第1中方法太耗时,违背“中断尽快处理”的原则。但是如何使用定时器?
核心在于:GPIO发生中断后,使用定时器计时10ms,如果期间又发生了中断就更新定时器,重新计时。
直到定时器超时后,再记录按键信息。
分析
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60//TIMER_SOFTIRQ软中断的初始化代码 void __init init_timers(void) { init_timer_cpus(); init_timer_stats(); timer_register_cpu_notifier(); open_softirq(TIMER_SOFTIRQ, run_timer_softirq); //注册了软中断的处理函数 } //发生硬件中断后,处理完硬件中断,内核调用软件中断处理函数 static void run_timer_softirq(struct softirq_action *h) { struct tvec_base *base = this_cpu_ptr(&tvec_bases); if (time_after_eq(jiffies, base->timer_jiffies)) __run_timers(base); } //add_timer会把timer放入内核某个链表中 //__run_timers会把链表中超时timer取出来,执行其中的函数 //判断超时就是jiffies大于等于timer->expires static inline void __run_timers(struct tvec_base *base) { struct timer_list *timer; spin_lock_irq(&base->lock); while (time_after_eq(jiffies, base->timer_jiffies)) { //.... hlist_move_list(base->tv1.vec + index, head); while (!hlist_empty(head)) { void (*fn)(unsigned long); unsigned long data; bool irqsafe; timer = hlist_entry(head->first, struct timer_list, entry); fn = timer->function; data = timer->data; irqsafe = timer->flags & TIMER_IRQSAFE; timer_stats_account_timer(timer); base->running_timer = timer; detach_expired_timer(timer, base); if (irqsafe) { spin_unlock(&base->lock); call_timer_fn(timer, fn, data); spin_lock(&base->lock); } else { spin_unlock_irq(&base->lock); call_timer_fn(timer, fn, data); spin_lock_irq(&base->lock); } } } base->running_timer = NULL; spin_unlock_irq(&base->lock); }
内核的timer,高效找到超时timer,可以参考这个文章
源码
button_timer.c
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244#include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/device.h> #include <linux/sched.h> #include <linux/wait.h> #include <linux/uaccess.h> #include <linux/irqreturn.h> #include <linux/gpio/consumer.h> #include <linux/of_gpio.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/fs.h> #include <linux/wait.h> #include <linux/poll.h> #include <linux/timer.h> struct gpio_key { int gpio; struct gpio_desc *gpiod; int flag; int irq; struct timer_list timer; }; static struct gpio_key *myBtn_key; static int button_major = 0; static struct class *button_class; static struct fasync_struct *btn_async; static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait); #define MaxSize 128 struct QNode { int Data[MaxSize]; int rear; int front; }; typedef struct QNode *Queue; int IsEmpty(Queue Q); void AddQ(Queue PtrQ, int item); int DeleteQ(Queue PtrQ); int IsEmpty(Queue Q) { return (Q->rear == Q->front); //1:empty 0:not empty } void AddQ(Queue PtrQ, int item) { if((PtrQ->rear+1)%MaxSize == PtrQ->front) { printk("%s,Queue fulln", __FUNCTION__); return; } PtrQ->rear = (PtrQ->rear+1)%MaxSize; PtrQ->Data[PtrQ->rear] = item; } int DeleteQ(Queue PtrQ) { if(PtrQ->front == PtrQ->rear) { printk("%s,Queue emptyn", __FUNCTION__); return -1; } else { PtrQ->front = (PtrQ->front+1)%MaxSize; return PtrQ->Data[PtrQ->front]; } } static Queue irqBuff; static ssize_t button_read(struct file *file, char __user *buf, size_t size, loff_t *offset) { int err; int val; if(IsEmpty(irqBuff) && (file->f_flags & O_NONBLOCK)) { return -EAGAIN; } wait_event_interruptible(gpio_key_wait, !IsEmpty(irqBuff)); val = DeleteQ(irqBuff); err = copy_to_user(buf, &val, 4); // if(err != 4) { // return -1; // } return 4; } static unsigned int button_poll(struct file *fp, poll_table * wait) { printk("%s,button polln", __FUNCTION__); poll_wait(fp, &gpio_key_wait, wait); return IsEmpty(irqBuff) ? 0 : POLLIN | POLLRDNORM; } int button_fasync(int fd, struct file *file, int on) { if(fasync_helper(fd, file, on, &btn_async) >= 0) return 0; else return -EIO; } static struct file_operations button_ops = { .owner = THIS_MODULE, .read = button_read, .poll = button_poll, .fasync = button_fasync, }; static irqreturn_t myBtn_irq_request(int irq, void *dev_id) { struct gpio_key *gpio_key = dev_id; printk(KERN_WARNING"myBtn_irq_request key %d irq happenedn", gpio_key->gpio); mod_timer(&gpio_key->timer, jiffies + HZ/50); return IRQ_HANDLED; } static void myBtn_timer(unsigned long data) { struct gpio_key *gpio_key = (struct gpio_key*)data; int val; val = gpiod_get_value(gpio_key->gpiod); printk(KERN_WARNING"key %d %dn", gpio_key->gpio, val); val = (myBtn_key->gpio << 8)|val; AddQ(irqBuff, val); wake_up_interruptible(&gpio_key_wait); kill_fasync(&btn_async, SIGIO, POLLIN); } static int my_button_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; int count; enum of_gpio_flags flag; int i, err; count = of_gpio_count(node); if(!count) { printk("%s,there isn't any gpio availiablen", __FUNCTION__); return -1; } myBtn_key = (struct gpio_key*)kzalloc(sizeof(struct gpio_key)*count, GFP_KERNEL); if(!myBtn_key) { printk("%s,kzalloc malloc failedn", __FUNCTION__); return -1; } for(i=0;i<count;i++) { myBtn_key[i].gpio = of_get_gpio_flags(node, i, &flag); if(myBtn_key[i].gpio < 0) { printk("%s, of_get_gpio_flags failedn", __FUNCTION__); return -1; } myBtn_key[i].gpiod = gpio_to_desc(myBtn_key[i].gpio); myBtn_key[i].flag = flag & OF_GPIO_ACTIVE_LOW; myBtn_key[i].irq = gpio_to_irq(myBtn_key[i].gpio); setup_timer(&myBtn_key[i].timer, myBtn_timer, (unsigned long)&myBtn_key[i]); myBtn_key[i].timer.expires = ~0; err = request_irq(myBtn_key[i].irq, myBtn_irq_request, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "myBtn_key", &myBtn_key[i]); } button_major = register_chrdev(0, "mybutton", &button_ops); if (button_major < 0) { printk(KERN_ERR "button : couldn't get a major number.n"); return -1; } button_class = class_create(THIS_MODULE, "button_class"); if(IS_ERR(button_class)) { printk(KERN_ERR "button class: create failedn"); unregister_chrdev(button_major, "mybutton"); return -1; } device_create(button_class, NULL, MKDEV(button_major, 0), NULL, "mybutton%d", 0); return 0; } static int my_button_remove(struct platform_device *pdev) { struct device_node *node= pdev->dev.of_node; int count; int i; device_destroy(button_class, MKDEV(button_major, 0)); class_destroy(button_class); unregister_chrdev(button_major, "mybutton"); count = of_gpio_count(node); for(i=0;i<count;i++) { free_irq(myBtn_key[i].irq, &myBtn_key[i]); del_timer(&myBtn_key[i].timer); } kfree(myBtn_key); return 0; } static struct of_device_id mybuttons[] = { { .compatible = "mybtn,btn_drv" }, { }, }; static struct platform_driver my_button_driver = { .probe = my_button_probe, .remove = my_button_remove, .driver = { .name = "button_dirver", .of_match_table = mybuttons, }, }; static int gpio_button_init(void) { int err; irqBuff = (Queue)kzalloc(sizeof(struct QNode), GFP_KERNEL); err = platform_driver_register(&my_button_driver); printk(KERN_WARNING"my button dirver initn"); return 0; } static void gpio_button_exit(void) { platform_driver_unregister(&my_button_driver); kfree(irqBuff); printk(KERN_WARNING"my button dirver exitn"); } module_init(gpio_button_init); module_exit(gpio_button_exit); MODULE_LICENSE("GPL");
最后
以上就是成就大叔最近收集整理的关于rk3288 定时器使用内核定时器定时器时间单位使用定时器处理按键防抖分析源码的全部内容,更多相关rk3288内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复