Raspberry Pi Interrupts – An adventure with vector interrupt controllers

Today’s topic is about the Raspberry Pi Interrupt controller. I know what you’re thinking but its not as bad as it sounds promise. So, I’ve been goofing around with my ultra sweet Raspberry Pi and in doing so had this wonderful idea to just roll my own OS. You know average weekend project stuff, right? Anyways my work on RazOS has just begun and most likely will continue for some time. Though so far its been awesome, I have encountered many a roadblock along the way and thought I should share a few in hopes of saving someone else from the pain and suffering of sorting though Linux source as well as the little tidbits that are scattered about. That said, if you’re interested in OS coding I’m planning a series to come which should provided a bit more back-story. I should mention for those interested in learning something cool that this is should give you a bit of the detail you will need. So if you have no idea what a Vector Interrupt Controller is then stick with me I’ll bring you up to speed, if you do know then you may want to skip the whys and go to the core of the article down below.

What is a Vector Interrupt Controller

So Wikipedia‘s definition goes as follows “An interrupt vector is the memory address of an interrupt handler, or an index into an array called an interrupt vector table that contains the memory addresses of interrupt handlers.” Not particularly enlightening, good news is it is much simpler than its made to sound. To get started I think its best to quickly go over interrupts in general. The purpose of interrupts are simple, lets imagine for a moment you are a accountant. A pretty good one at that who can master even the most obscure of tax codes and spreadsheets. I know bear with me. Unfortunately your assistant is well.. not quite all there. When he has new information to give you or that spreadsheets you asked for instead of knocking on your office door he just stands there. I guess he is just hoping you will think to answer. Of course if you don’t quickly enough his ADD may get the best of him and just wonders off, so your forced to constantly get up and check the door to see if he is there. Now its pretty easy to see you wouldn’t get much done having to check the door all the time no matter how good you are. So whats the most simple fix to this?  Probably just to tell him to knock instead of standing there! That is exactly what an interrupt is, a knock.

Unfortunately our CPU is a bit dumber than our accountant so we have to be a little more straight forward with our decision making but the metaphor is still quite applicable. But the question lingers still, what is a vector interrupt controller? In short a vector interrupt controller is for when we have more than one door which is almost always the case.  In the case of the Raspberry Pi it can visualized with one buzzer and you have to look up which door it came from but we will come back to that in more concrete terms.

Raspberry Pi Interrupt Controller

To began lets look at this bit of code from a great example provided from David Welch.


.globl _start
_start:
ldr pc,reset_handler
ldr pc,undefined_handler
ldr pc,swi_handler
ldr pc,prefetch_handler
ldr pc,data_handler
ldr pc,unused_handler
ldr pc,irq_handler
ldr pc,fiq_handler

reset_handler: .word reset
undefined_handler: .word hang
swi_handler: .word hang
prefetch_handler: .word hang
data_handler: .word hang
unused_handler: .word hang
irq_handler: .word irq
fiq_handler: .word hang

reset:
mov r0,#0x8000
mov r1,#0x0000
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}
ldmia r0!,{r2,r3,r4,r5,r6,r7,r8,r9}
stmia r1!,{r2,r3,r4,r5,r6,r7,r8,r9}

irq:
;@ What gets called if a IRQ event happens

This is an example set of one possible way to initialize your vector table but I find it to be very straight forward for illustration purposes. This code’s job is to put the addresses of the subroutines which will be called automatically by the processors hardware should any of the events be triggered as well as enabled. By default the hardware assumes that the first eight words of memory are address to subroutines, but it can be changed to the last eight words should you wish it. You can find out how here, get familiar with it many arm specific questions can be answered with it. Since the Pi expects and runs your code at 0x8000 we must relocate the table to 0x0000, which is what the remainder of the code does for us.

Since we are only interested in interrupts today I’m going to ignore all but the IRQ calls, though it should be noted that FIQ is essentially the same with a few perks to speed up interrupt handling. You can find more on the subject in the ARM Manual.

Who knocks?

So the final part of our interrupt adventure comes in finding which door the knock has occurred. But before we get any knocks we have to enable IRQ, this is a two step procedure. First of which we must turn on the “master IRQ switch” so to speak which is located outside in a coproccessor. Once again code courtesy of David Welch. Note the mrs and msr calls.


.globl enable_irq
enable_irq:
mrs r0,cpsr
bic r0,r0,#0x80
msr cpsr_c,r0
bx lr

Once we have enabled IRQ as a whole them we must enable the individual “Doors” which we wish to hear knocks from. From this point each sub component handles the the details, so you must refer to each individual component for the details of how it triggers an interrupt.  It is worth mentioning that most of the interrupts are not handled via the ARM processor unfortunately since technically it is the secondary processor in the Broadcom BCM2835, the undocumented Videocore GPU is the king on this chip. But the ARM does have access to all of the primary ones.

The subsystems can be found here. One big point to note about the peripherals document. Unless you have the MMU enabled and mapped as stated then almost all address in the guide must be translated from 0x7Ennnnnn to 0x20nnnnnn. For example the guide states that the interrupt begins at register is 0x7E00B000, NOPE! It is in fact at the physical address of 0x200B000, so keep this mind. Since this is running a bit long I’m going to end it here, a follow up to come.

Important Further Reading: