esp_lp_hal/
lib.rs

1//! Bare-metal (`no_std`) HAL for the low power and ultra-low power cores found
2//! in some Espressif devices. Where applicable, drivers implement the
3//! [embedded-hal] traits.
4//!
5//! ## Choosing a device
6//!
7//! Depending on your target device, you need to enable the chip feature
8//! for that device.
9//!
10//! ## Feature Flags
11#![doc = document_features::document_features!()]
12#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
13#![allow(asm_sub_register)]
14#![deny(missing_docs)]
15#![no_std]
16
17use core::arch::global_asm;
18
19pub mod delay;
20pub mod gpio;
21#[cfg(esp32c6)]
22pub mod i2c;
23#[cfg(esp32c6)]
24pub mod uart;
25
26#[cfg(feature = "esp32c6")]
27pub use esp32c6_lp as pac;
28#[cfg(feature = "esp32s2")]
29pub use esp32s2_ulp as pac;
30#[cfg(feature = "esp32s3")]
31pub use esp32s3_ulp as pac;
32
33/// The prelude
34pub mod prelude {
35    pub use procmacros::entry;
36}
37
38cfg_if::cfg_if! {
39    if #[cfg(feature = "esp32c6")] {
40        // LP_FAST_CLK is not very accurate, for now use a rough estimate
41        const LP_FAST_CLK_HZ: u32 = 16_000_000;
42        const XTAL_D2_CLK_HZ: u32 = 20_000_000;
43    } else if #[cfg(feature = "esp32s2")] {
44        const LP_FAST_CLK_HZ: u32 = 8_000_000;
45    } else if #[cfg(feature = "esp32s3")] {
46        const LP_FAST_CLK_HZ: u32 = 17_500_000;
47    }
48}
49
50pub(crate) static mut CPU_CLOCK: u32 = LP_FAST_CLK_HZ;
51
52/// Wake up the HP core
53#[cfg(feature = "esp32c6")]
54pub fn wake_hp_core() {
55    unsafe { &*esp32c6_lp::PMU::PTR }
56        .hp_lp_cpu_comm()
57        .write(|w| w.lp_trigger_hp().set_bit());
58}
59
60#[cfg(feature = "esp32c6")]
61global_asm!(
62    r#"
63    .section    .init.vector, "ax"
64    /* This is the vector table. It is currently empty, but will be populated
65     * with exception and interrupt handlers when this is supported
66     */
67
68    .align  0x4, 0xff
69    .global _vector_table
70    .type _vector_table, @function
71_vector_table:
72    .option push
73    .option norvc
74
75    .rept 32
76    nop
77    .endr
78
79    .option pop
80    .size _vector_table, .-_vector_table
81
82    .section .init, "ax"
83    .global reset_vector
84
85/* The reset vector, jumps to startup code */
86reset_vector:
87    j __start
88
89__start:
90    /* setup the stack pointer */
91    la sp, __stack_top
92    call rust_main
93loop:
94    j loop
95"#
96);
97
98#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
99global_asm!(
100    r#"
101	.section .text.vectors
102	.global irq_vector
103	.global reset_vector
104
105/* The reset vector, jumps to startup code */
106reset_vector:
107	j __start
108
109/* Interrupt handler */
110.balign 16
111irq_vector:
112	ret
113
114	.section .text
115
116__start:
117    /* setup the stack pointer */
118	la sp, __stack_top
119
120	call ulp_riscv_rescue_from_monitor
121	call rust_main
122	call ulp_riscv_halt
123loop:
124	j loop
125"#
126);
127
128#[link_section = ".init.rust"]
129#[export_name = "rust_main"]
130unsafe extern "C" fn lp_core_startup() -> ! {
131    extern "Rust" {
132        fn main() -> !;
133    }
134
135    #[cfg(feature = "esp32c6")]
136    if (*pac::LP_CLKRST::PTR)
137        .lp_clk_conf()
138        .read()
139        .fast_clk_sel()
140        .bit_is_set()
141    {
142        CPU_CLOCK = XTAL_D2_CLK_HZ;
143    }
144
145    main();
146}
147
148#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
149#[link_section = ".init.rust"]
150#[no_mangle]
151unsafe extern "C" fn ulp_riscv_rescue_from_monitor() {
152    // Rescue RISC-V core from monitor state.
153    unsafe { &*pac::RTC_CNTL::PTR }
154        .cocpu_ctrl()
155        .modify(|_, w| w.cocpu_done().clear_bit().cocpu_shut_reset_en().clear_bit());
156}
157
158#[cfg(any(feature = "esp32s2", feature = "esp32s3"))]
159#[link_section = ".init.rust"]
160#[no_mangle]
161unsafe extern "C" fn ulp_riscv_halt() {
162    unsafe { &*pac::RTC_CNTL::PTR }
163        .cocpu_ctrl()
164        .modify(|_, w| unsafe { w.cocpu_shut_2_clk_dis().bits(0x3f).cocpu_done().set_bit() });
165
166    loop {
167        riscv::asm::wfi();
168    }
169}