diff --git a/Cargo.toml b/Cargo.toml index ab13ba67d6f00e40938c9baa70e283455618b087..1577f79f47c0df3748f7d597f54f289b9fc03029 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ cortex-m-semihosting = "0.3.5" cortex-m = "0.6.2" aligned = "0.3.2" ufmt = "0.1.0" +panic-itm = "0.4.1" [dependencies.cortex-m-rt] version = "0.6.12" diff --git a/README.md b/README.md index c3bf7f2a75920767185de8fc5edb16855fbc8a6e..b0e3a5353dfe7eed00f727284ea45fc9a1fc3665 100644 --- a/README.md +++ b/README.md @@ -127,15 +127,14 @@ In a separate terminal: ``` console $ mkfifo /tmp/itm.fifo -$ itmdump -f /tmp/itm.fifo -F +$ itmdump -f /tmp/itm.fifo +Hello, again! ``` Now you can compile and run the `itm.rs` application using the same steps as the `hello` program. In the `itmdump` console you should now have the trace output. ``` console -$ mkfifo /tmp/itm.log -$ itmdump -f /tmp/itm.log -F -Hello, again! +$ cargo run --example itm ``` Under the hood there is much less overhead, the serial transfer rate is set to 2MBit in between the ITM (inside of the MCU) and `stlink` programmer (onboard the Nucleo devkit). So in theory we can transmit some 200kByte/s data over ITM. However, we are limited by the USB interconnection and `openocd` to receive and forward packages. @@ -146,7 +145,7 @@ The `stlink` programmer, buffers packages but has limited buffer space. Hence in ### Rust `panic` Handling -The `rust` compiler statically analyses your code, but in cases some errors cannot be detected at compile time (e.g., array indexing out of bounds, division by zore etc.). The `rust` compiler generates code checking such faults at run-time, instead of just crashing (or even worse, continuing with faulty/undefined values like a `C` program would) . A fault in Rust will render a `panic`, whith an associated error message (useful to debugging the application). We can choose how such `panic`s should be treated, e.g., transmitting the error message using `semihosting`, `ITM`, some other channel (e.g. a serial port), or simply aborting the program. +The `rust` compiler statically analyses your code, but in cases some errors cannot be detected at compile time (e.g., array indexing out of bounds, division by zero etc.). The `rust` compiler generates code checking such faults at run-time, instead of just crashing (or even worse, continuing with faulty/undefined values like a `C` program would) . A fault in Rust will render a `panic`, with an associated error message (useful to debugging the application). We can choose how such `panic`s should be treated, e.g., transmitting the error message using `semihosting`, `ITM`, some other channel (e.g. a serial port), or simply aborting the program. The `panic` example demonstrates some possible use cases. @@ -169,7 +168,7 @@ Breakpoint 1, rust_begin_unwind (_info=0x20017fb4) $1 = core::panic::PanicInfo {payload: core::any::&Any {pointer: 0x8000760 <.Lanon.21a036e607595cc96ffa1870690e4414.142> "\017\004\000", vtable: 0x8000760 <.Lanon.21a036e607595cc96ffa1870690e4414.142>}, message: core::option::Option<&core::fmt::Arguments>::Some(0x20017fd0), location: core::panic::Location {file: <error reading variable>, line: 27, col: 5}} ``` -Here `p *_info` prints the arument to `rust_begin_unwind`, at the far end you will find `line: 27, col 5`, which correstponds to the source code calling `panic("Ooops")`. (`gdb` is not (yet) Rust aware enough to figure out how the `file` field should be interpreted, but at least we get some useful information). +Here `p *_info` prints the arument to `rust_begin_unwind`, at the far end you will find `line: 27, col 5`, which corresponds to the source code calling `panic("Ooops")`. (`gdb` is not (yet) Rust aware enough to figure out how the `file` field should be interpreted, but at least we get some useful information). Alternatively we can trace the panic message over `semihosting` (comment out `extern crate panic_halt` and uncomment `extern crate panic_semihosting`). diff --git a/examples/itm.rs b/examples/itm.rs index b4c9401c792eb1cb985e3fbde67b6c6c157f1222..a522c0d6f13b6de1df15f2d930cc160b088c427a 100644 --- a/examples/itm.rs +++ b/examples/itm.rs @@ -2,10 +2,9 @@ //! //! ITM is much faster than semihosting. Like 4 orders of magnitude or so. //! -//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment two -//! `monitor` commands in the `.gdbinit` file. +//! You'll need [`itmdump`] to view the output. //! -//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/ +//! [`itmdump`]: https://docs.rs/itm/0.3.1/itm/ //! //! --- diff --git a/examples/panic.rs b/examples/panic.rs new file mode 100644 index 0000000000000000000000000000000000000000..27ad3336db9e385fe37f3c690280e4f417cc86be --- /dev/null +++ b/examples/panic.rs @@ -0,0 +1,28 @@ +//! Changing the panicking behavior +//! +//! The easiest way to change the panicking behavior is to use a different [panic handler crate][0]. +//! +//! [0]: https://crates.io/keywords/panic-impl + +#![no_main] +#![no_std] + +// Pick one of these panic handlers: + +// `panic!` halts execution; the panic message is ignored +extern crate panic_halt; + +// Reports panic messages to the host stderr using semihosting +// NOTE to use this you need to uncomment the `panic-semihosting` dependency in Cargo.toml +// extern crate panic_semihosting; + +// Logs panic messages using the ITM (Instrumentation Trace Macrocell) +// NOTE to use this you need to uncomment the `panic-itm` dependency in Cargo.toml +//extern crate panic_itm; + +use cortex_m_rt::entry; + +#[entry] +fn main() -> ! { + panic!("Oops") +} diff --git a/openocd.gdb b/openocd.gdb index 92d2058e4bc28237b019a303554516029769d43a..3d7321761457296364448f92b0456826e808198e 100644 --- a/openocd.gdb +++ b/openocd.gdb @@ -1,11 +1,22 @@ target extended-remote :3333 set print asm-demangle on + monitor arm semihosting enable -monitor tpiu config internal /tmp/itm.fifo uart off 16000000 2000000 +# ITM tracing +# send captured ITM to the file (or fifo) /tmp/itm.fifo +# (the microcontroller SWO pin must be connected to the programmer SWO pin) +# 16000000 must match the core clock frequency +# in this case the speed of SWO will be negotiated +monitor tpiu config internal /tmp/itm.fifo uart off 16000000 + +# OR: make the microcontroller SWO pin output compatible with UART (8N1) +# 16000000 must match the core clock frequency +# 2000000 is the frequency of the SWO pin +# monitor tpiu config external uart off 16000000 2000000 -# enable itm ports +# enable ITM ports monitor itm port 0 on monitor itm port 1 on monitor itm port 2 on @@ -14,12 +25,17 @@ monitor itm port 2 on break main # detect unhandled exceptions, hard faults and panics +break DefaultHandler break HardFault -break core::panicking::panic_fmt +break rust_begin_unwind # un-comment to check that flashing was successful # compare-sections +# make sure the processor is reset before loading (flashing) monitor reset init + load -stepi \ No newline at end of file + +# start the process but immediately halt the processor +stepi