From 5bc7aa321350e1e4ee6f959bb2a98ea0daf69eec Mon Sep 17 00:00:00 2001 From: Tomer-Eliahu <73798700+Tomer-Eliahu@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:17:24 +0000 Subject: [PATCH 1/6] make the challenge prompt match challenge code and fix typos --- mdbook/src/15-interrupts/sharing-data-with-globals.md | 4 ++-- mdbook/src/15-interrupts/the-challenge.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mdbook/src/15-interrupts/sharing-data-with-globals.md b/mdbook/src/15-interrupts/sharing-data-with-globals.md index 2ba51c2..ec3df3f 100644 --- a/mdbook/src/15-interrupts/sharing-data-with-globals.md +++ b/mdbook/src/15-interrupts/sharing-data-with-globals.md @@ -4,8 +4,8 @@ > *[Interrupts Is Threads]* by James Munns, which contains more discussion about this > topic. -As I mentioned in the last section, when an interrupt occurs we aren't passed any arguments and -cannot return any result. This makes it hard for our program interact with peripherals and other +As I mentioned previously, when an interrupt occurs we aren't passed any arguments and +cannot return any result. This makes it hard for our program to interact with peripherals and other main program state. Before worrying about this bare-metal embedded problem, it is likely worth thinking about threads in "std" Rust. diff --git a/mdbook/src/15-interrupts/the-challenge.md b/mdbook/src/15-interrupts/the-challenge.md index d22d277..d156253 100644 --- a/mdbook/src/15-interrupts/the-challenge.md +++ b/mdbook/src/15-interrupts/the-challenge.md @@ -4,7 +4,7 @@ Let's make the MB2 into a siren! But not just any siren — an interrupt-driven siren. That way we can turn the siren on and the rest of our program can run on, ignoring it. -Make your siren sweep the pitch from 220Hz to 440Hz and back +Make your siren sweep the pitch from 440Hz to 660Hz and back over a one-second period. The main program should start the siren, then print a ten-second countdown from 10 to 1, then stop the siren and print "launch!". The main program should From 777bc16eba3183c43d48cff42a111b7b5c227ccd Mon Sep 17 00:00:00 2001 From: Tomer-Eliahu <73798700+Tomer-Eliahu@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:19:08 +0000 Subject: [PATCH 2/6] add comment about critical section and higher priority interrupts interaction --- mdbook/src/15-interrupts/nvic-and-interrupt-priority.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md b/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md index b73a1eb..505e931 100644 --- a/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md +++ b/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md @@ -30,6 +30,10 @@ Preemption allows processors to respond very quickly to critical events. For ex If an equal-priority or lower-priority interrupt occurs during an ISR, it will be "pended": the NVIC will remember the new interrupt and run its ISR sometime after the current ISR completes. When an ISR function returns the NVIC looks to see if, while the ISR was running, other interrupts have happened that need to be handled. If so, the NVIC checks the interrupt table and calls the highest-priority ISR vectored there. Otherwise, the CPU returns to the running program. +Note that in most Cortex-M-based systems, *higher-priority* interrupts will be pended by the NVIC +*even* if all interrupts are disabled by a critical section (discussed later in this chapter), +though their execution will be delayed until the critical section ends. + In embedded Rust, we can program the NVIC using the [`cortex-m`] crate, which provides methods to enable and disable (called `unmask` and `mask`) interrupts, set interrupt priorities, and trigger interrupts from software. Frameworks such as [RTIC] can handle NVIC configuration for you, taking From 11df833e6ac685097066f186bfd3abe68f918175 Mon Sep 17 00:00:00 2001 From: Tomer-Eliahu <73798700+Tomer-Eliahu@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:22:51 +0000 Subject: [PATCH 3/6] add proc macro comment + fix typo --- mdbook/src/15-interrupts/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mdbook/src/15-interrupts/README.md b/mdbook/src/15-interrupts/README.md index 7b23f39..5b861b6 100644 --- a/mdbook/src/15-interrupts/README.md +++ b/mdbook/src/15-interrupts/README.md @@ -14,7 +14,7 @@ The model of computation used by our NRF52833 is the one used by almost every mo Everything about the computation the CPU is currently running is stored in the CPU registers. If the core is going to switch tasks, it must store the contents of the CPU registers somewhere so that the new task can use the registers as its own scratch-pad. When the new task is complete the CPU can then restore the register values and restart the old computation. Sure enough, that is exactly the first thing the core does in response to an interrupt request: it stops what it's doing immediately and stores the contents of the CPU registers on the stack. -The next step is actually jumping to the code that should be run in response to an interrupt. An Interrupt Service Routines (ISR), often referred to as an interrupt "handler", is a special function in your application code that gets called by the core in response to interrupts. An "interrupt table" in memory contains an "interrupt vector" for every possible interrupt: the interrupt vector indicates what ISR to call when a specific interrupt is received. We describe the details of ISR vectoring in the [NVIC and Interrupt Priority] section. +The next step is actually jumping to the code that should be run in response to an interrupt. An Interrupt Service Routine (ISR), often referred to as an interrupt "handler", is a special function in your application code that gets called by the core in response to interrupts. An "interrupt table" in memory contains an "interrupt vector" for every possible interrupt: the interrupt vector indicates what ISR to call when a specific interrupt is received. We describe the details of ISR vectoring in the [NVIC and Interrupt Priority] section. An ISR function "returns" using a special return-from-interrupt machine instruction that causes the CPU to restore the CPU registers and jump back to where it was before the ISR was called. @@ -33,6 +33,9 @@ that this ISR should be stored at the entry for the `GPIOTE` interrupt in the in The `#[interrupt]` decoration is used at compile time to mark a function to be treated specially as an ISR. (This is a "proc macro", in case you feel like exploring that concept.) +Essentially, a "proc macro" translates source code into other source code. If you are curious as to exactly what happens, +you could view the macro's definition. You can also expand any particular macro invocation using either the Tools in the [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024) or use the "rust-analyzer: Expand macro" command in your IDE. + Marking a function with `#[interrupt]` implies several special things about the function: * The compiler will check that the function takes no arguments and returns no value. The CPU has no From 70663a48ff66d8045a9457dffdbf30b15f86de58 Mon Sep 17 00:00:00 2001 From: Tomer-Eliahu <73798700+Tomer-Eliahu@users.noreply.github.com> Date: Thu, 28 Aug 2025 18:28:56 +0000 Subject: [PATCH 4/6] Clarified what marking a function with the interrupt attribute does --- mdbook/src/15-interrupts/README.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/mdbook/src/15-interrupts/README.md b/mdbook/src/15-interrupts/README.md index 5b861b6..203f2a6 100644 --- a/mdbook/src/15-interrupts/README.md +++ b/mdbook/src/15-interrupts/README.md @@ -38,17 +38,13 @@ you could view the macro's definition. You can also expand any particular macro Marking a function with `#[interrupt]` implies several special things about the function: -* The compiler will check that the function takes no arguments and returns no value. The CPU has no - arguments to provide to an ISR, and no place to put a return value from the ISR. +* The compiler will check that the function takes no arguments and returns no value (or never returns). The CPU has no + arguments to provide to an ISR, and no place to put a return value from the ISR. This is because interrupt handlers have their own call stack (at least *conceptually* if not always in practice). -* The compiler will place a vector to this function at the location in the interrupt table - implied by the function's name. +* A vector to this function (that is a function pointer) will be placed at the location in the interrupt table + which corresponds to the function's name. -* The function will be compiled to finishing by using a return-from-interrupt instruction rather - than the normal function return instruction. - -* Since the function finishes in a non-standard way, the compiler will understand not to allow - directly calling the ISR from normal code. +* The compiler will prevent directly calling the ISR from normal code. There are two steps to configure the interrupt. First, the GPIOTE must be set up to generate an interrupt when the pin connected to Button A goes from high to low voltage. Second, the NVIC must be From ad64d0cc5276e6c2e61413ed0c152aa264ee2404 Mon Sep 17 00:00:00 2001 From: Tomer-Eliahu <73798700+Tomer-Eliahu@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:24:00 +0300 Subject: [PATCH 5/6] Improve wording --- mdbook/src/15-interrupts/nvic-and-interrupt-priority.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md b/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md index 505e931..d252eea 100644 --- a/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md +++ b/mdbook/src/15-interrupts/nvic-and-interrupt-priority.md @@ -30,9 +30,7 @@ Preemption allows processors to respond very quickly to critical events. For ex If an equal-priority or lower-priority interrupt occurs during an ISR, it will be "pended": the NVIC will remember the new interrupt and run its ISR sometime after the current ISR completes. When an ISR function returns the NVIC looks to see if, while the ISR was running, other interrupts have happened that need to be handled. If so, the NVIC checks the interrupt table and calls the highest-priority ISR vectored there. Otherwise, the CPU returns to the running program. -Note that in most Cortex-M-based systems, *higher-priority* interrupts will be pended by the NVIC -*even* if all interrupts are disabled by a critical section (discussed later in this chapter), -though their execution will be delayed until the critical section ends. +Note that if interrupts are disabled entirely, all incoming interrupts will be pended. Pending interrupts will be handled once interrupts are enabled again. In embedded Rust, we can program the NVIC using the [`cortex-m`] crate, which provides methods to enable and disable (called `unmask` and `mask`) interrupts, set interrupt priorities, and trigger From 3b7d4d49f671e73b8783584b03bd62c7d18956bb Mon Sep 17 00:00:00 2001 From: Tomer-Eliahu <73798700+Tomer-Eliahu@users.noreply.github.com> Date: Sun, 21 Sep 2025 10:32:12 +0000 Subject: [PATCH 6/6] Link to Macros chapter and reword macro paragraph --- mdbook/src/15-interrupts/README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mdbook/src/15-interrupts/README.md b/mdbook/src/15-interrupts/README.md index 203f2a6..aa9ec89 100644 --- a/mdbook/src/15-interrupts/README.md +++ b/mdbook/src/15-interrupts/README.md @@ -31,10 +31,10 @@ The ISR handler function is "special". The name `GPIOTE` is required here, indic that this ISR should be stored at the entry for the `GPIOTE` interrupt in the interrupt table. The `#[interrupt]` decoration is used at compile time to mark a function to be treated specially as -an ISR. (This is a "proc macro", in case you feel like exploring that concept.) +an ISR. (This is a "proc macro": you can read more about it in the [Rust book] if you wish.) -Essentially, a "proc macro" translates source code into other source code. If you are curious as to exactly what happens, -you could view the macro's definition. You can also expand any particular macro invocation using either the Tools in the [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024) or use the "rust-analyzer: Expand macro" command in your IDE. +Essentially, a "proc macro" translates source code into other source code. If you are curious as to what any particular macro use translates into, +you could expand that macro invocation. You can do this by using either the Tools in the [Rust Playground] or the "rust-analyzer: Expand macro" command in your IDE. Marking a function with `#[interrupt]` implies several special things about the function: @@ -71,3 +71,5 @@ Normally, once an ISR is complete the main program continues running just as it [NVIC and Interrupt Priority]: nvic-and-interrupt-priority.html [Registers]: ../09-registers/index.html +[Rust Playground]: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024 +[Rust book]: https://doc.rust-lang.org/book/ch20-05-macros.html \ No newline at end of file