I am trying to write a simple interrupt handler for a GPIO in the linux kernel. I use request_threaded_irq
to get an interrupt context handler, and a threaded handler.
My problem is that the work done by the threaded handler has a big impact on the timing of the calls to the interrupt handler.
The code to setup the interrupt is:
gpio_request(93, "test")
gpio_direction_input(93);
gpio_request(33, "mirror");
gpio_direction_output(33, 1);
request_threaded_irq(gpio_to_irq(93),
interrupt_handler,
threaded_interrupt_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_TIMER,
"test", NULL);
Here, I am simply requesting gpio 93 to fire an interrupt on rising and falling edges. I also request gpio 33 to use as a mirror, see below.
(In my setup, I put a clock source on gpio 93).
The code of the interrupt handler is this:
static irqreturn_t interrupt_handler(int irq, void *data)
{
int state = gpio_get_value(93);
gpio_set_value(33, state);
return IRQ_WAKE_THREAD;
}
Here, the interrupt handler is simply mirroring gpio 93 input value as an output value for gpio 33. This allows me to monitor the effective rate of the calls to interrupt_handler
.
Lastly, the threaded handler:
static irqreturn_t threaded_interrupt_handler(int irq, void *data)
{
/* doing msleep here is apparently problematic... */
msleep(1);
return IRQ_HANDLED;
}
In the threaded interrupt handler, calling msleep
(or actually performing work) is problematic: by looking with a scope at the gpio output 33, I can see that the interrupt_handler
callback rate changes drastically when the threaded_interrupt_handler
sleeps or perform too much work.
How can I setup/use request_threaded_irq()
so that the interrupt handler is always called "on-time" even if the threaded handler as some big work to do?
I eventually understand what was happening. According to this answer on SO, the interrupt is masked while processing the interrupt and the threaded interrupt handler.
So it seems I misunderstood the point of request_threaded_irq
: it should really be used so that the interrupt handling is in a task scheduled by the scheduler.
For my needs, what I really wanted was simply a wait_queue. I remove the threaded interrupt handler for my code and changed the interrupt handler to something like:
static wait_queue_head_t wq;
static irqreturn_t interrupt_handler(int irq, void *data)
{
int state = gpio_get_value(93);
gpio_set_value(33, state);
wake_up_interruptible(&wq);
return IRQ_HANDLED;
}
Now, the interrupt handler is called with a correct timing!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With