diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ade05f1132..f6e78481f5a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add octal PSRAM support for ESP32-S3 (#610) - Add MD5 functions from ESP ROM (#618) - Add embassy async `read` support for `uart` (#620) +- Add bare-bones support to run code on ULP-RISCV / LP core (#631) ### Changed diff --git a/esp-hal-common/devices/esp32c6.toml b/esp-hal-common/devices/esp32c6.toml index cb1705fb406..2b1a48761e2 100644 --- a/esp-hal-common/devices/esp32c6.toml +++ b/esp-hal-common/devices/esp32c6.toml @@ -79,6 +79,7 @@ peripherals = [ "bt", "wifi", "ieee802154", + "lp_core", # ROM capabilities "rom_crc_le", diff --git a/esp-hal-common/devices/esp32s2.toml b/esp-hal-common/devices/esp32s2.toml index 5534775518c..22847ef11e0 100644 --- a/esp-hal-common/devices/esp32s2.toml +++ b/esp-hal-common/devices/esp32s2.toml @@ -54,6 +54,7 @@ peripherals = [ "phy", "wifi", "psram", + "ulp_riscv_core", # ROM capabilities "rom_crc_le", diff --git a/esp-hal-common/devices/esp32s3.toml b/esp-hal-common/devices/esp32s3.toml index 0cafed3ebe9..423f2baeb76 100644 --- a/esp-hal-common/devices/esp32s3.toml +++ b/esp-hal-common/devices/esp32s3.toml @@ -66,6 +66,7 @@ peripherals = [ "bt", "wifi", "psram", + "ulp_riscv_core", # ROM capabilities "rom_crc_le", diff --git a/esp-hal-common/src/lib.rs b/esp-hal-common/src/lib.rs index 8aac5e323a8..f4c24c45d12 100644 --- a/esp-hal-common/src/lib.rs +++ b/esp-hal-common/src/lib.rs @@ -62,9 +62,13 @@ pub use self::rtc_cntl::{Rtc, Rwdt}; pub use self::soc::cpu_control; #[cfg(efuse)] pub use self::soc::efuse; +#[cfg(lp_core)] +pub use self::soc::lp_core; pub use self::soc::peripherals; #[cfg(psram)] pub use self::soc::psram; +#[cfg(ulp_riscv_core)] +pub use self::soc::ulp_core; #[cfg(any(spi0, spi1, spi2, spi3))] pub use self::spi::Spi; #[cfg(any(timg0, timg1))] diff --git a/esp-hal-common/src/soc/esp32c6/lp_core.rs b/esp-hal-common/src/soc/esp32c6/lp_core.rs new file mode 100644 index 00000000000..754198f6869 --- /dev/null +++ b/esp-hal-common/src/soc/esp32c6/lp_core.rs @@ -0,0 +1,79 @@ +//! Control the LP core + +use esp32c6 as pac; + +use crate::peripheral::{Peripheral, PeripheralRef}; + +#[derive(Debug, Clone, Copy)] +pub enum LpCoreWakeupSource { + HpCpu, +} + +pub struct LpCore<'d> { + _lp_core: PeripheralRef<'d, crate::soc::peripherals::LP_CORE>, +} + +impl<'d> LpCore<'d> { + pub fn new(lp_core: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(lp_core); + Self { _lp_core: lp_core } + } + + pub fn stop(&mut self) { + ulp_lp_core_stop(); + } + + pub fn run(&mut self, wakeup_src: LpCoreWakeupSource) { + ulp_lp_core_run(wakeup_src); + } +} + +fn ulp_lp_core_stop() { + let pmu = unsafe { &*pac::PMU::PTR }; + pmu.lp_cpu_pwr1 + .modify(|_, w| unsafe { w.lp_cpu_wakeup_en().bits(0) }); + pmu.lp_cpu_pwr1 + .modify(|_, w| w.lp_cpu_sleep_req().set_bit()); +} + +fn ulp_lp_core_run(wakeup_src: LpCoreWakeupSource) { + let lp_aon = unsafe { &*pac::LP_AON::PTR }; + let pmu = unsafe { &*pac::PMU::PTR }; + let lp_peri = unsafe { &*pac::LP_PERI::PTR }; + + // Enable LP-Core + lp_aon.lpcore.modify(|_, w| w.disable().clear_bit()); + + // Allow LP core to access LP memory during sleep + lp_aon.lpbus.modify(|_, w| w.fast_mem_mux_sel().clear_bit()); + lp_aon + .lpbus + .modify(|_, w| w.fast_mem_mux_sel_update().set_bit()); + + // Enable stall at sleep request + pmu.lp_cpu_pwr0 + .modify(|_, w| w.lp_cpu_slp_stall_en().set_bit()); + + // Enable reset after wake-up + pmu.lp_cpu_pwr0 + .modify(|_, w| w.lp_cpu_slp_reset_en().set_bit()); + + // Set wake-up sources + let src = match wakeup_src { + LpCoreWakeupSource::HpCpu => 0x01, + }; + pmu.lp_cpu_pwr1 + .modify(|_, w| w.lp_cpu_wakeup_en().variant(src)); + + // Enable JTAG debugging + lp_peri + .cpu + .modify(|_, w| w.lpcore_dbgm_unavaliable().clear_bit()); + + // wake up + match wakeup_src { + LpCoreWakeupSource::HpCpu => { + pmu.hp_lp_cpu_comm.write(|w| w.hp_trigger_lp().set_bit()); + } + } +} diff --git a/esp-hal-common/src/soc/esp32c6/mod.rs b/esp-hal-common/src/soc/esp32c6/mod.rs index aae8ec3fc62..1f641540fb0 100644 --- a/esp-hal-common/src/soc/esp32c6/mod.rs +++ b/esp-hal-common/src/soc/esp32c6/mod.rs @@ -1,5 +1,6 @@ pub mod efuse; pub mod gpio; +pub mod lp_core; pub mod peripherals; pub mod radio_clocks; diff --git a/esp-hal-common/src/soc/esp32c6/peripherals.rs b/esp-hal-common/src/soc/esp32c6/peripherals.rs index e6964837cd6..5b14df9cde7 100644 --- a/esp-hal-common/src/soc/esp32c6/peripherals.rs +++ b/esp-hal-common/src/soc/esp32c6/peripherals.rs @@ -71,4 +71,5 @@ crate::peripherals! { UHCI0 => true, USB_DEVICE => true, RADIO => false, + LP_CORE => false, } diff --git a/esp-hal-common/src/soc/esp32s2/mod.rs b/esp-hal-common/src/soc/esp32s2/mod.rs index 80e97678762..e81e5922c01 100644 --- a/esp-hal-common/src/soc/esp32s2/mod.rs +++ b/esp-hal-common/src/soc/esp32s2/mod.rs @@ -4,6 +4,7 @@ pub mod peripherals; #[cfg(psram)] pub mod psram; pub mod radio_clocks; +pub mod ulp_core; pub(crate) mod constants { pub const I2S_SCLK: u32 = 160_000_000; diff --git a/esp-hal-common/src/soc/esp32s2/peripherals.rs b/esp-hal-common/src/soc/esp32s2/peripherals.rs index 94d3bf0390a..9b7eff7d162 100644 --- a/esp-hal-common/src/soc/esp32s2/peripherals.rs +++ b/esp-hal-common/src/soc/esp32s2/peripherals.rs @@ -51,4 +51,5 @@ crate::peripherals! { XTS_AES => true, RADIO => false, PSRAM => false, + ULP_RISCV_CORE => false, } diff --git a/esp-hal-common/src/soc/esp32s2/psram.rs b/esp-hal-common/src/soc/esp32s2/psram.rs index 0b0b2bf48bc..2c594d237bb 100644 --- a/esp-hal-common/src/soc/esp32s2/psram.rs +++ b/esp-hal-common/src/soc/esp32s2/psram.rs @@ -1,7 +1,7 @@ const PSRAM_VADDR: u32 = 0x3f500000; pub fn psram_vaddr_start() -> usize { - unsafe { PSRAM_VADDR_START as usize } + PSRAM_VADDR_START as usize } cfg_if::cfg_if! { diff --git a/esp-hal-common/src/soc/esp32s2/ulp_core.rs b/esp-hal-common/src/soc/esp32s2/ulp_core.rs new file mode 100644 index 00000000000..cde7c9b771b --- /dev/null +++ b/esp-hal-common/src/soc/esp32s2/ulp_core.rs @@ -0,0 +1,109 @@ +//! Control the ULP RISCV core + +use esp32s2 as pac; + +use crate::peripheral::{Peripheral, PeripheralRef}; + +extern "C" { + fn ets_delay_us(delay: u32); +} + +#[derive(Debug, Clone, Copy)] +pub enum UlpCoreWakeupSource { + HpCpu, +} + +pub struct UlpCore<'d> { + _lp_core: PeripheralRef<'d, crate::soc::peripherals::ULP_RISCV_CORE>, +} + +impl<'d> UlpCore<'d> { + pub fn new(lp_core: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(lp_core); + Self { _lp_core: lp_core } + } + + // currently stopping the ULP doesn't work (while following the proedures + // outlines in the TRM) - so don't offer this funtion for now + // + // pub fn stop(&mut self) { + // ulp_stop(); + // } + + pub fn run(&mut self, wakeup_src: UlpCoreWakeupSource) { + ulp_run(wakeup_src); + } +} + +fn ulp_stop() { + let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR }; + rtc_cntl + .ulp_cp_timer + .modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit()); + + // suspends the ulp operation + rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_done().set_bit()); + + // Resets the processor + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_shut_reset_en().set_bit()); +} + +fn ulp_run(wakeup_src: UlpCoreWakeupSource) { + let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR }; + + // Reset COCPU when power on + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_shut_reset_en().set_bit()); + + // Disable ULP timer + rtc_cntl + .ulp_cp_timer + .modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit()); + + // wait for at least 1 RTC_SLOW_CLK cycle + unsafe { + ets_delay_us(20); + } + + // Select ULP-RISC-V to send the DONE signal + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_done_force().set_bit()); + + ulp_config_wakeup_source(wakeup_src); + + // Select RISC-V as the ULP_TIMER trigger target + rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_sel().clear_bit()); + + // Clear any spurious wakeup trigger interrupts upon ULP startup + unsafe { + ets_delay_us(20); + } + + rtc_cntl.int_clr_rtc.write(|w| { + w.cocpu_int_clr() + .set_bit() + .cocpu_trap_int_clr() + .set_bit() + .ulp_cp_int_clr() + .set_bit() + }); +} + +fn ulp_config_wakeup_source(wakeup_src: UlpCoreWakeupSource) { + match wakeup_src { + UlpCoreWakeupSource::HpCpu => { + // use timer to wake up + let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR }; + rtc_cntl + .ulp_cp_ctrl + .modify(|_, w| w.ulp_cp_force_start_top().clear_bit()); + rtc_cntl + .ulp_cp_timer + .modify(|_, w| w.ulp_cp_slp_timer_en().set_bit()); + } + } +} diff --git a/esp-hal-common/src/soc/esp32s3/mod.rs b/esp-hal-common/src/soc/esp32s3/mod.rs index 74511f4fcae..757b10472b9 100644 --- a/esp-hal-common/src/soc/esp32s3/mod.rs +++ b/esp-hal-common/src/soc/esp32s3/mod.rs @@ -5,6 +5,7 @@ pub mod peripherals; #[cfg(psram)] pub mod psram; pub mod radio_clocks; +pub mod ulp_core; pub(crate) mod constants { pub const I2S_SCLK: u32 = 160_000_000; diff --git a/esp-hal-common/src/soc/esp32s3/peripherals.rs b/esp-hal-common/src/soc/esp32s3/peripherals.rs index f1f65741a7a..74aa1285951 100644 --- a/esp-hal-common/src/soc/esp32s3/peripherals.rs +++ b/esp-hal-common/src/soc/esp32s3/peripherals.rs @@ -62,4 +62,5 @@ crate::peripherals! { XTS_AES => true, RADIO => false, PSRAM => false, + ULP_RISCV_CORE => false, } diff --git a/esp-hal-common/src/soc/esp32s3/ulp_core.rs b/esp-hal-common/src/soc/esp32s3/ulp_core.rs new file mode 100644 index 00000000000..5c90dc2436a --- /dev/null +++ b/esp-hal-common/src/soc/esp32s3/ulp_core.rs @@ -0,0 +1,138 @@ +//! Control the ULP RISCV core + +use esp32s3 as pac; + +use crate::peripheral::{Peripheral, PeripheralRef}; + +extern "C" { + fn ets_delay_us(delay: u32); +} + +#[derive(Debug, Clone, Copy)] +pub enum UlpCoreWakeupSource { + HpCpu, +} + +pub struct UlpCore<'d> { + _lp_core: PeripheralRef<'d, crate::soc::peripherals::ULP_RISCV_CORE>, +} + +impl<'d> UlpCore<'d> { + pub fn new(lp_core: impl Peripheral

+ 'd) -> Self { + crate::into_ref!(lp_core); + Self { _lp_core: lp_core } + } + + pub fn stop(&mut self) { + ulp_stop(); + } + + pub fn run(&mut self, wakeup_src: UlpCoreWakeupSource) { + ulp_run(wakeup_src); + } +} + +fn ulp_stop() { + let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR }; + rtc_cntl + .ulp_cp_timer + .modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit()); + + // suspends the ulp operation + rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_done().set_bit()); + + // Resets the processor + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_shut_reset_en().set_bit()); + + unsafe { + ets_delay_us(20); + } + + // above doesn't seem to halt the ULP core - this will + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_clkgate_en().clear_bit()); +} + +fn ulp_run(wakeup_src: UlpCoreWakeupSource) { + let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR }; + + // Reset COCPU when power on + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_shut_reset_en().set_bit()); + + // The coprocessor cpu trap signal doesnt have a stable reset value, + // force ULP-RISC-V clock on to stop RTC_COCPU_TRAP_TRIG_EN from waking the CPU + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_clk_fo().set_bit()); + + // Disable ULP timer + rtc_cntl + .ulp_cp_timer + .modify(|_, w| w.ulp_cp_slp_timer_en().clear_bit()); + + // wait for at least 1 RTC_SLOW_CLK cycle + unsafe { + ets_delay_us(20); + } + + // We do not select RISC-V as the Coprocessor here as this could lead to a hang + // in the main CPU. Instead, we reset RTC_CNTL_COCPU_SEL after we have enabled + // the ULP timer. + // + // IDF-4510 + + // Select ULP-RISC-V to send the DONE signal + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_done_force().set_bit()); + + // Set the CLKGATE_EN signal + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_clkgate_en().set_bit()); + + ulp_config_wakeup_source(wakeup_src); + + // Select RISC-V as the ULP_TIMER trigger target + // Selecting the RISC-V as the Coprocessor at the end is a workaround + // for the hang issue recorded in IDF-4510. + rtc_cntl.cocpu_ctrl.modify(|_, w| w.cocpu_sel().clear_bit()); + + // Clear any spurious wakeup trigger interrupts upon ULP startup + unsafe { + ets_delay_us(20); + } + + rtc_cntl.int_clr_rtc.write(|w| { + w.cocpu_int_clr() + .set_bit() + .cocpu_trap_int_clr() + .set_bit() + .ulp_cp_int_clr() + .set_bit() + }); + + rtc_cntl + .cocpu_ctrl + .modify(|_, w| w.cocpu_clkgate_en().set_bit()); +} + +fn ulp_config_wakeup_source(wakeup_src: UlpCoreWakeupSource) { + match wakeup_src { + UlpCoreWakeupSource::HpCpu => { + // use timer to wake up + let rtc_cntl = unsafe { &*pac::RTC_CNTL::PTR }; + rtc_cntl + .ulp_cp_ctrl + .modify(|_, w| w.ulp_cp_force_start_top().clear_bit()); + rtc_cntl + .ulp_cp_timer + .modify(|_, w| w.ulp_cp_slp_timer_en().set_bit()); + } + } +} diff --git a/esp32c6-hal/examples/lp_core_basic.rs b/esp32c6-hal/examples/lp_core_basic.rs new file mode 100644 index 00000000000..1689a3f983f --- /dev/null +++ b/esp32c6-hal/examples/lp_core_basic.rs @@ -0,0 +1,83 @@ +//! This shows a very basic example of running code on the LP core. +//! +//! Code on LP core just increments a counter. The current value is printed by +//! the HP core. + +#![no_std] +#![no_main] + +use esp32c6_hal::{ + clock::ClockControl, + peripherals::Peripherals, + prelude::*, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use esp_hal_common::lp_core; +use esp_println::println; + +// 50000000 <_start>: +// 50000000: 00000517 auipc a0,0x0 +// 50000004: 01050513 addi a0,a0,16 # 50000010 +// 50000008: 4581 li a1,0 +// +// 5000000a <_loop>: +// 5000000a: 0585 addi a1,a1,1 +// 5000000c: c10c sw a1,0(a0) +// 5000000e: bff5 j 5000000a <_loop> +// +// 50000010 : +// 50000010: 0000 0000 + +const CODE: &[u8] = &[ + 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf, + 0x00, 0x00, 0x00, 0x00, +]; + +#[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 lp_core = esp32c6_hal::lp_core::LpCore::new(peripherals.LP_CORE); + lp_core.stop(); + println!("lp core stopped"); + + // copy code to LP ram + let lp_ram = 0x5000_0000 as *mut u8; + unsafe { + core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len()); + } + println!("copied code (len {})", CODE.len()); + + // start LP core + lp_core.run(lp_core::LpCoreWakeupSource::HpCpu); + println!("lpcore run"); + + let data = (0x5000_0010 - 0) as *mut u32; + loop { + println!("Current {}", unsafe { data.read_volatile() }); + } +} diff --git a/esp32s2-hal/examples/ulp_riscv_core_basic.rs b/esp32s2-hal/examples/ulp_riscv_core_basic.rs new file mode 100644 index 00000000000..02cd16098ec --- /dev/null +++ b/esp32s2-hal/examples/ulp_riscv_core_basic.rs @@ -0,0 +1,72 @@ +//! This shows a very basic example of running code on the ULP RISCV core. +//! +//! Code on ULP core just increments a counter. The current value is printed by +//! the HP core. + +#![no_std] +#![no_main] + +use esp32s2_hal::{ + clock::ClockControl, + peripherals::Peripherals, + prelude::*, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; + +// 50000000 <_start>: +// 50000000: 00000517 auipc a0,0x0 +// 50000004: 01050513 addi a0,a0,16 # 50000010 +// 50000008: 4581 li a1,0 +// +// 5000000a <_loop>: +// 5000000a: 0585 addi a1,a1,1 +// 5000000c: c10c sw a1,0(a0) +// 5000000e: bff5 j 5000000a <_loop> +// +// 50000010 : +// 50000010: 0000 0000 + +const CODE: &[u8] = &[ + 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf, + 0x00, 0x00, 0x00, 0x00, +]; + +#[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 ulp_core = esp32s2_hal::ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE); + + // copy code to RTC ram + let lp_ram = 0x5000_0000 as *mut u8; + unsafe { + core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len()); + } + println!("copied code (len {})", CODE.len()); + + // start ULP core + ulp_core.run(esp32s2_hal::ulp_core::UlpCoreWakeupSource::HpCpu); + println!("ulpcore run"); + + let data = (0x5000_0010 - 0) as *mut u32; + loop { + println!("Current {}", unsafe { data.read_volatile() }); + } +} diff --git a/esp32s3-hal/examples/ulp_riscv_core_basic.rs b/esp32s3-hal/examples/ulp_riscv_core_basic.rs new file mode 100644 index 00000000000..90acbc7262f --- /dev/null +++ b/esp32s3-hal/examples/ulp_riscv_core_basic.rs @@ -0,0 +1,74 @@ +//! This shows a very basic example of running code on the ULP RISCV core. +//! +//! Code on ULP core just increments a counter. The current value is printed by +//! the HP core. + +#![no_std] +#![no_main] + +use esp32s3_hal::{ + clock::ClockControl, + peripherals::Peripherals, + prelude::*, + timer::TimerGroup, + Rtc, +}; +use esp_backtrace as _; +use esp_println::println; + +// 50000000 <_start>: +// 50000000: 00000517 auipc a0,0x0 +// 50000004: 01050513 addi a0,a0,16 # 50000010 +// 50000008: 4581 li a1,0 +// +// 5000000a <_loop>: +// 5000000a: 0585 addi a1,a1,1 +// 5000000c: c10c sw a1,0(a0) +// 5000000e: bff5 j 5000000a <_loop> +// +// 50000010 : +// 50000010: 0000 0000 + +const CODE: &[u8] = &[ + 0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x05, 0x01, 0x81, 0x45, 0x85, 0x05, 0x0c, 0xc1, 0xf5, 0xbf, + 0x00, 0x00, 0x00, 0x00, +]; + +#[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 ulp_core = esp32s3_hal::ulp_core::UlpCore::new(peripherals.ULP_RISCV_CORE); + ulp_core.stop(); + println!("ulp core stopped"); + + // copy code to RTC ram + let lp_ram = 0x5000_0000 as *mut u8; + unsafe { + core::ptr::copy_nonoverlapping(CODE as *const _ as *const u8, lp_ram, CODE.len()); + } + println!("copied code (len {})", CODE.len()); + + // start ULP core + ulp_core.run(esp32s3_hal::ulp_core::UlpCoreWakeupSource::HpCpu); + println!("ulpcore run"); + + let data = (0x5000_0010 - 0) as *mut u32; + loop { + println!("Current {}", unsafe { data.read_volatile() }); + } +}