Skip to content

Commit

Permalink
Merge pull request #36 from perlindgren/panic-rtt-target-cs
Browse files Browse the repository at this point in the history
panic-rtt-target with CS
  • Loading branch information
Dirbaio authored Mar 27, 2023
2 parents 4d8bdd8 + ec89dcc commit a98a849
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 34 deletions.
14 changes: 6 additions & 8 deletions panic-rtt-target/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,17 @@
name = "panic-rtt-target"
description = "Logs panic messages over RTT using rtt-target"
version = "0.1.2"
edition = "2018"
edition = "2021"
readme = "README.md"
keywords = ["no-std", "embedded", "debugging", "rtt"]
license = "MIT"
license-file = "../LICENSE"
authors = ["Matti Virkkunen <[email protected]>"]
authors = [
"Matti Virkkunen <[email protected]>",
"Per Lindgren <[email protected]>",
]
repository = "https://github.com/probe-rs/rtt-target"

[dependencies]
rtt-target = "0.4.0"

# Platform specific stuff
cortex-m = { version = "0.7.1", optional = true }

[package.metadata.docs.rs]
features = ["cortex-m"]
critical-section = "1.1.1"
32 changes: 29 additions & 3 deletions panic-rtt-target/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ Logs panic messages over RTT. A companion crate for rtt-target.

RTT must have been initialized by using one of the `rtt_init` macros. Otherwise you will get a linker error at compile time.

Panics are always logged on channel 0. Upon panicking the channel mode is also automatically set to `BlockIfFull`, so that the full message will always be logged. If the code somehow manages to panic at runtime before RTT is initialized (quite unlikely), or if channel 0 doesn't exist, nothing is logged.
Panics are always logged on channel 0. Upon panicking the channel mode is also automatically set to `BlockIfFull`, so that the full message will always be logged. If the code somehow manages to panic at runtime before RTT is initialized (quite unlikely), or if channel 0 doesn't exist, nothing is logged.

A platform feature such as `cortex-m` is required to use this crate.
The panic handler runs in a non-returning [critical_section](https://docs.rs/critical-section/latest/critical_section/) which implementation should be provided by the user.

# Usage

Cargo.toml:

```toml
[dependencies]
panic-rtt-target = { version = "x.y.z", features = ["cortex-m"] }
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]}
panic-rtt-target = { version = "x.y.z" }
```

main.rs:
Expand All @@ -36,3 +37,28 @@ fn main() -> ! {
panic!("Something has gone terribly wrong");
}
```

## Implementation details

The provided interrupt handler checks if RTT channel 0 is configured, writes the `info` and enters an infinite loop. If RTT channel 0 is not configured, the panic handler enters the *failed to get channel* infinite loop. The final state can be observed by breaking/halting the target.
```rust
fn panic(info: &PanicInfo) -> ! {
critical_section::with(|_| {
if let Some(mut channel) = unsafe { UpChannel::conjure(0) } {
channel.set_mode(ChannelMode::BlockIfFull);

writeln!(channel, "{}", info).ok();
} else {
// failed to get channel, but not much else we can do but spin
loop {
compiler_fence(SeqCst);
}
}

// we should never leave critical section
loop {
compiler_fence(SeqCst);
}
})
}
```
35 changes: 15 additions & 20 deletions panic-rtt-target/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,29 +50,24 @@ use core::{
#[allow(unused)]
use rtt_target::{ChannelMode, UpChannel};

#[cfg(feature = "cortex-m")]
#[inline(never)]
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
use cortex_m::interrupt;
critical_section::with(|_| {
if let Some(mut channel) = unsafe { UpChannel::conjure(0) } {
channel.set_mode(ChannelMode::BlockIfFull);

interrupt::disable();
writeln!(channel, "{}", info).ok();
} else {
// failed to get channel, but not much else we can do but spin
loop {
compiler_fence(SeqCst);
}
}

if let Some(mut channel) = unsafe { UpChannel::conjure(0) } {
channel.set_mode(ChannelMode::BlockIfFull);

writeln!(channel, "{}", info).ok();
}

loop {
compiler_fence(SeqCst);
}
// we should never leave critical section
loop {
compiler_fence(SeqCst);
}
})
}

#[cfg(not(any(feature = "cortex-m")))]
compile_error!(concat!(
"You must specify a platform feature for panic-rtt-target, such as 'cortex-m'.\r\n",
"Example:\r\n",
" # Cargo.toml\r\n",
" panic-rtt-target = { version = \"x.y.z\", features = [\"cortex-m\"] }\r\n"
));
4 changes: 2 additions & 2 deletions panic-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
name = "panic-test"
version = "0.1.0"
authors = ["Matti Virkkunen <[email protected]>"]
edition = "2018"
edition = "2021"

[dependencies]
cortex-m-rt = "0.7"
panic-rtt-target = { path = "../panic-rtt-target", features = ["cortex-m"] }
panic-rtt-target = { path = "../panic-rtt-target" }
rtt-target = { path = "../rtt-target" }
3 changes: 2 additions & 1 deletion rtt-target/src/rtt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ impl RttChannel {
ptr::write_volatile(&mut self.buffer, buffer as *mut u8);
}

/// Returns true on a non-null value of the (raw) buffer pointerh
pub fn is_initialized(&self) -> bool {
self.buffer.is_null()
!self.buffer.is_null()
}

pub(crate) fn mode(&self) -> ChannelMode {
Expand Down

0 comments on commit a98a849

Please sign in to comment.