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