esp_hal/soc/esp32c6/
lp_core.rs

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