esp_hal/soc/esp32c6/lp_core.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//! # Control the LP core
//!
//! ## Overview
//! The `LP_CORE` driver provides an interface for controlling and managing the
//! low power core of `ESP` chips, allowing efficient low power operation and
//! wakeup from sleep based on configurable sources. The low power core is
//! responsible for executing low power tasks while the high power core is in
//! sleep mode.
//!
//! The `LpCore` struct provides methods to stop and run the low power core.
//!
//! The `stop` method stops the low power core, putting it into a sleep state.
//!
//! The `run` method starts the low power core and specifies the wakeup source.
//!
//! ⚠️: The examples for LP Core are quite extensive, so for a more
//! detailed study of how to use this LP Core please visit [the repository
//! with corresponding example].
//!
//! [the repository with corresponding example]: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/lp_core_basic.rs
use esp32c6 as pac;
use crate::peripheral::{Peripheral, PeripheralRef};
/// Represents the possible wakeup sources for the LP (Low Power) core.
#[derive(Debug, Clone, Copy)]
pub enum LpCoreWakeupSource {
/// Wakeup source from the HP (High Performance) CPU.
HpCpu,
}
/// Clock sources for the LP core
#[derive(Debug, Clone, Copy)]
pub enum LpCoreClockSource {
/// 17.5 MHz clock
///
/// Might not be very accurate
RcFastClk,
/// 20 MHz clock
XtalD2Clk,
}
/// Represents the Low Power (LP) core peripheral.
pub struct LpCore<'d> {
_lp_core: PeripheralRef<'d, crate::soc::peripherals::LP_CORE>,
}
impl<'d> LpCore<'d> {
/// Create a new instance using [LpCoreClockSource::RcFastClk]
pub fn new(lp_core: impl Peripheral<P = crate::soc::peripherals::LP_CORE> + 'd) -> Self {
LpCore::new_with_clock(lp_core, LpCoreClockSource::RcFastClk)
}
/// Create a new instance using the given clock
pub fn new_with_clock(
lp_core: impl Peripheral<P = crate::soc::peripherals::LP_CORE> + 'd,
clk_src: LpCoreClockSource,
) -> Self {
crate::into_ref!(lp_core);
match clk_src {
LpCoreClockSource::RcFastClk => unsafe {
(*crate::soc::peripherals::LP_CLKRST::PTR)
.lp_clk_conf()
.modify(|_, w| w.fast_clk_sel().clear_bit());
},
LpCoreClockSource::XtalD2Clk => unsafe {
(*crate::soc::peripherals::LP_CLKRST::PTR)
.lp_clk_conf()
.modify(|_, w| w.fast_clk_sel().set_bit());
},
}
let mut this = Self { _lp_core: lp_core };
this.stop();
// clear all of LP_RAM - this makes sure .bss is cleared without relying
let lp_ram =
unsafe { core::slice::from_raw_parts_mut(0x5000_0000 as *mut u32, 16 * 1024 / 4) };
lp_ram.fill(0u32);
this
}
/// Stop the LP core
pub fn stop(&mut self) {
ulp_lp_core_stop();
}
/// Start the LP core
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| unsafe { w.lp_cpu_wakeup_en().bits(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());
}
}
}