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