在Linux内核驱动程序中,我想无限地重复以下顺序:

  • 在时间T,启用了硬件IRQ
  • 在时间T和T +“大约” 15毫秒之间使用
  • ,如果触发了IRQ,则可以到达IRQ回调。我绕着说是因为我没有使用RT内核,如果它是14或16ms,就可以了。在IRQ回调中,我需要记下get cpu_clock(0)并调用ake_up_interruptible。超时需要终止。整个过程需要在5毫秒内重新开始。
  • 如果通过T +“大约” 15ms,IRQ尚未被触发,我需要执行一些其他代码。然后应禁用IRQ。整个过程需要在5毫秒内重新开始。

  • 因此,在最坏情况下,在T +“大约” 20ms左右,整个过程需要重新开始。

    请注意,如果IRQ在18毫秒时被物理触发,那就太糟糕了,“我错过了火车”。我将在下一个序列中捕获另一个硬件触发器。

    在测试时,我正在按照以下伪代码进行操作:
    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);
        }
    }
    

    我正在尝试编写一个健壮但简单的驱动程序。这是正确的实现吗?我如何改善这种实现?

    最佳答案

    回答我自己的问题:问题是queue_delayed_work是基于jiffies的。否则,因为HZ = 100(1个jiffy = 10ms),所以5ms是不可能的。人力资源计时器带来了很好的解决方案。

    关于linux - Linux内核驱动程序: IRQ triggered or timeout,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14800214/

    10-11 16:27