Skip to content

Commit 01419cc

Browse files
committed
Add introduction to interrupts.
1 parent 629612b commit 01419cc

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

src/interrupt_intro.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Interrupts
2+
3+
In the last exercise, we learnt how to read to read a GPIO pin state.
4+
However, it's not always desirable to poll the pin state in software.
5+
This is where interrupts come it. We can ask hardware to notify us whenever the pin state changes.
6+
7+
## Background
8+
9+
Because interrupts can happen at any time during the execution of our program, we can think of them
10+
as if they're running on a separate thread. As such, when working with interrupts, we apply the same
11+
principles as when working in a multi-threaded environment.
12+
13+
Additionally, because the interrupt routine is called by hardware, there is no way to pass parameters or
14+
return values from the interrupt handler.
15+
16+
One common way to pass data between the application and interrupt contexts is using global state.
17+
This is mostly straightforward in C, as you can just read and write any global variable at any time.
18+
Whether you like it or not, this "feature" opens up questions about what happens when the variable is modified
19+
while some other code is reading it?
20+
21+
Consider this code:
22+
23+
```c
24+
volatile int counter = 0;
25+
26+
int main() {
27+
while (true) {
28+
app_task();
29+
++counter; // Same as: counter = counter + 1
30+
}
31+
}
32+
33+
void timer_interrupt() {
34+
interrupt_task(counter);
35+
counter = 0;
36+
}
37+
```
38+
39+
In Rust, however, using a mutable global state is explicitly `unsafe`. While it's possible to bypass
40+
the compiler rules, the language strongly encourages developers to write correct code.
41+
42+
## Atomics & Mutexes
43+
44+
When working with primitive types we can use one of the types provided in [`core::sync::atomic`][1].
45+
Atomic types are the most fundamental way to ensure exclusive access -- these opperations are provided by the CPU.
46+
47+
For more complex types, we have to resort to higher level synchronization primitives, such as [Mutexes][2] and
48+
other types of locks. Note that `Mutex` is only available in the `std` library, as is requires operating system support.
49+
50+
No worries though, for embedded systems we can use Mutex provided by the [`critical_section`][3] crate.
51+
52+
[1]: https://doc.rust-lang.org/nightly/std/sync/atomic/index.html
53+
[2]: https://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html
54+
[3]: https://docs.rs/critical-section/latest/critical_section/

0 commit comments

Comments
 (0)