задержка прерывания сторожевого таймера руки

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

Спасибо, что прочитали мой вопрос, я надеюсь, что он будет решен как можно скорее.

Это код обработчика прерывания:

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;
 }

person Yu Shixiang    schedule 10.06.2013    source источник


Ответы (2)


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

person Igor Skochinsky    schedule 10.06.2013
comment
Я увеличил интервал прерывания до 2000 мкс, но ошибка все еще существует, а максимальная ошибка составляет около 100 мкс. И интервал прерывания, который я хочу, составляет 20 мкс. стоимость обработчика прерывания не более 100 циклов. - person Yu Shixiang; 11.06.2013

Я думаю, что вы видите другие прерывания. Когда, например, сетевая карта отправляет прерывание, ядро ​​переходит в режим прерывания и обрабатывает сетевое прерывание. Когда он возвращается из этого, процессор видит, что ваше прерывание ожидает обработки, и запускает его. Но вы потеряли время, затраченное на сетевое прерывание.

Вам придется изменить любой другой обработчик прерываний, который занимает больше времени, чем, скажем, 10 мкс, чтобы повторно включить прерывания и запустить фактический обработчик в режиме SYS/SVC.

person Goswin von Brederlow    schedule 29.04.2018