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#![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
41pub mod prelude {
43 pub use procmacros::entry;
44}
45
46cfg_if::cfg_if! {
47 if #[cfg(feature = "esp32c6")] {
48 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#[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 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}