最近,我写了一个linux模块,用看门狗每20us产生一次中断。我使用全局计时器来测试两个中断之间的间隔是否为20us。但我发现结果大于20us。因此,如果错误足够大,我会在中断函数中更改看门狗计数器的值,以调整错误。在添加误差调整代码后,在大多数中断情况下,结果都比以前好,但两次中断之间仍然存在一些巨大的误差,误差远大于20us。
感谢您阅读我的问题,我希望这个问题能尽快得到解决。
这是中断处理程序代码:
static irqreturn_t wd_interrupt(int irq, void *dev_id) {
long long regulate_value;
long load_value;
long long err;
tick_start = read_global_timer();
//the cmp_cycle is the value of global timer if the interrupt are not delayed
cmp_cycle += (long long)wd_load;
err = tick_start - cmp_cycle;
//if the err is biger than cmp_err, I will write a new value to watch dog to eliminate the error
if(err > cmp_err)
{
regulate_value = (long long)wd_load - err;
load_value = least_load;
// if the err is very big, the regulate_value may be too small
if(regulate_value > (long long)load_value)
load_value = (long)regulate_value;
__raw_writel(load_value, twd_base + TWD_WDOG_COUNTER);
}
if(err > max_err)
max_err = err;
return IRQ_HANDLED;
}这是我启动看门狗和全局计时器的代码
static int kthread_init(void *arg) {
unsigned long ctl;
int err;
if((err = request_irq(30, wd_interrupt, 0, NULL, NULL)) < 0)
{
printk("request_irq err:%d\n",err);
return 0;
}
gt_base = ioremap((OMAP44XX_LOCAL_TWD_BASE - 0X400), SZ_256);
cmp_cycle = 0;
// wd_load = twd_timer_rate / 50000; //20us
wd_load = twd_timer_rate / 500; //2000us
cmp_err = 1000;
least_load = wd_load - 2000;
tick_start = 0;
max_err = 0;
//init the global timer
__raw_writel(0x00, gt_base + GLOBAL_TIMER_CONTROL);
__raw_writel(0x00, gt_base + GLOBAL_TIMER_COUNTER_LOW);
__raw_writel(0x00, gt_base + GLOBAL_TIMER_COUNTER_UPPER);
//switch the watch dog to timer mode
__raw_writel(0x12345678, twd_base + TWD_WDOG_DISABLE);
__raw_writel(0x87654321, twd_base + TWD_WDOG_DISABLE);
//write the watch dog load register
__raw_writel(wd_load, twd_base + TWD_WDOG_LOAD);
//write the watch dog control register
ctl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_PERIODIC;
//start the watch dog and global timer
__raw_writel(ctl, twd_base + TWD_WDOG_CONTROL);
__raw_writel(0x01, gt_base + GLOBAL_TIMER_CONTROL);
set_current_state(TASK_INTERRUPTIBLE);
schedule();
while(!kthread_should_stop())
{
set_current_state(TASK_INTERRUPTIBLE);
schedule();
}
__raw_writel(0x0, twd_base + TWD_WDOG_CONTROL);
printk("wd_load:%lu,max_err:%lld\n",wd_load,max_err);
return 0;
}发布于 2013-06-11 01:03:58
我的猜测是,您的处理程序和所有Linux包装代码无法在20us内完成运行,因此以下中断会被延迟。尝试增加延迟,看看是否有帮助。
发布于 2018-04-29 19:00:00
我认为你看到的是其他中断的发生。例如,当网卡发送中断时,内核进入中断模式并处理网络中断。当它从那里返回时,cpu看到你的中断是挂起的,并触发它。但是你已经失去了网络中断所花费的时间。
您必须更改任何其他中断处理程序,这些中断处理程序需要花费超过10us的时间来重新启用中断并在SYS/SVC模式下运行实际的处理程序。
https://stackoverflow.com/questions/17028492
复制相似问题