diff --git a/README.md b/README.md index b0e3a5353dfe7eed00f727284ea45fc9a1fc3665..064921d3ab7706b4cf408ebdcd51930db78a0b33 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 0000000000000000000000000000000000000000..b91ab9c8e84808f658425983c83b85214fb25355 --- /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 0000000000000000000000000000000000000000..6460d71452756bd58e05eccb2e62da22d3d51818 --- /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 0000000000000000000000000000000000000000..e6d6131e47e6040dc984c4985ac5a1ff7278f3a1 --- /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 f36bdb3edeb66447ed3290aef1408356f3e64eea..aa4a095baae75995c420ad8ffa831e0d4cfda16c 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 a522c0d6f13b6de1df15f2d930cc160b088c427a..bb50f0ff349ed7599ba0c5753a349151ab4a0395 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; + } }