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