probe_rs/vendor/espressif/sequences/
esp32s2.rsuse std::{
sync::Arc,
time::{Duration, Instant},
};
use super::esp::EspFlashSizeDetector;
use crate::{
architecture::xtensa::{
communication_interface::{XtensaCommunicationInterface, XtensaError},
sequences::XtensaDebugSequence,
xdm::{self, DebugControlBits, DebugRegisterError},
},
MemoryInterface, Session,
};
#[derive(Debug)]
pub struct ESP32S2 {
inner: EspFlashSizeDetector,
}
impl ESP32S2 {
const RTC_CNTL_BASE: u64 = 0x3f408000;
const OPTIONS0: u64 = Self::RTC_CNTL_BASE;
const CLK_CONF: u64 = Self::RTC_CNTL_BASE + 0x0074;
const STORE4: u64 = Self::RTC_CNTL_BASE + 0x00BC;
const STORE5: u64 = Self::RTC_CNTL_BASE + 0x00C0;
const RTC_CNTL_DIG_PWC_REG: u64 = Self::RTC_CNTL_BASE + 0x8C;
const SW_CPU_STALL: u64 = Self::RTC_CNTL_BASE + 0x00B8;
const RTC_WRITE_PROT: u64 = Self::RTC_CNTL_BASE | 0xAC;
const RTC_WDTCONFIG0: u64 = Self::RTC_CNTL_BASE | 0x94;
const SWD_BASE: u64 = 0x3f408000;
const SWD_WRITE_PROT: u64 = Self::SWD_BASE | 0xB4;
const SWD_CONF: u64 = Self::SWD_BASE | 0xB0;
const SWD_AUTO_FEED_EN: u32 = 1 << 31;
const SWD_WRITE_PROT_KEY: u32 = 0x8f1d312a;
const TIMG0_BASE: u64 = 0x3f41f000;
const TIMG0_WRITE_PROT: u64 = Self::TIMG0_BASE | 0x64;
const TIMG0_WDTCONFIG0: u64 = Self::TIMG0_BASE | 0x48;
const TIMG1_BASE: u64 = 0x3f420000;
const TIMG1_WRITE_PROT: u64 = Self::TIMG1_BASE | 0x64;
const TIMG1_WDTCONFIG0: u64 = Self::TIMG1_BASE | 0x48;
pub fn create() -> Arc<dyn XtensaDebugSequence> {
Arc::new(Self {
inner: EspFlashSizeDetector {
stack_pointer: 0x3ffce000,
load_address: 0x4002c400,
spiflash_peripheral: 0x3f40_2000,
efuse_get_spiconfig_fn: Some(0x4000e4a0),
attach_fn: 0x4001_7004,
},
})
}
fn set_peri_reg_mask(
&self,
core: &mut XtensaCommunicationInterface,
addr: u64,
mask: u32,
value: u32,
) -> Result<(), crate::Error> {
let mut reg = core.read_word_32(addr)?;
reg &= !mask;
reg |= value;
core.write_word_32(addr, reg)?;
Ok(())
}
fn set_stall(
&self,
stall: bool,
core: &mut XtensaCommunicationInterface,
) -> Result<(), crate::Error> {
const STALL_PROCPU_C1_M: u32 = 0x3F << 26;
const STALL_PROCPU_C1: u32 = 0x21 << 26;
const STALL_PROCPU_C0_M: u32 = 0x3 << 2;
const STALL_PROCPU_C0: u32 = 0x2 << 2;
self.set_peri_reg_mask(
core,
Self::SW_CPU_STALL,
STALL_PROCPU_C1_M,
if stall { STALL_PROCPU_C1 } else { 0 },
)?;
self.set_peri_reg_mask(
core,
Self::OPTIONS0,
STALL_PROCPU_C0_M,
if stall { STALL_PROCPU_C0 } else { 0 },
)?;
Ok(())
}
pub(crate) fn stall(
&self,
core: &mut XtensaCommunicationInterface,
) -> Result<(), crate::Error> {
self.set_stall(true, core)
}
pub(crate) fn unstall(
&self,
core: &mut XtensaCommunicationInterface,
) -> Result<(), crate::Error> {
self.set_stall(false, core)
}
}
impl XtensaDebugSequence for ESP32S2 {
fn on_connect(&self, core: &mut XtensaCommunicationInterface) -> Result<(), crate::Error> {
tracing::info!("Disabling ESP32-S2 watchdogs...");
core.write_word_32(Self::SWD_WRITE_PROT, Self::SWD_WRITE_PROT_KEY)?; let current = core.read_word_32(Self::SWD_CONF)?;
core.write_word_32(Self::SWD_CONF, current | Self::SWD_AUTO_FEED_EN)?;
core.write_word_32(Self::SWD_WRITE_PROT, 0x0)?; core.write_word_32(Self::TIMG0_WRITE_PROT, 0x50D83AA1)?; core.write_word_32(Self::TIMG0_WDTCONFIG0, 0x0)?;
core.write_word_32(Self::TIMG0_WRITE_PROT, 0x0)?; core.write_word_32(Self::TIMG1_WRITE_PROT, 0x50D83AA1)?; core.write_word_32(Self::TIMG1_WDTCONFIG0, 0x0)?;
core.write_word_32(Self::TIMG1_WRITE_PROT, 0x0)?; core.write_word_32(Self::RTC_WRITE_PROT, 0x50D83AA1)?; core.write_word_32(Self::RTC_WDTCONFIG0, 0x0)?;
core.write_word_32(Self::RTC_WRITE_PROT, 0x0)?; Ok(())
}
fn detect_flash_size(&self, session: &mut Session) -> Result<Option<usize>, crate::Error> {
self.inner.detect_flash_size(session)
}
fn reset_system_and_halt(
&self,
core: &mut XtensaCommunicationInterface,
timeout: Duration,
) -> Result<(), crate::Error> {
const CLK_CONF_DEF: u32 = 0x1583218;
const SYS_RESET: u32 = 1 << 31;
core.reset_and_halt(timeout)?;
core.write_word_32(Self::STORE4, 0)?;
core.write_word_32(Self::STORE5, 0)?;
core.write_word_32(Self::RTC_CNTL_DIG_PWC_REG, 0)?;
core.write_word_32(Self::CLK_CONF, CLK_CONF_DEF)?;
self.stall(core)?;
core.xdm.debug_control({
let mut control = DebugControlBits(0);
control.set_enable_ocd(true);
control.set_run_stall_in_en(true);
control
})?;
self.set_peri_reg_mask(core, Self::OPTIONS0, SYS_RESET, SYS_RESET)?;
match core.xdm.execute() {
err @ Err(XtensaError::XdmError(
xdm::Error::ExecOverrun
| xdm::Error::InstructionIgnored
| xdm::Error::Xdm {
source: DebugRegisterError::Unexpected(_),
..
},
)) => {
tracing::debug!("Error ignored: {err:?}");
}
other => other?,
}
let start = Instant::now();
std::thread::sleep(Duration::from_millis(100));
while !core.xdm.read_power_status()?.core_was_reset() {
if start.elapsed() > timeout {
return Err(crate::Error::Timeout);
}
std::thread::sleep(Duration::from_millis(10));
}
core.reset_and_halt(timeout)?;
self.unstall(core)?;
core.xdm.debug_control({
let mut control = DebugControlBits(0);
control.set_enable_ocd(true);
control
})?;
Ok(())
}
}