Interrupt handling


15 posts
by doetoe » Sat Jun 23, 2012 11:46 pm
I have been looking in the peripherals data sheet for information on interrupts but I didn't find what I was looking for, possibly because I was looking for the wrong things. I only have some experience with interrupts on Arduino's AVR, which has a list of interrupts that can be enabled and configured by setting and clearing bits in various registers, and to which the address of a user ISR (interrupt service routine) can be associated.
Chapter 7 of the data sheet lists registers in which interrupts can be enabled or disabled, but it is not specified what these interrupts are (e.g. what is gpio_int[i]?). Can that be found somewhere?
Then in chapter 6 on GPIO there is mention of setting some pin event detection. Do these events trigger an interrupt? If so, which ones, can they be associated to the gpio_int[i] I mentioned before?
Finally, there is no mention of specifying ISRs. Is that because in linux there is a standard interrupt API which should be used?
I would be very grateful if anybody could help me out, even if it is just some keywords to look for on google. Thanks.
Posts: 7
Joined: Wed Nov 02, 2011 1:09 pm
by bertr2d2 » Thu Aug 09, 2012 1:34 pm
my this help you getting forward:

http://lnxpps.de/rpie/#gpio_test
Posts: 80
Joined: Wed Aug 08, 2012 10:12 pm
by Grumpy Mike » Thu Aug 09, 2012 5:46 pm
Is that because in linux there is a standard interrupt API which should be used?

Yes.
Basically Linux completely messes up all the interrupt structure. It is not even certain if you can deliver true interrupt performance on the Pi without having to replace the kernel.

There are some examples I have see where you set an interrupt to occur and then get your thread to shut down. It then gets woken up when the interrupt has happened. To me this is no sort of interrupt at all and is just like polling but in Linux land this seems to pass as a definition of an interrupt.
User avatar
Posts: 783
Joined: Sat Sep 10, 2011 7:49 pm
Location: Manchester (England England)
by gordon@drogon.net » Thu Aug 09, 2012 7:36 pm
doetoe wrote:Finally, there is no mention of specifying ISRs. Is that because in linux there is a standard interrupt API which should be used?
I would be very grateful if anybody could help me out, even if it is just some keywords to look for on google. Thanks.


Linux (and unix) in-general never really expected user-land code to handle hardware interrupts (that's the kernels job!), and that's the issue at-hand - there really is no API for handling interrupts in user-land code.

So in the traditional sense, there isn't "ISR" - Interrupt Service Routine.

So what can you do - many things. One, write your own operating system. A bit drastic that one! Use another OS - well the only other viable choice right now is RiscOS... You could write your own kernel module - this is the closest you'll get to a real ISR. You write the module, poke the hardware to tell it to deliver an edge triggered interrupt and tell Linux to register your driver with the interrupt handler and off you go. It actually is a real ISR - within the Linux kernel interrupt handler - this is the same mechanism Linux usesto access all interrupt driven hardware, disk controllers, serial ports, and so on. All your code is running at the kernel level with all the implications that has - security, robustness, crashability, etc.

Great if you're a Linux kernel module writer, not so good for the other 99.9999% of us... (Although from what I've seen the learning curve isn't that steep for an accomplished C programmer, however, much though I wish I have dived in, I've never found time).

So we're left with Plan B.

Firstly, it is good to know that is is possible to get an edge detected interrupt on a GPIO pin delivered into a user-land program. It's not technically the same as a true ISR, but it does have the same effect and with care you can handle about 10K interrupts/second although realistically at that speed the overhead is so high, there's little cpu left for anything else.

The way to do it is to create a thread in your program - that's a function that you write, and which you then ask Linux to schedule concurrently with the main program. That thread then asks the kernel to make it sleep, and wake it up when the interrupt happens.

Meanwhile, your main part of the program carries on executing, doing its thing, whatever that might be.

When the interrupt happens, the main program is suspended and the sleeping thread is woken up, it can do "stuff" to handle the interrupt, possibly use global vairables to communicate with the main program, then go back to sleep, waiting for the next interrupt.

Note that it's not the same as polling as the thread is stopped and consumes zero cpu, (which polling wouldn't) however the mechanism inside the Linux kernel to suspend the main task and wake up the sleeping thread when the interrupt fires does have more overhead than something you might be used to on an embedded controller with no operating system as such.

Anyway, that's the way that's currently implemented - I know of someone working on a Plan C, however I don't think i's quite ready yet.

If you want examples, demos, then see:

https://projects.drogon.net/raspberry-pi/wiringpi/functions/

scroll down to interrupts, then get the wiringPi code and have a look at the wfi.c code in the examples directory

-Gordon
--
Gordons projects: https://projects.drogon.net/
User avatar
Posts: 1487
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
by jbeale » Sat Aug 11, 2012 3:18 pm
with care you can handle about 10K interrupts/second

Thanks for the detailed explanation Gordon. That timing matches what I've seen elsewhere, about 100 usec latency is just what you get on this system. What I'm curious about is, if this CPU runs at approx. 900 MIPS, that means there are roughly 90,000 instructions of overhead involved in doing an interrupt(?) I know Linux doesn't have a real-time design and I don't know the first thing about what actually goes on behind the scenes to allow interrupt handling, but whatever it is, isn't that rather high? Is it writing to the SD card each time, or something like that?
User avatar
Posts: 1965
Joined: Tue Nov 22, 2011 11:51 pm
by gordon@drogon.net » Sat Aug 11, 2012 6:40 pm
jbeale wrote:
with care you can handle about 10K interrupts/second

Thanks for the detailed explanation Gordon. That timing matches what I've seen elsewhere, about 100 usec latency is just what you get on this system. What I'm curious about is, if this CPU runs at approx. 900 MIPS, that means there are roughly 90,000 instructions of overhead involved in doing an interrupt(?) I know Linux doesn't have a real-time design and I don't know the first thing about what actually goes on behind the scenes to allow interrupt handling, but whatever it is, isn't that rather high? Is it writing to the SD card each time, or something like that?


I dont know exactly what's going on behind the scenes - I can just guess - the kernel gets the interrupt, then has to scan a list of stuff to do, or handlers to call - one will recognise the GPIO pin and somehow signal the scheduller to allow the userland program to un-block and run - so the kernel then exits the interrupt handler, the scheduller now has a new task un-blocked and puts that into the run-queue and it's it's its turn to run, it returns from the "waitForInterrupt" function - the handler can make sure it always goes to the front of the queue by setting itself to be a "real-time" task with a higher priority than the rest of the system, however I've not done any measurements there.

I think it takes so-long because there is a lot of code to execute!

Similarly when calling the "waitForInterrupt" routine, it takes time to work through the kernel code to put the task to sleep, so that's not helping either.

Finally, I know when calling system functions (ie. functions inside the kerel) it can take a microsecond or more - e.g. try calling gettimeofday() twice in succession - I've been timing this and even though it has microsecond resolution, it can take over a microsecond to get into the kernel, get the data and get back again...

So I think think there's anytihng else going on, just the time it takes the few 1000 lines of code to execute to setup the handler, take the interrupt and make that task run again.

I think this is OK for what we need it to do - it's not OK for something where we need hard/guaranteed real-time control, but that was never the aim of the Pi anyway IIRC.

We can still get close though - I saw a youtue video of someone controlling a stepper motor from a bash script recently! amazing!

-Gordon
--
Gordons projects: https://projects.drogon.net/
User avatar
Posts: 1487
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
by doetoe » Sat Aug 11, 2012 10:34 pm
Thanks everybody for your great comments. I'll have a closer look as soon as I have time!
Posts: 7
Joined: Wed Nov 02, 2011 1:09 pm
by jackokring » Sat Aug 11, 2012 11:34 pm
The last I read on writing Linux ISR code, is that the interrupt does trigger very fast, but the driver code must be written to quickly save any relevant state information, and schedule the processing of this information and then exit. The interrupt is then processed when the scheduled handler process is scheduled at a convenient time for the kernel. In a multi-tasking kernel this is about the best you get.

Cheers Jacko
Pi=B256R0USB CL4SD8GB Raspbian Stock. https://sites.google.com/site/rubikcompression/strictly-long https://dl.dropboxusercontent.com/u/1615413/Own%20Work/Leptronics.pdf https://groups.google.com/forum/#!topic/comp.compression/t22ct_BKi9w
User avatar
Posts: 773
Joined: Tue Jul 31, 2012 8:27 am
Location: London, UK
by the.Lily » Sun Sep 08, 2013 12:01 pm
gordon@drogon.net wrote:
doetoe wrote:If you want examples, demos, then see:

https://projects.drogon.net/raspberry-pi/wiringpi/functions/

scroll down to interrupts, then get the wiringPi code and have a look at the wfi.c code in the examples directory

-Gordon


Hey Gordon, thanks a lot for the great explanation and website
I was looking for the example wfi.c but I could not find it, can you please give me the link to that ?

thanks
Posts: 15
Joined: Wed Jul 31, 2013 10:50 am
by jaynvt » Sun Sep 08, 2013 11:45 pm
I used this code .. https://developer.ridgerun.com/wiki/index.php/Gpio-int-test.c as an example to service gpio interrupts from a MCP23017 - i2c 16 input/output port expander..
..jay
Posts: 5
Joined: Tue Dec 11, 2012 2:47 pm
by makbut » Mon Nov 18, 2013 9:39 am
Hello. I read all of the above answers and i want just to confirm what i have understood.
I am totally noob in using the raspberry pi.

So basically when using the raspberry pi, i cannot have a gpio pin generate a hardware interrupt which will run my ISR for that specific interrupt.
What i can do is use the functions described above, so in the same time, my program will be executed, doing whatever i have programmed it to do and parallel the OS will keeping an eye on the interrupt i want (That is done by polling the IRQ pending registers described in Chapter 7 on datasheet?? ).

Is that correct? :/
Posts: 20
Joined: Mon Nov 18, 2013 9:04 am
by joan » Mon Nov 18, 2013 10:26 am
makbut wrote:Hello. I read all of the above answers and i want just to confirm what i have understood.
I am totally noob in using the raspberry pi.

So basically when using the raspberry pi, i cannot have a gpio pin generate a hardware interrupt which will run my ISR for that specific interrupt.
What i can do is use the functions described above, so in the same time, my program will be executed, doing whatever i have programmed it to do and parallel the OS will keeping an eye on the interrupt i want (That is done by polling the IRQ pending registers described in Chapter 7 on datasheet?? ).

Is that correct? :/

Your understanding is broadly correct, if you are using Linux from userland (the normal usage). You could write a Linux kernel module to set up an ISR. Alternatively you could ditch Linux and code in bare-metal.
User avatar
Posts: 5151
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by makbut » Mon Nov 18, 2013 10:49 am
joan wrote:
makbut wrote:Hello. I read all of the above answers and i want just to confirm what i have understood.
I am totally noob in using the raspberry pi.

So basically when using the raspberry pi, i cannot have a gpio pin generate a hardware interrupt which will run my ISR for that specific interrupt.
What i can do is use the functions described above, so in the same time, my program will be executed, doing whatever i have programmed it to do and parallel the OS will keeping an eye on the interrupt i want (That is done by polling the IRQ pending registers described in Chapter 7 on datasheet?? ).

Is that correct? :/

Your understanding is broadly correct, if you are using Linux from userland (the normal usage). You could write a Linux kernel module to set up an ISR. Alternatively you could ditch Linux and code in bare-metal.


Thanks for the reply, it made things clearer i think but now another question occured.

When you say that i could write a Linux kernel module to set up an ISR, how is it different from using a function in c for example
int wiringPiISR (int pin, int edgeType, void (*function)(void)) ;
Isn't this function supposed to do so? what's the difference?
Sorry if my question is stupid .
Posts: 20
Joined: Mon Nov 18, 2013 9:04 am
by joan » Mon Nov 18, 2013 10:55 am
The difference is in all the layers of Linux code called before your callback. I haven't looked at the source of wiringPiISR but I doubt it's an ISR in the normally accepted sense. I'd expect hardware interrupt, ISR called, with little if any intervening processing.
User avatar
Posts: 5151
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK
by makbut » Mon Nov 18, 2013 12:47 pm
ok i see, thanks a lot for the help.
Posts: 20
Joined: Mon Nov 18, 2013 9:04 am