我想使用一个hrtimer来控制两个硬件gpio引脚,这样一些总线信号。 我在这样的内核模块中设置了一个hrtimer
#include <linux/slab.h> #include <linux/delay.h> #include <linux/ktime.h> #include <linux/hrtimer.h> #define PIN_A_HIGH_TO_A_LOW_US 48 /* microseconds */ #define PIN_A_LOW_TO_B_LOW_US 24 /* microseconds */ static struct kt_data { struct hrtimer timer; ktime_t period; } *data; typedef enum { eIDle = 0,eSetPinALow,eSetPinBLow,} teControlState; static enum hrtimer_restart TimerCallback(struct hrtimer *var); static voID StopTimer(voID); static teControlState cycle_state = eIDle; static enum hrtimer_restart TimerCallback(struct hrtimer *var) { local_irq_disable(); switch (cycle_state) { case eSetPinALow: SetPinA_Low(); data->period = ktime_set(0,PIN_A_LOW_TO_B_LOW_US * 1000); cycle_state = eSetPinBLow; break; case eSetPinBLow: SetPinB_Low(); /* Do Stuff */ /* no break */ default: cycle_state = eIDle; break; } if (cycle_state != eIDle) { hrtimer_forward_Now(var,data->period); local_irq_enable(); return HRTIMER_RESTART; } local_irq_enable(); return HRTIMER_norESTART; } voID StartBusCycleControl(voID) { SetPinA_High(); SetPinB_High(); data->period = ktime_set(0,PIN_A_HIGH_TO_A_LOW_US * 1000); cycle_state = eSetPinALow; hrtimer_start(&data->timer,data->period,HRTIMER_MODE_REL); } int InitTimer(voID) { data = kmalloc(sizeof(*data),GFP_KERNEL); if (data) { hrtimer_init(&data->timer,CLOCK_MONOTONIC,HRTIMER_MODE_REL); data->timer.function = TimerCallback; printk(KERN_INFO DRV_name ": %s hr timer successfully initializedn",__func__); return 0; } else { printk(KERN_CRIT DRV_name ": %s Failed to initialize the hr timern",__func__); return -ENOMEM; } }
所以这个想法是
两个引脚在开始时都很高
hrtimer设置为在48微秒后过期
在callback函数中,引脚A被拉低
定时器24微秒被推进
第二次callback被触发时,引脚B被拉低
我使用带有内核4.1.2的BeagleBoneBlack和rt-preempt补丁。
我所看到的范围是,第一个计时器的工作就像一个约65-67微秒的魅力(我可以忍受的)。 但转发似乎失灵,因为我测量的引脚A低电平和B引脚电平变低的时间在2到50微秒之间。 所以从本质上讲,第二次callback被触发的时候有时会在我定义的24微秒之前发生。 而且这个时间对我的使用情况不起作用。
在C程序中计算经过的时间(以毫秒为单位)
为什么在/ proc / interrupts中不启用rtc中断?
C语言在指定的时间调用一个函数
clock_gettime无法立即更新
C ++我可以用什么来代替sleep()函数?
任何指针,我在做什么错?
什么可能会导致OpenGL在“开始deBUGging”与“不开始deBUGging”选项下performance不同?
用amd64上的debian linuxtestingtimerfd_create
使用OS定时器处理游戏循环
linux'hrtimer – 微秒精度?
在没有Application.IDle的C#windows窗体应用程序中检测空闲时间
所以要自己来回答这个:这是一个错误期望的问题。
我们在这里期望的是在回调期间将定时器设置为我们设置的量(24us)。 但是如果我们看一下hrtimer_forward_Now()的内核实现,我们可以看到时间实际上被添加到定时器的最后一个事件/事件中(参见delta的计算):
从linux / kernel / time / hrtimer.c
833 u64 hrtimer_forward(struct hrtimer *timer,ktime_t Now,ktime_t interval) 834 { 835 u64 orun = 1; 836 ktime_t delta; 837 838 delta = ktime_sub(Now,hrtimer_get_expires(timer)); 839 840 if (delta.tv64 < 0) 841 return 0; 842 843 if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED)) 844 return 0; 845 846 if (interval.tv64 < hrtimer_resolution) 847 interval.tv64 = hrtimer_resolution; 848 849 if (unlikely(delta.tv64 >= interval.tv64)) { 850 s64 incr = ktime_to_ns(interval); 851 852 orun = ktime_divns(delta,incr); 853 hrtimer_add_expires_ns(timer,incr * orun); 854 if (hrtimer_get_expires_tv64(timer) > Now.tv64) 855 return orun; 856 /* 857 * This (and the ktime_add() below) is the 858 * correction for exact: 859 */ 860 orun++; 861 } 862 hrtimer_add_expires(timer,interval); 863 864 return orun; 865 }
这意味着在定时器触发和实际执行的回调之间所花的时间延迟在这里没有考虑到。 这些条形码在间隔时间上是精确的,并且不受通常的发射和回调之间的延迟的影响。 我们的期望是在计算中包括那个时间,因为我们希望计时器在我们执行定时器回调中的一个动作的那一刻重新开始。
我试图把它画成下图:
在红色编号的气泡之后,我们得到:
定时器以X时间开始启动
时间X已经过去,定时器被触发
在根据系统的负载和其他因素“延迟X”之后,调用hrtimer的回调函数
hrtimer_forward_Now根据最后一个事件加上新的预期时间hrtimer_forward_Now设置新的定时器(这可能是将来只有2us而不是24个)
这是预期与现实的差距。 hrtimer在最后一次事件发生24us后触发,我们期望在调用forward_Now()之后24us触发。
总而言之,我们完全抛弃了上面的代码示例,并在触发两个GPIO引脚之间调用了usleep_range() 。 该函数的底层实现也是使用hrtimer完成的,但是它对用户来说是隐藏的,并且在这种情况下它就像我们期望的那样工作。
总结以上是内存溢出为你收集整理的为什么我的hrtimercallback在转发之后返回太早?全部内容,希望文章能够帮你解决为什么我的hrtimercallback在转发之后返回太早?所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)