esp_lp_hal/
lib.rs

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