3

Linuxカーネルドライバーで、次のシーケンスを無期限に繰り返したいと思います。

  • 時間Tで、ハードウェアIRQが有効になります
  • 時間TとT+「約」15msの間に、IRQがトリガーされた場合、IRQコールバックに到達できます。私はRTカーネルを使用していないので、14ミリ秒または16ミリ秒であれば問題ありません。IRQコールバックでは、get cpu_clock(0)を書き留めて、wake_up_interruptibleを呼び出す必要があります。タイムアウトを強制終了する必要があります。プロセス全体を5ms以内に再開する必要があります。
  • T +「約」15msまでに、IRQがトリガーされていない場合は、他のコードを実行する必要があります。その場合、IRQを無効にする必要があります。プロセス全体を5ms以内に再開する必要があります。

したがって、T +「約」20msまでに、最悪の場合、プロセス全体を再開する必要があります。

IRQが18msで物理的にトリガーされた場合、あまりにも悪いことに、「電車に乗り遅れた」ことに注意してください。次のシーケンスで別のハードウェアトリガーをキャッチします。

テスト中、私は次の擬似コードに沿って何かをしていました。

INIT_DELAYED_WORK(&priv->work, driver_work);
INIT_DELAYED_WORK(&priv->timeout, driver_timeout);
request_irq(priv->irq, driver_interrupt, IRQF_TRIGGER_RISING, "my_irq", priv);

それから:

queue_delayed_work(priv->workq, &priv->work, 0ms);

static void driver_work(struct work_struct *work) {
    queue_delayed_work(priv->workq, &priv->timeout, 15ms);
    priv->interruptCalled = 0;
    enable_irq(priv->irq);
}

それで:

static irqreturn_t driver_interrupt(int irq, void *_priv) {
    disable_irq_nosync(priv->irq);
    priv->interruptCalled = 1;
    cancel_delayed_work(&priv->timeout);
    priv->stamp = cpu_clock(0);
    wake_up_interruptible(&driver_wait);
    queue_delayed_work(priv->workq, &priv->work, 5ms);
    return IRQ_HANDLED;

}

と:

static void driver_timeout(struct work_struct *work) {
    if (priv->interruptCalled == 0) {
        disable_irq_nosync(priv->irq);
        //Do other small cleanup
        queue_delayed_work(priv->workq, &priv->work, 5ms);
    }
}

堅牢でシンプルなドライバーを作成しようとしています。これは適切な実装ですか?この実装をどのように改善できますか?

4

1 に答える 1

1

私自身の質問に答える: 問題は、queue_delayed_work が jiffies に基づいていることです。または、HZ=100 (1 jiffy = 10ms) であるため、5ms は不可能です。HRタイマーは良い解決策をもたらしました。

于 2013-02-25T01:13:20.290 に答える