From fea324dafb22cf8e088b86712d4ec5b1477242e2 Mon Sep 17 00:00:00 2001
From: Per Lindgren <per.lindgren@ltu.se>
Date: Thu, 30 Jan 2020 18:38:14 +0100
Subject: [PATCH] continue; and exception

---
 README.md                     |  9 +++----
 examples/exception.rs         | 39 +++++++++++++++++++++++++++++
 examples/exception_itm.rs     | 47 +++++++++++++++++++++++++++++++++++
 examples/exception_itm_raw.rs | 41 ++++++++++++++++++++++++++++++
 examples/hello.rs             |  4 ++-
 examples/itm.rs               |  4 ++-
 6 files changed, 137 insertions(+), 7 deletions(-)
 create mode 100644 examples/exception.rs
 create mode 100644 examples/exception_itm.rs
 create mode 100644 examples/exception_itm_raw.rs

diff --git a/README.md b/README.md
index b0e3a53..064921d 100644
--- a/README.md
+++ b/README.md
@@ -189,18 +189,17 @@ A third alternative would be to store the panic message in some non-volatile mem
 
 ### Exception Handling and Core Peripheral Access
 
-The ARM Cortex-M processors features a set of *core* peripherpherals and *exception* handlers. These offer basic functionality independent of vendor (NXP, STM, ...). The `SysTick` perihperal is a 24-bit countdown timer, that raises a `SysTick` exception when hitting 0 and reloads the set value. Seen as a real-time system, we can dispatch the `SysTick` task in a periodic fashion (without accumulated drift under some additional constraints).
+The ARM Cortex-M processors features a set of *core* peripherals and *exception* handlers. These offer basic functionality independent of vendor (NXP, STM, ...). The `SysTick` peripheral is a 24-bit countdown timer, that raises a `SysTick` exception when hitting 0 and reloads the set value. Seen as a real-time system, we can dispatch the `SysTick` task in a periodic fashion (without accumulated drift under some additional constraints).
 
 In the `exception.rs` example  a `.` is emitted by the `SysTick` handler using `semihosting`. Running the example should give you a periodic updated of the `openocd` console.
 
-The `exception_itm.rs` and `exception_itm_raw.rs` uses the ITM instead. The difference is the way
-they gain access to the `ITM` periphereal. In the first case we *steal* the whole set of core peripherals (stealing works only in `--release` mode), while the in the second case we use *raw* pointer access to the `ITM`. In both cases, the code is *unsafe*, as there is no guarantee that other tasks may access the peripheral simultaneously (causing a conflict/race). Later we will see how the concurrency problem is solved in RTFM to offer safe access to peripherals.
+The `exception_itm.rs` and `exception_itm_raw.rs` uses the ITM instead. The difference is the way they gain access to the `ITM` peripheral. In the first case we *steal* the whole set of core peripherals, while the in the second case we use *raw* pointer access to the `ITM`. In both cases, the code is *unsafe*, as there is no guarantee that other tasks may access the peripheral simultaneously (causing a conflict/race). Later we will see how the concurrency problem is solved in RTFM to offer safe access to peripherals.
 
 ---
 
-### Crash - Analysing the Exception Frame
+### Crash - Analyzing the Exception Frame
 
-In case the execution of an intstruction fails, a `HardFault` exception is raised by the hardware, and the `HardFault` handler is executed. We can define our own handler as in example `crash.rs`. In `main` we attempt to read an illegal address, causing a `HardFault`, and we hit a breakpoint (`openocd.gdb` script sets a breakbpoint at the `HardFualt` handler). From there you can print the exception frame, reflecting the state of the MCU when the error occured. You can use `gdb` to give a `back trace` of the call-stack leading up to the error. See the example for detailed information.
+In case the execution of an instruction fails, a `HardFault` exception is raised by the hardware, and the `HardFault` handler is executed. We can define our own handler as in example `crash.rs`. In `main` we attempt to read an illegal address, causing a `HardFault`, and we hit a breakpoint (`openocd.gdb` script sets a breakpoint at the `HardFualt` handler). From there you can print the exception frame, reflecting the state of the MCU when the error occurred. You can use `gdb` to give a `back trace` of the call-stack leading up to the error. See the example for detailed information.
 
 ---
 
diff --git a/examples/exception.rs b/examples/exception.rs
new file mode 100644
index 0000000..b91ab9c
--- /dev/null
+++ b/examples/exception.rs
@@ -0,0 +1,39 @@
+//! Overriding an exception handler
+//!
+//! You can override an exception handler using the [`#[exception]`][1] attribute.
+//!
+//! [1]: https://rust-embedded.github.io/cortex-m-rt/0.6.1/cortex_m_rt_macros/fn.exception.html
+//!
+//! ---
+
+#![deny(unsafe_code)]
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+
+use cortex_m::peripheral::syst::SystClkSource;
+use cortex_m::Peripherals;
+use cortex_m_rt::{entry, exception};
+use cortex_m_semihosting::hprint;
+
+#[entry]
+fn main() -> ! {
+    let p = Peripherals::take().unwrap();
+    let mut syst = p.SYST;
+
+    // configures the system timer to trigger a SysTick exception every second
+    syst.set_clock_source(SystClkSource::Core);
+    syst.set_reload(16_000_000); // period = 1s
+    syst.enable_counter();
+    syst.enable_interrupt();
+
+    loop {
+        continue;
+    }
+}
+
+#[exception]
+fn SysTick() {
+    hprint!(".").unwrap();
+}
diff --git a/examples/exception_itm.rs b/examples/exception_itm.rs
new file mode 100644
index 0000000..6460d71
--- /dev/null
+++ b/examples/exception_itm.rs
@@ -0,0 +1,47 @@
+//! Overriding an exception handler
+//!
+//! You can override an exception handler using the [`#[exception]`][1] attribute.
+//!
+//! [1]: https://rust-embedded.github.io/cortex-m-rt/0.6.1/cortex_m_rt_macros/fn.exception.html
+//!
+//! Notice, steal will panic! in debug mode, due to a `debug_assert` (ignored in release).
+//! ---
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+
+use cortex_m::peripheral::syst::SystClkSource;
+use cortex_m::{iprint, iprintln, Peripherals};
+use cortex_m_rt::{entry, exception};
+
+#[entry]
+fn main() -> ! {
+    let mut p = Peripherals::take().unwrap();
+    let mut syst = p.SYST;
+    let stim = &mut p.ITM.stim[0];
+    iprintln!(stim, "exception_itm");
+
+    // configures the system timer to trigger a SysTick exception every second
+    syst.set_clock_source(SystClkSource::Core);
+    syst.set_reload(16_000_000); // period = 1s
+    syst.enable_counter();
+    syst.enable_interrupt();
+
+    loop {
+        continue;
+    }
+}
+
+#[exception]
+fn SysTick() {
+    // Here we steal all the peripherals.
+    //
+    // This is unsafe, as some other task/tasks may access the peripherals
+    // simultaneously, causing a conflict/race.
+    //
+    let mut p = unsafe { cortex_m::Peripherals::steal() };
+    let stim = &mut p.ITM.stim[0];
+    iprint!(stim, ".");
+}
diff --git a/examples/exception_itm_raw.rs b/examples/exception_itm_raw.rs
new file mode 100644
index 0000000..e6d6131
--- /dev/null
+++ b/examples/exception_itm_raw.rs
@@ -0,0 +1,41 @@
+//! Overriding an exception handler
+//!
+//! You can override an exception handler using the [`#[exception]`][1] attribute.
+//!
+//! [1]: https://rust-embedded.github.io/cortex-m-rt/0.6.1/cortex_m_rt_macros/fn.exception.html
+//!
+
+#![no_main]
+#![no_std]
+
+extern crate panic_halt;
+
+use cortex_m::peripheral::{syst::SystClkSource, ITM};
+use cortex_m::{iprint, iprintln, Peripherals};
+use cortex_m_rt::{entry, exception};
+
+#[entry]
+fn main() -> ! {
+    let mut p = Peripherals::take().unwrap();
+    let mut syst = p.SYST;
+    let stim = &mut p.ITM.stim[0];
+    iprintln!(stim, "exception_itm_raw");
+
+    // configures the system timer to trigger a SysTick exception every second
+    syst.set_clock_source(SystClkSource::Core);
+    syst.set_reload(16_000_000); // period = 1s
+    syst.enable_counter();
+    syst.enable_interrupt();
+
+    loop {}
+}
+
+#[exception]
+fn SysTick() {
+    // here we access `ITM` using a *raw* pointer
+    // this is unsafe, as there may be other tasks accessing the peripheral
+    // simultaneously (and that might cause a conflict/race)
+    let itm = unsafe { &mut *ITM::ptr() };
+    let stim = &mut itm.stim[0];
+    iprint!(stim, ".");
+}
diff --git a/examples/hello.rs b/examples/hello.rs
index f36bdb3..aa4a095 100644
--- a/examples/hello.rs
+++ b/examples/hello.rs
@@ -11,5 +11,7 @@ use cortex_m_semihosting::hprintln;
 #[entry]
 fn main() -> ! {
     hprintln!("Hello, world!").unwrap();
-    loop {}
+    loop {
+        continue;
+    }
 }
diff --git a/examples/itm.rs b/examples/itm.rs
index a522c0d..bb50f0f 100644
--- a/examples/itm.rs
+++ b/examples/itm.rs
@@ -22,5 +22,7 @@ fn main() -> ! {
     let stim = &mut p.ITM.stim[0];
 
     iprintln!(stim, "Hello, again!");
-    loop {}
+    loop {
+        continue;
+    }
 }
-- 
GitLab