2013-06-10 2 views
0

Недавно я написал модуль linux для генерации прерывания каждые 20us с помощью часовой собаки. Я использую глобальный таймер, чтобы проверить, является ли интервал между двумя прерываниями 20us. Но я считаю, что результат больше 20us. Поэтому я изменяю значение сторожевого счетчика в функции прерывания, чтобы регулировать ошибку, если ошибка больше. После того, как я добавлю код ошибки регулирования, в большинстве прерываний результат лучше, чем раньше, тогда как между двумя interrpts существует огромная ошибка, и ошибка намного выше, чем 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; 
} 

ответ

0

Я думаю, что ваш обработчик вместе со всем кодом оберточной Linux может 't закончить работу в 20us, поэтому следующие прерывания задерживаются. Попробуйте увеличить задержку и посмотрите, поможет ли это.

+0

Я увеличил интервал прерываний до 2000us, но ошибка все еще существует, а максимальная ошибка составляет около 100us. И интервал прерывания, который я хочу, - 20us. стоимость обработчика прерываний не превышает 100 циклов. –