diff --git a/esp-hal-common/Cargo.toml b/esp-hal-common/Cargo.toml index 35e24991e75..1387cde513e 100644 --- a/esp-hal-common/Cargo.toml +++ b/esp-hal-common/Cargo.toml @@ -51,11 +51,11 @@ ufmt-write = { version = "0.1.0", optional = true } # Each supported device MUST have its PAC included below along with a # corresponding feature. esp32 = { version = "0.23.0", features = ["critical-section"], optional = true } -esp32c2 = { version = "0.10.0", features = ["critical-section"], optional = true } -esp32c3 = { version = "0.13.0", features = ["critical-section"], optional = true } -esp32c6 = { version = "0.3.0", features = ["critical-section"], optional = true } +esp32c2 = { version = "0.11.0", features = ["critical-section"], optional = true } +esp32c3 = { version = "0.14.0", features = ["critical-section"], optional = true } +esp32c6 = { version = "0.4.0", features = ["critical-section"], optional = true } esp32s2 = { version = "0.14.0", features = ["critical-section"], optional = true } -esp32s3 = { version = "0.17.0", features = ["critical-section"], optional = true } +esp32s3 = { version = "0.18.0", features = ["critical-section"], optional = true } [build-dependencies] basic-toml = "0.1.2" diff --git a/esp-hal-common/devices/esp32c2.toml b/esp-hal-common/devices/esp32c2.toml index 59d92e28f13..cbde774781d 100644 --- a/esp-hal-common/devices/esp32c2.toml +++ b/esp-hal-common/devices/esp32c2.toml @@ -29,6 +29,7 @@ peripherals = [ "uart0", "uart1", "xts_aes", + "assist_debug_sp_monitor", # Additional peripherals defined by us (the developers): "adc", diff --git a/esp-hal-common/devices/esp32c3.toml b/esp-hal-common/devices/esp32c3.toml index 35760f607d1..f2e2ea5defa 100644 --- a/esp-hal-common/devices/esp32c3.toml +++ b/esp-hal-common/devices/esp32c3.toml @@ -40,6 +40,8 @@ peripherals = [ "uhci1", "usb_device", "xts_aes", + "assist_debug_sp_monitor", + "assist_debug_region_monitor", # Additional peripherals defined by us (the developers): "adc", diff --git a/esp-hal-common/devices/esp32c6.toml b/esp-hal-common/devices/esp32c6.toml index 1cc267a6a5b..d2351becd15 100644 --- a/esp-hal-common/devices/esp32c6.toml +++ b/esp-hal-common/devices/esp32c6.toml @@ -66,6 +66,8 @@ peripherals = [ "uart1", "uhci0", "usb_device", + "assist_debug_sp_monitor", + "assist_debug_region_monitor", # Additional peripherals defined by us (the developers): "adc", diff --git a/esp-hal-common/devices/esp32s3.toml b/esp-hal-common/devices/esp32s3.toml index b605984c006..4bb8f87148b 100644 --- a/esp-hal-common/devices/esp32s3.toml +++ b/esp-hal-common/devices/esp32s3.toml @@ -56,6 +56,7 @@ peripherals = [ "usb_wrap", "wcl", "xts_aes", + "assist_debug_region_monitor", # Additional peripherals defined by us (the developers): "adc", diff --git a/esp-hal-common/src/assist_debug.rs b/esp-hal-common/src/assist_debug.rs new file mode 100644 index 00000000000..e95aa3dc66b --- /dev/null +++ b/esp-hal-common/src/assist_debug.rs @@ -0,0 +1,486 @@ +//! Debug Assistant +//! +//! 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. +//! +//! Not all targets support all the features. +//! +//! Bus write access logging is not available via this API. + +use crate::{ + peripheral::{Peripheral, PeripheralRef}, + system::PeripheralClockControl, +}; + +pub struct DebugAssist<'d> { + debug_assist: PeripheralRef<'d, crate::peripherals::ASSIST_DEBUG>, +} + +impl<'d> DebugAssist<'d> { + pub fn new( + debug_assist: impl Peripheral

+ 'd, + _peripheral_clock_control: &mut PeripheralClockControl, + ) -> Self { + crate::into_ref!(debug_assist); + + // we should use peripheral clock control to enable the debug assist however + // it's always enabled in ROM code already + + DebugAssist { debug_assist } + } +} + +#[cfg(assist_debug_sp_monitor)] +impl<'d> DebugAssist<'d> { + pub fn enable_sp_monitor(&mut self, lower_bound: u32, upper_bound: u32) { + self.debug_assist + .core_0_sp_min + .write(|w| w.core_0_sp_min().variant(lower_bound)); + + self.debug_assist + .core_0_sp_max + .write(|w| w.core_0_sp_max().variant(upper_bound)); + + self.debug_assist.core_0_montr_ena.modify(|_, w| { + w.core_0_sp_spill_min_ena() + .set_bit() + .core_0_sp_spill_max_ena() + .set_bit() + }); + + self.clear_sp_monitor_interrupt(); + + self.debug_assist.core_0_intr_ena.modify(|_, w| { + w.core_0_sp_spill_max_intr_ena() + .set_bit() + .core_0_sp_spill_min_intr_ena() + .set_bit() + }); + } + + pub fn disable_sp_monitor(&mut self) { + self.debug_assist.core_0_intr_ena.modify(|_, w| { + w.core_0_sp_spill_max_intr_ena() + .clear_bit() + .core_0_sp_spill_min_intr_ena() + .clear_bit() + }); + + self.debug_assist.core_0_montr_ena.modify(|_, w| { + w.core_0_sp_spill_min_ena() + .clear_bit() + .core_0_sp_spill_max_ena() + .clear_bit() + }); + } + + pub fn clear_sp_monitor_interrupt(&mut self) { + self.debug_assist.core_0_intr_clr.write(|w| { + w.core_0_sp_spill_max_clr() + .set_bit() + .core_0_sp_spill_min_clr() + .set_bit() + }); + } + + pub fn is_sp_monitor_interrupt_set(&self) -> bool { + self.debug_assist + .core_0_intr_raw + .read() + .core_0_sp_spill_max_raw() + .bit_is_set() + || self + .debug_assist + .core_0_intr_raw + .read() + .core_0_sp_spill_min_raw() + .bit_is_set() + } + + pub fn get_sp_monitor_pc(&self) -> u32 { + self.debug_assist.core_0_sp_pc.read().core_0_sp_pc().bits() + } +} + +#[cfg(all(assist_debug_sp_monitor, multi_core))] +impl<'d> DebugAssist<'d> { + pub fn enable_core1_sp_monitor(&mut self, lower_bound: u32, upper_bound: u32) { + self.debug_assist + .core_1_sp_min + .write(|w| w.core_1_sp_min().variant(lower_bound)); + + self.debug_assist + .core_1_sp_max + .write(|w| w.core_1_sp_max().variant(upper_bound)); + + self.debug_assist.core_1_montr_ena.modify(|_, w| { + w.core_1_sp_spill_min_ena() + .set_bit() + .core_1_sp_spill_max_ena() + .set_bit() + }); + + self.clear_core1_sp_monitor_interrupt(); + + self.debug_assist.core_1_intr_ena.modify(|_, w| { + w.core_1_sp_spill_max_intr_ena() + .set_bit() + .core_1_sp_spill_min_intr_ena() + .set_bit() + }); + } + + 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() + .clear_bit() + .core_1_sp_spill_min_intr_ena() + .clear_bit() + }); + + self.debug_assist.core_1_montr_ena.modify(|_, w| { + w.core_1_sp_spill_min_ena() + .clear_bit() + .core_1_sp_spill_max_ena() + .clear_bit() + }); + } + + 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() + .set_bit() + .core_1_sp_spill_min_clr() + .set_bit() + }); + } + + pub fn is_core1_sp_monitor_interrupt_set(&self) -> bool { + self.debug_assist + .core_1_intr_raw + .read() + .core_1_sp_spill_max_raw() + .bit_is_set() + || self + .debug_assist + .core_1_intr_raw + .read() + .core_1_sp_spill_min_raw() + .bit_is_set() + } + + 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> { + pub fn enable_region0_monitor( + &mut self, + lower_bound: u32, + upper_bound: u32, + reads: bool, + writes: bool, + ) { + self.debug_assist + .core_0_area_dram0_0_min + .write(|w| w.core_0_area_dram0_0_min().variant(lower_bound)); + + self.debug_assist + .core_0_area_dram0_0_max + .write(|w| w.core_0_area_dram0_0_max().variant(upper_bound)); + + self.debug_assist.core_0_montr_ena.modify(|_, w| { + w.core_0_area_dram0_0_rd_ena() + .bit(reads) + .core_0_area_dram0_0_wr_ena() + .bit(writes) + }); + + self.clear_region0_monitor_interrupt(); + + self.debug_assist.core_0_intr_ena.modify(|_, w| { + w.core_0_area_dram0_0_rd_intr_ena() + .set_bit() + .core_0_area_dram0_0_wr_intr_ena() + .set_bit() + }); + } + + 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() + .clear_bit() + .core_0_area_dram0_0_wr_intr_ena() + .clear_bit() + }); + + self.debug_assist.core_0_montr_ena.modify(|_, w| { + w.core_0_area_dram0_0_rd_ena() + .clear_bit() + .core_0_area_dram0_0_wr_ena() + .clear_bit() + }); + } + + 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() + .set_bit() + .core_0_area_dram0_0_wr_clr() + .set_bit() + }); + } + + pub fn is_region0_monitor_interrupt_set(&self) -> bool { + self.debug_assist + .core_0_intr_raw + .read() + .core_0_area_dram0_0_rd_raw() + .bit_is_set() + || self + .debug_assist + .core_0_intr_raw + .read() + .core_0_area_dram0_0_wr_raw() + .bit_is_set() + } + + pub fn enable_region1_monitor( + &mut self, + lower_bound: u32, + upper_bound: u32, + reads: bool, + writes: bool, + ) { + self.debug_assist + .core_0_area_dram0_1_min + .write(|w| w.core_0_area_dram0_1_min().variant(lower_bound)); + + self.debug_assist + .core_0_area_dram0_1_max + .write(|w| w.core_0_area_dram0_1_max().variant(upper_bound)); + + self.debug_assist.core_0_montr_ena.modify(|_, w| { + w.core_0_area_dram0_1_rd_ena() + .bit(reads) + .core_0_area_dram0_1_wr_ena() + .bit(writes) + }); + + self.clear_region1_monitor_interrupt(); + + self.debug_assist.core_0_intr_ena.modify(|_, w| { + w.core_0_area_dram0_1_rd_intr_ena() + .set_bit() + .core_0_area_dram0_1_wr_intr_ena() + .set_bit() + }); + } + + 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() + .clear_bit() + .core_0_area_dram0_1_wr_intr_ena() + .clear_bit() + }); + + self.debug_assist.core_0_montr_ena.modify(|_, w| { + w.core_0_area_dram0_1_rd_ena() + .clear_bit() + .core_0_area_dram0_1_wr_ena() + .clear_bit() + }); + } + + 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() + .set_bit() + .core_0_area_dram0_1_wr_clr() + .set_bit() + }); + } + + pub fn is_region1_monitor_interrupt_set(&self) -> bool { + self.debug_assist + .core_0_intr_raw + .read() + .core_0_area_dram0_1_rd_raw() + .bit_is_set() + || self + .debug_assist + .core_0_intr_raw + .read() + .core_0_area_dram0_1_wr_raw() + .bit_is_set() + } + + pub fn get_region_monitor_pc(&self) -> u32 { + self.debug_assist + .core_0_area_pc + .read() + .core_0_area_pc() + .bits() + } +} + +#[cfg(all(assist_debug_region_monitor, multi_core))] +impl<'d> DebugAssist<'d> { + pub fn enable_core1_region0_monitor( + &mut self, + lower_bound: u32, + upper_bound: u32, + reads: bool, + writes: bool, + ) { + self.debug_assist + .core_1_area_dram0_0_min + .write(|w| w.core_1_area_dram0_0_min().variant(lower_bound)); + + self.debug_assist + .core_1_area_dram0_0_max + .write(|w| w.core_1_area_dram0_0_max().variant(upper_bound)); + + self.debug_assist.core_1_montr_ena.modify(|_, w| { + w.core_1_area_dram0_0_rd_ena() + .bit(reads) + .core_1_area_dram0_0_wr_ena() + .bit(writes) + }); + + self.clear_core1_region0_monitor_interrupt(); + + self.debug_assist.core_1_intr_ena.modify(|_, w| { + w.core_1_area_dram0_0_rd_intr_ena() + .set_bit() + .core_1_area_dram0_0_wr_intr_ena() + .set_bit() + }); + } + + 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() + .clear_bit() + .core_1_area_dram0_0_wr_intr_ena() + .clear_bit() + }); + + self.debug_assist.core_1_montr_ena.modify(|_, w| { + w.core_1_area_dram0_0_rd_ena() + .clear_bit() + .core_1_area_dram0_0_wr_ena() + .clear_bit() + }); + } + + 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() + .set_bit() + .core_1_area_dram0_0_wr_clr() + .set_bit() + }); + } + + pub fn is_core1_region0_monitor_interrupt_set(&self) -> bool { + self.debug_assist + .core_1_intr_raw + .read() + .core_1_area_dram0_0_rd_raw() + .bit_is_set() + || self + .debug_assist + .core_1_intr_raw + .read() + .core_1_area_dram0_0_wr_raw() + .bit_is_set() + } + + pub fn enable_core1_region1_monitor( + &mut self, + lower_bound: u32, + upper_bound: u32, + reads: bool, + writes: bool, + ) { + self.debug_assist + .core_1_area_dram0_1_min + .write(|w| w.core_1_area_dram0_1_min().variant(lower_bound)); + + self.debug_assist + .core_1_area_dram0_1_max + .write(|w| w.core_1_area_dram0_1_max().variant(upper_bound)); + + self.debug_assist.core_1_montr_ena.modify(|_, w| { + w.core_1_area_dram0_1_rd_ena() + .bit(reads) + .core_1_area_dram0_1_wr_ena() + .bit(writes) + }); + + self.clear_core1_region1_monitor_interrupt(); + + self.debug_assist.core_1_intr_ena.modify(|_, w| { + w.core_1_area_dram0_1_rd_intr_ena() + .set_bit() + .core_1_area_dram0_1_wr_intr_ena() + .set_bit() + }); + } + + 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() + .clear_bit() + .core_1_area_dram0_1_wr_intr_ena() + .clear_bit() + }); + + self.debug_assist.core_1_montr_ena.modify(|_, w| { + w.core_1_area_dram0_1_rd_ena() + .clear_bit() + .core_1_area_dram0_1_wr_ena() + .clear_bit() + }); + } + + 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() + .set_bit() + .core_1_area_dram0_1_wr_clr() + .set_bit() + }); + } + + pub fn is_core1_region1_monitor_interrupt_set(&self) -> bool { + self.debug_assist + .core_1_intr_raw + .read() + .core_1_area_dram0_1_rd_raw() + .bit_is_set() + || self + .debug_assist + .core_1_intr_raw + .read() + .core_1_area_dram0_1_wr_raw() + .bit_is_set() + } + + pub fn get_core1_region_monitor_pc(&self) -> u32 { + self.debug_assist + .core_1_area_pc + .read() + .core_1_area_pc() + .bits() + } +} diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 19658372e10..b122c7fae0f 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -72,6 +72,8 @@ pub use self::{delay::Delay, soc::peripherals}; pub mod aes; #[cfg(any(adc, dac))] pub mod analog; +#[cfg(assist_debug)] +pub mod assist_debug; pub mod clock; pub mod delay; #[cfg(any(gdma, pdma))] diff --git a/esp32c2-hal/examples/debug_assist.rs b/esp32c2-hal/examples/debug_assist.rs new file mode 100644 index 00000000000..0f55f918569 --- /dev/null +++ b/esp32c2-hal/examples/debug_assist.rs @@ -0,0 +1,89 @@ +//! This shows debug-assist + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use critical_section::Mutex; +use esp32c2_hal::{ + assist_debug::DebugAssist, + clock::ClockControl, + interrupt, + peripherals::{self, Peripherals}, + prelude::*, + riscv, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; + +static DA: Mutex>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + + let mut da = DebugAssist::new( + peripherals.ASSIST_DEBUG, + &mut system.peripheral_clock_control, + ); + + da.enable_sp_monitor(0x3fccee00, 0x3fcd0000); + + critical_section::with(|cs| DA.borrow_ref_mut(cs).replace(da)); + + interrupt::enable( + peripherals::Interrupt::ASSIST_DEBUG, + interrupt::Priority::Priority3, + ) + .unwrap(); + + unsafe { + riscv::interrupt::enable(); + } + + eat_up_stack(0); + + loop {} +} + +#[allow(unconditional_recursion)] +fn eat_up_stack(v: u32) { + println!("Iteration {v}"); + eat_up_stack(v + 1); +} + +#[interrupt] +fn ASSIST_DEBUG() { + critical_section::with(|cs| { + println!("\n\nDEBUG_ASSIST interrupt"); + let mut da = DA.borrow_ref_mut(cs); + let da = da.as_mut().unwrap(); + + if da.is_sp_monitor_interrupt_set() { + println!("SP MONITOR TRIGGERED"); + da.clear_sp_monitor_interrupt(); + let pc = da.get_sp_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + loop {} + }); +} diff --git a/esp32c3-hal/examples/debug_assist.rs b/esp32c3-hal/examples/debug_assist.rs new file mode 100644 index 00000000000..f7f8afece3d --- /dev/null +++ b/esp32c3-hal/examples/debug_assist.rs @@ -0,0 +1,116 @@ +//! This shows debug-assist +//! +//! Uncomment the functionality you want to test + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use critical_section::Mutex; +use esp32c3_hal::{ + assist_debug::DebugAssist, + clock::ClockControl, + interrupt, + peripherals::{self, Peripherals}, + prelude::*, + riscv, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; + +static DA: Mutex>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let mut da = DebugAssist::new( + peripherals.ASSIST_DEBUG, + &mut system.peripheral_clock_control, + ); + + // uncomment the functionality you want to test + + // da.enable_sp_monitor(0x3fcce000, 0x3fccffff); + // da.enable_region0_monitor(0x3fcce000, 0x3fcce100, true, true); + da.enable_region1_monitor(0x3fcce000, 0x3fcce100, true, true); + + critical_section::with(|cs| DA.borrow_ref_mut(cs).replace(da)); + + interrupt::enable( + peripherals::Interrupt::ASSIST_DEBUG, + interrupt::Priority::Priority3, + ) + .unwrap(); + + unsafe { + riscv::interrupt::enable(); + } + + eat_up_stack(0); + + loop {} +} + +#[allow(unconditional_recursion)] +fn eat_up_stack(v: u32) { + println!("Iteration {v}"); + eat_up_stack(v + 1); +} + +#[interrupt] +fn ASSIST_DEBUG() { + critical_section::with(|cs| { + println!("\n\nDEBUG_ASSIST interrupt"); + let mut da = DA.borrow_ref_mut(cs); + let da = da.as_mut().unwrap(); + + if da.is_sp_monitor_interrupt_set() { + println!("SP MONITOR TRIGGERED"); + da.clear_sp_monitor_interrupt(); + let pc = da.get_sp_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + if da.is_region0_monitor_interrupt_set() { + println!("REGION0 MONITOR TRIGGERED"); + da.clear_region0_monitor_interrupt(); + let pc = da.get_region_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + if da.is_region1_monitor_interrupt_set() { + println!("REGION1 MONITOR TRIGGERED"); + da.clear_region1_monitor_interrupt(); + let pc = da.get_region_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + loop {} + }); +} diff --git a/esp32c6-hal/examples/debug_assist.rs b/esp32c6-hal/examples/debug_assist.rs new file mode 100644 index 00000000000..daf4b21a11e --- /dev/null +++ b/esp32c6-hal/examples/debug_assist.rs @@ -0,0 +1,116 @@ +//! This shows debug-assist +//! +//! Uncomment the functionality you want to test + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use critical_section::Mutex; +use esp32c6_hal::{ + assist_debug::DebugAssist, + clock::ClockControl, + interrupt, + peripherals::{self, Peripherals}, + prelude::*, + riscv, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; + +static DA: Mutex>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.PCR.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let mut rtc = Rtc::new(peripherals.LP_CLKRST); + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt0 = timer_group0.wdt; + let timer_group1 = TimerGroup::new( + peripherals.TIMG1, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt1 = timer_group1.wdt; + + // Disable watchdog timers + rtc.swd.disable(); + rtc.rwdt.disable(); + wdt0.disable(); + wdt1.disable(); + + let mut da = DebugAssist::new( + peripherals.ASSIST_DEBUG, + &mut system.peripheral_clock_control, + ); + + // uncomment the functionality you want to test + + // da.enable_sp_monitor(0x4087ee00, 0x40880000); + // da.enable_region0_monitor(0x4087ee00, 0x4087ef00, true, true); + da.enable_region1_monitor(0x4087ee00, 0x4087ef00, true, true); + + critical_section::with(|cs| DA.borrow_ref_mut(cs).replace(da)); + + interrupt::enable( + peripherals::Interrupt::ASSIST_DEBUG, + interrupt::Priority::Priority3, + ) + .unwrap(); + + unsafe { + riscv::interrupt::enable(); + } + + eat_up_stack(0); + + loop {} +} + +#[allow(unconditional_recursion)] +fn eat_up_stack(v: u32) { + println!("Iteration {v}"); + eat_up_stack(v + 1); +} + +#[interrupt] +fn ASSIST_DEBUG() { + critical_section::with(|cs| { + println!("\n\nDEBUG_ASSIST interrupt"); + let mut da = DA.borrow_ref_mut(cs); + let da = da.as_mut().unwrap(); + + if da.is_sp_monitor_interrupt_set() { + println!("SP MONITOR TRIGGERED"); + da.clear_sp_monitor_interrupt(); + let pc = da.get_sp_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + if da.is_region0_monitor_interrupt_set() { + println!("REGION0 MONITOR TRIGGERED"); + da.clear_region0_monitor_interrupt(); + let pc = da.get_region_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + if da.is_region1_monitor_interrupt_set() { + println!("REGION1 MONITOR TRIGGERED"); + da.clear_region1_monitor_interrupt(); + let pc = da.get_region_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + loop {} + }); +} diff --git a/esp32s3-hal/examples/debug_assist.rs b/esp32s3-hal/examples/debug_assist.rs new file mode 100644 index 00000000000..c3c9a768a98 --- /dev/null +++ b/esp32s3-hal/examples/debug_assist.rs @@ -0,0 +1,95 @@ +//! This shows debug-assist +//! +//! Uncomment the functionality you want to test + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use critical_section::Mutex; +use esp32s3_hal::{ + assist_debug::DebugAssist, + clock::ClockControl, + interrupt, + peripherals::{self, Peripherals}, + prelude::*, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; + +static DA: Mutex>> = Mutex::new(RefCell::new(None)); + +#[entry] +fn main() -> ! { + let peripherals = Peripherals::take(); + let mut system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + + let timer_group0 = TimerGroup::new( + peripherals.TIMG0, + &clocks, + &mut system.peripheral_clock_control, + ); + let mut wdt = timer_group0.wdt; + let mut rtc = Rtc::new(peripherals.RTC_CNTL); + + // Disable MWDT and RWDT (Watchdog) flash boot protection + wdt.disable(); + rtc.rwdt.disable(); + + let mut da = DebugAssist::new( + peripherals.ASSIST_DEBUG, + &mut system.peripheral_clock_control, + ); + + // uncomment the functionality you want to test + + da.enable_region0_monitor(0x3fcce000, 0x3fcce100, true, true); + // da.enable_region1_monitor(0x3fcce000, 0x3fcce100, true, true); + + critical_section::with(|cs| DA.borrow_ref_mut(cs).replace(da)); + + interrupt::enable( + peripherals::Interrupt::ASSIST_DEBUG, + interrupt::Priority::Priority3, + ) + .unwrap(); + + eat_up_stack(0); + + loop {} +} + +#[allow(unconditional_recursion)] +fn eat_up_stack(v: u32) { + println!("Iteration {v}"); + eat_up_stack(v + 1); +} + +#[interrupt] +fn ASSIST_DEBUG() { + critical_section::with(|cs| { + println!("\n\nDEBUG_ASSIST interrupt"); + let mut da = DA.borrow_ref_mut(cs); + let da = da.as_mut().unwrap(); + + if da.is_region0_monitor_interrupt_set() { + println!("REGION0 MONITOR TRIGGERED"); + da.clear_region0_monitor_interrupt(); + let pc = da.get_region_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + if da.is_region1_monitor_interrupt_set() { + println!("REGION1 MONITOR TRIGGERED"); + da.clear_region1_monitor_interrupt(); + let pc = da.get_region_monitor_pc(); + println!("PC = 0x{:x}", pc); + } + + loop {} + }); +}