Interrupts
Motivation
Say you’ve applied for a job at CabbageCorp - you’ve wanted to work there for your entire life and finally apply for one of their co-op postings, but your phone doesn’t have email notifications. Anxious about accidentally missing an opportunity, you keep on refreshing your email every few minutes to see if they’ve replied to your application. It’s gotten to the point where it’s hard to do anything else since you are quite busy refreshing your inbox rather than doing work or going out.
It would be so much simpler to have a notification pop up on your phone to update you rather than having to check it constantly. In this case, constantly checking your phone is referred to as polling, whereas the notification will interrupt you and you can deal with it then.
Polling vs Interrupts
As discussed in the above example, polling is when you manually check on the state of something, whereas an interrupt is when you receive a signal to act upon something.
There are situations in which one may be a better solution than the other. See the table below
Polling | Interrupt |
---|---|
Easier to implement | Harder to implement as additional logic is required to set flags and integrate in program flow |
Typically blocking (i.e. you cannot do anything else while polling) | Non-blocking, the CPU is free to do anything else |
Theory of Operation
There are 2 types of interrupts, hardware interrupts and software interrupts. For now, we will generalize them as “interrupts”.
The steps are as follows, adapted from here.
MCU closes the current task and saves the address of the next instruction on the stack, referred to as the program counter
Jumps to the memory location of the interrupt service routine (ISR) via the interrupt vector table (i.e. goes to the ISR function you defined)
Note, the interrupt vector table is basically a map saying that if X interrupt gets triggered, go to Y address. It is the user's responsibility to set the address that it goes to.
After the ISR function ends, it will go back to the program counter and pops the bytes from the stack. The program will resume normally.
A common example of a hardware interrupt is a GPIO interrupt, such as a user pressing a button and changing the state of the pin from HIGH to LOW. Another type of interrupt is a UART interrupt, where the program will stop itself upon receiving new input from the UART peripheral for you to deal with.
Application Notes
Your compiler doesn’t know when an ISR occurs, and thus may optimize out variables that are inside the ISR. Thus, it is important to understand the concept of the C keyword volatile, further reading can be found in my article here: Volatile
In an interrupt, your goal should be to get in, address what you need to as possible, and get out. The interrupt is NOT a place to be doing large amounts of computational power. Instead, set a flag for your code to read and to address. In an RTOS, a binary semaphore is a cheap way to do this.
Don’t try to print() in an ISR, it is a bad idea. Just don’t. Try it for yourself if you don’t believe me