Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Interrupts

In the last exercise, we learnt how to read to read a GPIO pin state. However, it's not always desirable to poll the pin state in software. This is where interrupts come it. We can ask hardware to notify us whenever the pin state changes.

Background

Because interrupts can happen at any time during the execution of our program, we can think of them as if they're running on a separate thread. As such, when working with interrupts, we apply the same principles as when working in a multi-threaded environment.

Additionally, because the interrupt routine is called by hardware, there is no way to pass parameters or return values from the interrupt handler.

One common way to pass data between the application and interrupt contexts is using global state. This is mostly straightforward in C, as you can just read and write any global variable at any time. Whether you like it or not, this "feature" opens up questions about what happens when the variable is modified while some other code is reading it?

Consider this code:

volatile int counter = 0;

int main() {
    while (true) {
        app_task();
        ++counter; // Same as: counter = counter + 1
    }
}

void timer_interrupt() {
    interrupt_task(counter);
    counter = 0;
}

In Rust, however, using a mutable global state is explicitly unsafe. While it's possible to bypass the compiler rules, the language strongly encourages developers to write correct code.

Atomics & Mutexes

When working with primitive types we can use one of the types provided in core::sync::atomic. Atomic types are the most fundamental way to ensure exclusive access -- these opperations are provided by the CPU.

For more complex types, we have to resort to higher level synchronization primitives, such as Mutexes and other types of locks. Note that Mutex is only available in the std library, as is requires operating system support.

No worries though, for embedded systems we can use Mutex provided by the critical_section crate.