Skip to content

Commit

Permalink
Runtime ISR binding and simple public API docs for assist-debug (#1395)
Browse files Browse the repository at this point in the history
* Runtime ISR binding and simple public API docs for assist-debug

* changelog

* actually use runtime ISR in example

* revert MODE generic argument
  • Loading branch information
JurajSadel authored Apr 4, 2024
1 parent bf2cca9 commit 215573a
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 12 deletions.
1 change: 1 addition & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `UsbSerialJtag` can be created in async or blocking mode. The blocking constructor takes an optional interrupt handler argument (#1377)
- SYSTIMER and TIMG instances can now be created in async or blocking mode (#1348)
- Runtime ISR binding for TWAI (#1384)
- Runtime ISR binding for assist_debug (#1395)

### Removed

Expand Down
75 changes: 70 additions & 5 deletions esp-hal/src/assist_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,62 @@
//! Debug Assistant is an auxiliary module that features a set of functions to
//! help locate bugs and issues during software debugging.
//!
//! While all the targets support PC logging it's API is not exposed here.
//! Instead the ROM bootloader will always enable it and print the last seen PC
//! (e.g. _Saved PC:0x42002ff2_). Make sure the reset was triggered by a TIMG
//! watchdog. Not an RTC or SWD watchdog.
//! While all the targets support program counter (PC) logging it's API is not
//! exposed here. Instead the ROM bootloader will always enable it and print the
//! last seen PC (e.g. _Saved PC:0x42002ff2_). Make sure the reset was triggered
//! by a TIMG watchdog. Not an RTC or SWD watchdog.
//!
//! ⚠️ Bus write access logging is not available via this API. ⚠️
//!
//! ⚠️ This driver has only blocking API. ⚠️
use crate::{
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
peripherals::ASSIST_DEBUG,
};

/// The debug assist driver instance.
pub struct DebugAssist<'d> {
debug_assist: PeripheralRef<'d, ASSIST_DEBUG>,
}

impl<'d> DebugAssist<'d> {
pub fn new(debug_assist: impl Peripheral<P = ASSIST_DEBUG> + 'd) -> Self {
/// Create a new instance in [crate::Blocking] mode.
///
/// Optionally an interrupt handler can be bound.
pub fn new(
debug_assist: impl Peripheral<P = ASSIST_DEBUG> + 'd,
interrupt: Option<InterruptHandler>,
) -> Self {
crate::into_ref!(debug_assist);

// NOTE: We should enable the debug assist, however, it's always enabled in ROM
// code already.

if let Some(interrupt) = interrupt {
unsafe {
crate::interrupt::bind_interrupt(
crate::peripherals::Interrupt::ASSIST_DEBUG,
interrupt.handler(),
);
crate::interrupt::enable(
crate::peripherals::Interrupt::ASSIST_DEBUG,
interrupt.priority(),
)
.unwrap();
}
}

DebugAssist { debug_assist }
}
}

#[cfg(assist_debug_sp_monitor)]
impl<'d> DebugAssist<'d> {
/// Enable SP monitoring on main core. When the SP exceeds the
/// `lower_bound` or `upper_bound` treshold, the module will record the PC
/// pointer and generate an interrupt.
pub fn enable_sp_monitor(&mut self, lower_bound: u32, upper_bound: u32) {
self.debug_assist
.core_0_sp_min()
Expand All @@ -64,6 +91,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Disable SP monitoring on main core.
pub fn disable_sp_monitor(&mut self) {
self.debug_assist.core_0_intr_ena().modify(|_, w| {
w.core_0_sp_spill_max_intr_ena()
Expand All @@ -80,6 +108,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Clear SP monitoring interrupt on main core.
pub fn clear_sp_monitor_interrupt(&mut self) {
self.debug_assist.core_0_intr_clr().write(|w| {
w.core_0_sp_spill_max_clr()
Expand All @@ -89,6 +118,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Check, if SP monitoring interrupt is set on main core.
pub fn is_sp_monitor_interrupt_set(&self) -> bool {
self.debug_assist
.core_0_intr_raw()
Expand All @@ -103,6 +133,7 @@ impl<'d> DebugAssist<'d> {
.bit_is_set()
}

/// Get SP monitoring PC value on main core.
pub fn get_sp_monitor_pc(&self) -> u32 {
self.debug_assist
.core_0_sp_pc()
Expand All @@ -114,6 +145,9 @@ impl<'d> DebugAssist<'d> {

#[cfg(all(assist_debug_sp_monitor, multi_core))]
impl<'d> DebugAssist<'d> {
/// Enable SP monitoring on secondondary core. When the SP exceeds the
/// `lower_bound` or `upper_bound` treshold, the module will record the PC
/// pointer and generate an interrupt.
pub fn enable_core1_sp_monitor(&mut self, lower_bound: u32, upper_bound: u32) {
self.debug_assist
.core_1_sp_min
Expand All @@ -140,6 +174,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Disable SP monitoring on secondary core.
pub fn disable_core1_sp_monitor(&mut self) {
self.debug_assist.core_1_intr_ena.modify(|_, w| {
w.core_1_sp_spill_max_intr_ena()
Expand All @@ -156,6 +191,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Clear SP monitoring interrupt on secondary core.
pub fn clear_core1_sp_monitor_interrupt(&mut self) {
self.debug_assist.core_1_intr_clr.write(|w| {
w.core_1_sp_spill_max_clr()
Expand All @@ -165,6 +201,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Check, if SP monitoring interrupt is set on secondary core.
pub fn is_core1_sp_monitor_interrupt_set(&self) -> bool {
self.debug_assist
.core_1_intr_raw
Expand All @@ -179,13 +216,18 @@ impl<'d> DebugAssist<'d> {
.bit_is_set()
}

/// Get SP monitoring PC value on secondary core.
pub fn get_core1_sp_monitor_pc(&self) -> u32 {
self.debug_assist.core_1_sp_pc.read().core_1_sp_pc().bits()
}
}

#[cfg(assist_debug_region_monitor)]
impl<'d> DebugAssist<'d> {
/// Enable region monitoring of read/write performed by the main CPU in a
/// certain memory region0. Whenever the bus reads or writes in the
/// specified memory region, an interrupt will be triggered. Two memory
/// regions (region0, region1) can be monitored at the same time.
pub fn enable_region0_monitor(
&mut self,
lower_bound: u32,
Expand Down Expand Up @@ -218,6 +260,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Disable region0 monitoring on main core.
pub fn disable_region0_monitor(&mut self) {
self.debug_assist.core_0_intr_ena().modify(|_, w| {
w.core_0_area_dram0_0_rd_intr_ena()
Expand All @@ -234,6 +277,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Clear region0 monitoring interrupt on main core.
pub fn clear_region0_monitor_interrupt(&mut self) {
self.debug_assist.core_0_intr_clr().write(|w| {
w.core_0_area_dram0_0_rd_clr()
Expand All @@ -243,6 +287,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Check, if region0 monitoring interrupt is set on main core.
pub fn is_region0_monitor_interrupt_set(&self) -> bool {
self.debug_assist
.core_0_intr_raw()
Expand All @@ -257,6 +302,9 @@ impl<'d> DebugAssist<'d> {
.bit_is_set()
}

/// Enable region monitoring of read/write performed by the main CPU in a
/// certain memory region1. Whenever the bus reads or writes in the
/// specified memory region, an interrupt will be triggered.
pub fn enable_region1_monitor(
&mut self,
lower_bound: u32,
Expand Down Expand Up @@ -289,6 +337,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Disable region1 monitoring on main core.
pub fn disable_region1_monitor(&mut self) {
self.debug_assist.core_0_intr_ena().modify(|_, w| {
w.core_0_area_dram0_1_rd_intr_ena()
Expand All @@ -305,6 +354,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Clear region1 monitoring interrupt on main core.
pub fn clear_region1_monitor_interrupt(&mut self) {
self.debug_assist.core_0_intr_clr().write(|w| {
w.core_0_area_dram0_1_rd_clr()
Expand All @@ -314,6 +364,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Check, if region1 monitoring interrupt is set on main core.
pub fn is_region1_monitor_interrupt_set(&self) -> bool {
self.debug_assist
.core_0_intr_raw()
Expand All @@ -328,6 +379,7 @@ impl<'d> DebugAssist<'d> {
.bit_is_set()
}

/// Get region monotoring PC value on main core.
pub fn get_region_monitor_pc(&self) -> u32 {
self.debug_assist
.core_0_area_pc()
Expand All @@ -339,6 +391,9 @@ impl<'d> DebugAssist<'d> {

#[cfg(all(assist_debug_region_monitor, multi_core))]
impl<'d> DebugAssist<'d> {
/// Enable region monitoring of read/write performed by the secondary CPU in
/// a certain memory region0. Whenever the bus reads or writes in the
/// specified memory region, an interrupt will be triggered.
pub fn enable_core1_region0_monitor(
&mut self,
lower_bound: u32,
Expand Down Expand Up @@ -371,6 +426,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Disable region0 monitoring on secondary core.
pub fn disable_core1_region0_monitor(&mut self) {
self.debug_assist.core_1_intr_ena().modify(|_, w| {
w.core_1_area_dram0_0_rd_intr_ena()
Expand All @@ -387,6 +443,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Clear region0 monitoring interrupt on secondary core.
pub fn clear_core1_region0_monitor_interrupt(&mut self) {
self.debug_assist.core_1_intr_clr().write(|w| {
w.core_1_area_dram0_0_rd_clr()
Expand All @@ -396,6 +453,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Check, if region0 monitoring interrupt is set on secondary core.
pub fn is_core1_region0_monitor_interrupt_set(&self) -> bool {
self.debug_assist
.core_1_intr_raw()
Expand All @@ -410,6 +468,9 @@ impl<'d> DebugAssist<'d> {
.bit_is_set()
}

/// Enable region monitoring of read/write performed by the secondary CPU in
/// a certain memory region1. Whenever the bus reads or writes in the
/// specified memory region, an interrupt will be triggered.
pub fn enable_core1_region1_monitor(
&mut self,
lower_bound: u32,
Expand Down Expand Up @@ -442,6 +503,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Disable region1 monitoring on secondary core.
pub fn disable_core1_region1_monitor(&mut self) {
self.debug_assist.core_1_intr_ena().modify(|_, w| {
w.core_1_area_dram0_1_rd_intr_ena()
Expand All @@ -458,6 +520,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Clear region1 monitoring interrupt on secondary core.
pub fn clear_core1_region1_monitor_interrupt(&mut self) {
self.debug_assist.core_1_intr_clr().write(|w| {
w.core_1_area_dram0_1_rd_clr()
Expand All @@ -467,6 +530,7 @@ impl<'d> DebugAssist<'d> {
});
}

/// Check, if region1 monitoring interrupt is set on secondary core.
pub fn is_core1_region1_monitor_interrupt_set(&self) -> bool {
self.debug_assist
.core_1_intr_raw()
Expand All @@ -481,6 +545,7 @@ impl<'d> DebugAssist<'d> {
.bit_is_set()
}

/// Get region monotoring PC value on secondary core.
pub fn get_core1_region_monitor_pc(&self) -> u32 {
self.debug_assist
.core_1_area_pc()
Expand Down
11 changes: 4 additions & 7 deletions examples/src/bin/debug_assist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ use esp_backtrace as _;
use esp_hal::{
assist_debug::DebugAssist,
clock::ClockControl,
interrupt::{self, Priority},
peripherals::{Interrupt, Peripherals},
peripherals::Peripherals,
prelude::*,
};
use esp_println::println;
Expand All @@ -28,7 +27,7 @@ fn main() -> ! {
let system = peripherals.SYSTEM.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();

let mut da = DebugAssist::new(peripherals.ASSIST_DEBUG);
let mut da = DebugAssist::new(peripherals.ASSIST_DEBUG, Some(interrupt_handler));

cfg_if::cfg_if! {
if #[cfg(not(feature = "esp32s3"))] {
Expand Down Expand Up @@ -68,8 +67,6 @@ fn main() -> ! {

critical_section::with(|cs| DA.borrow_ref_mut(cs).replace(da));

interrupt::enable(Interrupt::ASSIST_DEBUG, Priority::Priority3).unwrap();

eat_up_stack(0);

loop {}
Expand All @@ -81,8 +78,8 @@ fn eat_up_stack(v: u32) {
eat_up_stack(v + 1);
}

#[interrupt]
fn ASSIST_DEBUG() {
#[handler(priority = esp_hal::interrupt::Priority::min())]
fn interrupt_handler() {
critical_section::with(|cs| {
println!("\n\nDEBUG_ASSIST interrupt");
let mut da = DA.borrow_ref_mut(cs);
Expand Down

0 comments on commit 215573a

Please sign in to comment.