esp_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-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 all Espressif ESP32 devices.
6//!
7//! This documentation is built for the
8#![cfg_attr(esp32, doc = "**ESP32**")]
9#![cfg_attr(esp32s2, doc = "**ESP32-S2**")]
10#![cfg_attr(esp32s3, doc = "**ESP32-S3**")]
11#![cfg_attr(esp32c2, doc = "**ESP32-C2**")]
12#![cfg_attr(esp32c3, doc = "**ESP32-C3**")]
13#![cfg_attr(esp32c6, doc = "**ESP32-C6**")]
14#![cfg_attr(esp32h2, doc = "**ESP32-H2**")]
15//! . Please ensure you are reading the correct [documentation] for your target
16//! device.
17//!
18//! ## Choosing a Device
19//!
20//! Depending on your target device, you need to enable the chip feature
21//! for that device. You may also need to do this on ancillary esp-hal crates.
22//!
23//! ## Overview
24//!
25//! ### Peripheral drivers
26//!
27//! The HAL implements both blocking _and_ async APIs for many peripherals.
28//! Where applicable, driver implement the [embedded-hal] and
29//! [embedded-hal-async] traits.
30//!
31//! ### Peripheral singletons
32//!
33//! Each peripheral driver needs a peripheral singleton that tells the driver
34//! which hardware block to use. The peripheral singletons are created by the
35//! HAL initialization, and are returned from [`init`] as fields of the
36//! [`Peripherals`] struct.
37//!
38//! These singletons, by default, represent peripherals for the entire lifetime
39//! of the program. To allow for reusing peripherals, the HAL provides a
40//! `reborrow` method on each peripheral singleton. This method creates a new
41//! handle to the peripheral with a shorter lifetime. This allows you to pass
42//! the handle to a driver, while still keeping the original handle alive. Once
43//! you drop the driver, you will be able to reborrow the peripheral again.
44//!
45//! For example, if you want to use the [`I2c`](i2c::master::I2c) driver and you
46//! don't intend to drop the driver, you can pass the peripheral singleton to
47//! the driver by value:
48//!
49//! ```rust, ignore
50//! // Peripheral singletons are returned from the `init` function.
51//! let peripherals = esp_hal::init(esp_hal::Config::default());
52//!
53//! let mut i2c = I2C::new(peripherals.I2C0, /* ... */);
54//! ```
55//!
56//! If you want to use the peripheral in multiple places (for example, you want
57//! to drop the driver for some period of time to minimize power consumption),
58//! you can reborrow the peripheral singleton and pass it to the driver by
59//! reference:
60//!
61//! ```rust, ignore
62//! // Note that in this case, `peripherals` needs to be mutable.
63//! let mut peripherals = esp_hal::init(esp_hal::Config::default());
64//!
65//! let i2c = I2C::new(peripherals.I2C0.reborrow(), /* ... */);
66//!
67//! // Do something with the I2C driver...
68//!
69//! core::mem::drop(i2c); // Drop the driver to minimize power consumption.
70//!
71//! // Do something else...
72//!
73//! // You can then take or reborrow the peripheral singleton again.
74//! let i2c = I2C::new(peripherals.I2C0.reborrow(), /* ... */);
75//! ```
76//!
77//! ## Examples
78//!
79//! We have a plethora of [examples] in the esp-hal repository. We use
80//! an [xtask] to automate the building, running, and testing of code and
81//! examples within esp-hal.
82//!
83//! Invoke the following command in the root of the esp-hal repository to get
84//! started:
85//!
86//! ```bash
87//! cargo xtask help
88//! ```
89//!
90//! ## Creating a Project
91//!
92//! We have a [book] that explains the full esp-rs ecosystem
93//! and how to get started, it's advisable to give that a read
94//! before proceeding. We also have a [training] that covers some common
95//! scenarios with examples.
96//!
97//! We have developed a project generation tool, [esp-generate], which we
98//! recommend when starting new projects. It can be installed and run, e.g.
99//! for the ESP32-C6, as follows:
100//!
101//! ```bash
102//! cargo install esp-generate
103//! esp-generate --chip=esp32c6 your-project
104//! ```
105//!
106//! ## Blinky
107//!
108//! Some minimal code to blink an LED looks like this:
109//!
110//! ```rust, no_run
111//! #![no_std]
112//! #![no_main]
113//!
114//! use esp_hal::{
115//!     clock::CpuClock,
116//!     gpio::{Io, Level, Output, OutputConfig},
117//!     main,
118//!     time::{Duration, Instant},
119//! };
120//!
121//! // You need a panic handler. Usually, you you would use esp_backtrace, panic-probe, or
122//! // something similar, but you can also bring your own like this:
123//! #[panic_handler]
124//! fn panic(_: &core::panic::PanicInfo) -> ! {
125//!     esp_hal::system::software_reset()
126//! }
127//!
128//! #[main]
129//! fn main() -> ! {
130//!     let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
131//!     let peripherals = esp_hal::init(config);
132//!
133//!     // Set GPIO0 as an output, and set its state high initially.
134//!     let mut led = Output::new(peripherals.GPIO0, Level::High, OutputConfig::default());
135//!
136//!     loop {
137//!         led.toggle();
138//!         // Wait for half a second
139//!         let delay_start = Instant::now();
140//!         while delay_start.elapsed() < Duration::from_millis(500) {}
141//!     }
142//! }
143//! ```
144//!
145//! ## Additional configuration
146//!
147//! We've exposed some configuration options that don't fit into cargo
148//! features. These can be set via environment variables, or via cargo's `[env]`
149//! section inside `.cargo/config.toml`. Note that unstable options can only be
150//! enabled when the `unstable` feature is enabled for the crate. Below is a
151//! table of tunable parameters for this crate:
152#![doc = ""]
153#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_hal_config_table.md"))]
154#![doc = ""]
155//! ## Don't use `core::mem::forget`
156//!
157//! You should never use `core::mem::forget` on any type defined in the HAL.
158//! Some types heavily rely on their `Drop` implementation to not leave the
159//! hardware in undefined state and causing UB.
160//!
161//! You might want to consider using [`#[deny(clippy::mem_forget)`](https://rust-lang.github.io/rust-clippy/v0.0.212/index.html#mem_forget) in your project.
162//!
163//! ## Library usage
164//!
165//! If you intend to write a library that uses esp-hal, you should import it as follows:
166//!
167//! ```toml
168//! [dependencies]
169//! esp-hal = { version = "1", default-features = false } }
170//! ```
171//!
172//! This ensures that the `rt` feature is not enabled, nor any chip features. The application that
173//! uses your library will then be able to choose the chip feature it needs and enable `rt` such
174//! that only the final user application calls [`init`].
175//!
176//! If your library depends on `unstable` features, you *must* use the `requires-unstable` feature,
177//! and *not* the unstable feature itself. Doing so, improves the quality of the error messages if a
178//! user hasn't enabled the unstable feature of esp-hal.
179//!
180//! [documentation]: https://docs.espressif.com/projects/rust/esp-hal/latest/
181//! [examples]: https://github.com/esp-rs/esp-hal/tree/main/examples
182//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
183//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
184//! [xtask]: https://github.com/matklad/cargo-xtask
185//! [esp-generate]: https://github.com/esp-rs/esp-generate
186//! [book]: https://docs.espressif.com/projects/rust/book/
187//! [training]: https://docs.espressif.com/projects/rust/no_std-training/
188//!
189//! ## Feature Flags
190#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
191#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
192#![allow(asm_sub_register, async_fn_in_trait, stable_features)]
193#![cfg_attr(xtensa, feature(asm_experimental_arch))]
194#![deny(missing_docs, rust_2018_idioms, rustdoc::all)]
195#![allow(rustdoc::private_doc_tests)] // compile tests are done via rustdoc
196#![cfg_attr(docsrs, feature(doc_cfg, custom_inner_attributes, proc_macro_hygiene))]
197// Don't trip up on broken/private links when running semver-checks
198#![cfg_attr(
199    semver_checks,
200    allow(rustdoc::private_intra_doc_links, rustdoc::broken_intra_doc_links)
201)]
202#![no_std]
203
204// MUST be the first module
205mod fmt;
206
207#[macro_use]
208extern crate esp_metadata_generated;
209
210use core::marker::PhantomData;
211
212pub use esp_metadata_generated::chip;
213use esp_rom_sys as _;
214
215metadata!("build_info", CHIP_NAME, chip!());
216
217#[cfg(all(riscv, feature = "rt"))]
218#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", feature = "rt"))))]
219#[cfg_attr(not(feature = "unstable"), doc(hidden))]
220pub use esp_riscv_rt::{self, riscv};
221use esp_sync::RawMutex;
222pub(crate) use peripherals::pac;
223#[cfg(xtensa)]
224#[cfg(all(xtensa, feature = "rt"))]
225#[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", feature = "rt"))))]
226#[cfg_attr(not(feature = "unstable"), doc(hidden))]
227pub use xtensa_lx_rt::{self, xtensa_lx};
228
229#[cfg(lp_core)]
230#[instability::unstable]
231#[cfg_attr(not(feature = "unstable"), allow(unused))]
232pub use self::soc::lp_core;
233#[cfg(ulp_riscv_core)]
234#[instability::unstable]
235#[cfg_attr(not(feature = "unstable"), allow(unused))]
236pub use self::soc::ulp_core;
237
238#[cfg(any(soc_has_dport, soc_has_hp_sys, soc_has_pcr, soc_has_system))]
239pub mod clock;
240#[cfg(soc_has_gpio)]
241pub mod gpio;
242#[cfg(any(soc_has_i2c0, soc_has_i2c1))]
243pub mod i2c;
244pub mod peripherals;
245#[cfg(all(feature = "unstable", any(soc_has_hmac, soc_has_sha)))]
246mod reg_access;
247#[cfg(any(soc_has_spi0, soc_has_spi1, soc_has_spi2, soc_has_spi3))]
248pub mod spi;
249pub mod system;
250pub mod time;
251#[cfg(any(soc_has_uart0, soc_has_uart1, soc_has_uart2))]
252pub mod uart;
253
254mod macros;
255
256#[cfg(feature = "rt")]
257pub use procmacros::blocking_main as main;
258#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
259#[instability::unstable]
260#[cfg_attr(not(feature = "unstable"), allow(unused))]
261pub use procmacros::handler;
262#[cfg(any(lp_core, ulp_riscv_core))]
263#[instability::unstable]
264#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
265pub use procmacros::load_lp_code;
266pub use procmacros::ram;
267
268#[cfg(all(feature = "rt", feature = "exception-handler"))]
269mod exception_handler;
270
271// can't use instability on inline module definitions, see https://github.com/rust-lang/rust/issues/54727
272#[doc(hidden)]
273macro_rules! unstable_module {
274    ($(
275        $(#[$meta:meta])*
276        pub mod $module:ident;
277    )*) => {
278        $(
279            $(#[$meta])*
280            #[cfg(feature = "unstable")]
281            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
282            pub mod $module;
283
284            $(#[$meta])*
285            #[cfg(not(feature = "unstable"))]
286            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
287            #[allow(unused)]
288            pub(crate) mod $module;
289        )*
290    };
291}
292
293// can't use instability on inline module definitions, see https://github.com/rust-lang/rust/issues/54727
294// we don't want unstable drivers to be compiled even, unless enabled
295#[doc(hidden)]
296macro_rules! unstable_driver {
297    ($(
298        $(#[$meta:meta])*
299        pub mod $module:ident;
300    )*) => {
301        $(
302            $(#[$meta])*
303            #[cfg(feature = "unstable")]
304            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
305            pub mod $module;
306        )*
307    };
308}
309
310pub(crate) use unstable_module;
311
312unstable_module! {
313    pub mod asynch;
314    pub mod config;
315    pub mod debugger;
316    #[cfg(any(soc_has_dport, soc_has_interrupt_core0, soc_has_interrupt_core1))]
317    pub mod interrupt;
318    pub mod rom;
319    #[doc(hidden)]
320    pub mod sync;
321    // Drivers needed for initialization or they are tightly coupled to something else.
322    #[cfg(any(adc, dac))]
323    pub mod analog;
324    #[cfg(any(systimer, timergroup))]
325    pub mod timer;
326    #[cfg(soc_has_lpwr)]
327    pub mod rtc_cntl;
328    #[cfg(any(gdma, pdma))]
329    pub mod dma;
330    #[cfg(soc_has_etm)]
331    pub mod etm;
332    #[cfg(soc_has_usb0)]
333    pub mod otg_fs;
334    #[cfg(psram)] // DMA needs some things from here
335    pub mod psram;
336    pub mod efuse;
337    pub mod work_queue;
338}
339
340unstable_driver! {
341    #[cfg(soc_has_aes)]
342    pub mod aes;
343    #[cfg(soc_has_assist_debug)]
344    pub mod assist_debug;
345    pub mod delay;
346    #[cfg(soc_has_ecc)]
347    pub mod ecc;
348    #[cfg(soc_has_hmac)]
349    pub mod hmac;
350    #[cfg(any(soc_has_i2s0, soc_has_i2s1))]
351    pub mod i2s;
352    #[cfg(soc_has_lcd_cam)]
353    pub mod lcd_cam;
354    #[cfg(soc_has_ledc)]
355    pub mod ledc;
356    #[cfg(any(soc_has_mcpwm0, soc_has_mcpwm1))]
357    pub mod mcpwm;
358    #[cfg(soc_has_parl_io)]
359    pub mod parl_io;
360    #[cfg(soc_has_pcnt)]
361    pub mod pcnt;
362    #[cfg(soc_has_rmt)]
363    pub mod rmt;
364    #[cfg(soc_has_rng)]
365    pub mod rng;
366    #[cfg(soc_has_rsa)]
367    pub mod rsa;
368    #[cfg(soc_has_sha)]
369    pub mod sha;
370    #[cfg(touch)]
371    pub mod touch;
372    #[cfg(soc_has_trace0)]
373    pub mod trace;
374    #[cfg(soc_has_tsens)]
375    pub mod tsens;
376    #[cfg(any(soc_has_twai0, soc_has_twai1))]
377    pub mod twai;
378    #[cfg(soc_has_usb_device)]
379    pub mod usb_serial_jtag;
380}
381
382/// State of the CPU saved when entering exception or interrupt
383#[instability::unstable]
384#[cfg(feature = "rt")]
385#[allow(unused_imports)]
386pub mod trapframe {
387    #[cfg(riscv)]
388    pub use esp_riscv_rt::TrapFrame;
389    #[cfg(xtensa)]
390    pub use xtensa_lx_rt::exception::Context as TrapFrame;
391}
392
393// The `soc` module contains chip-specific implementation details and should not
394// be directly exposed.
395mod soc;
396
397#[cfg(is_debug_build)]
398procmacros::warning! {"
399WARNING: use --release
400  We *strongly* recommend using release profile when building esp-hal.
401  The dev profile can potentially be one or more orders of magnitude
402  slower than release, and may cause issues with timing-senstive
403  peripherals and/or devices.
404"}
405
406/// A marker trait for driver modes.
407///
408/// Different driver modes offer different features and different API. Using
409/// this trait as a generic parameter ensures that the driver is initialized in
410/// the correct mode.
411pub trait DriverMode: crate::private::Sealed {}
412
413#[procmacros::doc_replace]
414/// Marker type signalling that a driver is initialized in blocking mode.
415///
416/// Drivers are constructed in blocking mode by default. To learn about the
417/// differences between blocking and async drivers, see the [`Async`] mode
418/// documentation.
419///
420/// [`Async`] drivers can be converted to a [`Blocking`] driver using the
421/// `into_blocking` method, for example:
422///
423/// ```rust, no_run
424/// # {before_snippet}
425/// # use esp_hal::uart::{Config, Uart};
426/// let uart = Uart::new(peripherals.UART0, Config::default())?
427///     .with_rx(peripherals.GPIO1)
428///     .with_tx(peripherals.GPIO2)
429///     .into_async();
430///
431/// let blocking_uart = uart.into_blocking();
432///
433/// # {after_snippet}
434/// ```
435#[derive(Debug)]
436#[non_exhaustive]
437pub struct Blocking;
438
439#[procmacros::doc_replace]
440/// Marker type signalling that a driver is initialized in async mode.
441///
442/// Drivers are constructed in blocking mode by default. To set up an async
443/// driver, a [`Blocking`] driver must be converted to an `Async` driver using
444/// the `into_async` method, for example:
445///
446/// ```rust, no_run
447/// # {before_snippet}
448/// # use esp_hal::uart::{Config, Uart};
449/// let uart = Uart::new(peripherals.UART0, Config::default())?
450///     .with_rx(peripherals.GPIO1)
451///     .with_tx(peripherals.GPIO2)
452///     .into_async();
453///
454/// # {after_snippet}
455/// ```
456///
457/// Drivers can be converted back to blocking mode using the `into_blocking`
458/// method, see [`Blocking`] documentation for more details.
459///
460/// Async mode drivers offer most of the same features as blocking drivers, but
461/// with the addition of async APIs. Interrupt-related functions are not
462/// available in async mode, as they are handled by the driver's interrupt
463/// handlers.
464///
465/// Note that async functions usually take up more space than their blocking
466/// counterparts, and they are generally slower. This is because async functions
467/// are implemented using a state machine that is driven by interrupts and is
468/// polled by a runtime. For short operations, the overhead of the state machine
469/// can be significant. Consider using the blocking functions on the async
470/// driver for small transfers.
471///
472/// When initializing an async driver, the driver disables user-specified
473/// interrupt handlers, and sets up internal interrupt handlers that drive the
474/// driver's async API. The driver's interrupt handlers run on the same core as
475/// the driver was initialized on. This means that the driver can not be sent
476/// across threads, to prevent incorrect concurrent access to the peripheral.
477///
478/// Switching back to blocking mode will disable the interrupt handlers and
479/// return the driver to a state where it can be sent across threads.
480#[derive(Debug)]
481#[non_exhaustive]
482pub struct Async(PhantomData<*const ()>);
483
484unsafe impl Sync for Async {}
485
486impl crate::DriverMode for Blocking {}
487impl crate::DriverMode for Async {}
488impl crate::private::Sealed for Blocking {}
489impl crate::private::Sealed for Async {}
490
491pub(crate) mod private {
492    use core::mem::ManuallyDrop;
493
494    pub trait Sealed {}
495
496    #[non_exhaustive]
497    #[doc(hidden)]
498    /// Magical incantation to gain access to internal APIs.
499    pub struct Internal;
500
501    impl Internal {
502        /// Obtain magical powers to access internal APIs.
503        ///
504        /// # Safety
505        ///
506        /// By calling this function, you accept that you are using an internal
507        /// API that is not guaranteed to be documented, stable, working
508        /// and may change at any time.
509        ///
510        /// You declare that you have tried to look for other solutions, that
511        /// you have opened a feature request or an issue to discuss the
512        /// need for this function.
513        pub unsafe fn conjure() -> Self {
514            Self
515        }
516    }
517
518    pub(crate) struct OnDrop<F: FnOnce()>(ManuallyDrop<F>);
519    impl<F: FnOnce()> OnDrop<F> {
520        pub fn new(cb: F) -> Self {
521            Self(ManuallyDrop::new(cb))
522        }
523
524        pub fn defuse(self) {
525            core::mem::forget(self);
526        }
527    }
528
529    impl<F: FnOnce()> Drop for OnDrop<F> {
530        fn drop(&mut self) {
531            unsafe { (ManuallyDrop::take(&mut self.0))() }
532        }
533    }
534}
535
536#[doc(hidden)]
537pub use private::Internal;
538
539/// Marker trait for types that can be safely used in `#[ram(unstable(persistent))]`.
540///
541/// # Safety
542///
543/// - The type must be inhabited
544/// - The type must be valid for any bit pattern of its backing memory in case a reset occurs during
545///   a write or a reset interrupts the zero initialization on first boot.
546/// - Structs must contain only `Persistable` fields and padding
547#[instability::unstable]
548pub unsafe trait Persistable: Sized {}
549
550/// Marker trait for types that can be safely used in `#[ram(reclaimed)]`.
551///
552/// # Safety
553///
554/// - The type must be some form of `MaybeUninit<T>`
555#[instability::unstable]
556pub unsafe trait Uninit: Sized {}
557
558macro_rules! impl_persistable {
559    ($($t:ty),+) => {$(
560        unsafe impl Persistable for $t {}
561    )+};
562    (atomic $($t:ident),+) => {$(
563        unsafe impl Persistable for portable_atomic::$t {}
564    )+};
565}
566
567impl_persistable!(
568    u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64
569);
570impl_persistable!(atomic AtomicU8, AtomicI8, AtomicU16, AtomicI16, AtomicU32, AtomicI32, AtomicUsize, AtomicIsize);
571
572unsafe impl<T: Persistable, const N: usize> Persistable for [T; N] {}
573
574unsafe impl<T> Uninit for core::mem::MaybeUninit<T> {}
575unsafe impl<T, const N: usize> Uninit for [core::mem::MaybeUninit<T>; N] {}
576
577#[doc(hidden)]
578pub mod __macro_implementation {
579    //! Private implementation details of esp-hal-procmacros.
580
581    #[instability::unstable]
582    pub const fn assert_is_zeroable<T: bytemuck::Zeroable>() {}
583
584    #[instability::unstable]
585    pub const fn assert_is_persistable<T: super::Persistable>() {}
586
587    #[instability::unstable]
588    pub const fn assert_is_uninit<T: super::Uninit>() {}
589
590    #[cfg(feature = "rt")]
591    #[cfg(riscv)]
592    pub use esp_riscv_rt::entry as __entry;
593    #[cfg(feature = "rt")]
594    #[cfg(xtensa)]
595    pub use xtensa_lx_rt::entry as __entry;
596}
597
598use crate::clock::CpuClock;
599#[cfg(feature = "unstable")]
600use crate::config::{WatchdogConfig, WatchdogStatus};
601#[cfg(feature = "rt")]
602use crate::{clock::Clocks, peripherals::Peripherals};
603
604/// A spinlock for seldom called stuff. Users assume that lock contention is not an issue.
605pub(crate) static ESP_HAL_LOCK: RawMutex = RawMutex::new();
606
607/// System configuration.
608///
609/// This `struct` is marked with `#[non_exhaustive]` and can't be instantiated
610/// directly. This is done to prevent breaking changes when new fields are added
611/// to the `struct`. Instead, use the [`Config::default()`] method to create a
612/// new instance.
613///
614/// For usage examples, see the [config module documentation](crate::config).
615#[non_exhaustive]
616#[derive(Default, Clone, Copy, procmacros::BuilderLite)]
617pub struct Config {
618    /// The CPU clock configuration.
619    cpu_clock: CpuClock,
620
621    /// Enable watchdog timer(s).
622    #[cfg(feature = "unstable")]
623    #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
624    #[builder_lite(unstable)]
625    watchdog: WatchdogConfig,
626
627    /// PSRAM configuration.
628    #[cfg(feature = "unstable")]
629    #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
630    #[cfg(feature = "psram")]
631    #[builder_lite(unstable)]
632    psram: psram::PsramConfig,
633}
634
635#[procmacros::doc_replace]
636/// Initialize the system.
637///
638/// This function sets up the CPU clock and watchdog, then, returns the
639/// peripherals and clocks.
640///
641/// # Example
642///
643/// ```rust, no_run
644/// # {before_snippet}
645/// use esp_hal::{Config, init};
646/// let peripherals = init(Config::default());
647/// # {after_snippet}
648/// ```
649#[cfg_attr(docsrs, doc(cfg(feature = "rt")))]
650#[cfg(feature = "rt")]
651pub fn init(config: Config) -> Peripherals {
652    crate::soc::pre_init();
653
654    #[cfg(stack_guard_monitoring)]
655    crate::soc::enable_main_stack_guard_monitoring();
656
657    system::disable_peripherals();
658
659    let mut peripherals = Peripherals::take();
660
661    Clocks::init(config.cpu_clock);
662
663    crate::rtc_cntl::rtc::configure_clock();
664
665    // RTC domain must be enabled before we try to disable
666    let mut rtc = crate::rtc_cntl::Rtc::new(peripherals.LPWR.reborrow());
667
668    #[cfg(any(esp32, esp32s2, esp32s3, esp32c3, esp32c6, esp32c2))]
669    crate::rtc_cntl::sleep::RtcSleepConfig::base_settings(&rtc);
670
671    // Handle watchdog configuration with defaults
672    #[cfg(not(any(esp32, esp32s2)))]
673    rtc.swd.disable();
674
675    rtc.rwdt.disable();
676
677    #[cfg(timergroup_timg0)]
678    crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new().disable();
679
680    #[cfg(timergroup_timg1)]
681    crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new().disable();
682
683    #[cfg(feature = "unstable")]
684    {
685        #[cfg(not(any(esp32, esp32s2)))]
686        if config.watchdog.swd() {
687            rtc.swd.enable();
688        }
689
690        if let WatchdogStatus::Enabled(duration) = config.watchdog.rwdt() {
691            rtc.rwdt
692                .set_timeout(crate::rtc_cntl::RwdtStage::Stage0, duration);
693            rtc.rwdt.enable();
694        }
695
696        #[cfg(timergroup_timg0)]
697        if let WatchdogStatus::Enabled(duration) = config.watchdog.timg0() {
698            let mut timg0_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new();
699            timg0_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration);
700            timg0_wd.enable();
701        }
702
703        #[cfg(timergroup_timg1)]
704        if let WatchdogStatus::Enabled(duration) = config.watchdog.timg1() {
705            let mut timg1_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new();
706            timg1_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration);
707            timg1_wd.enable();
708        }
709    }
710
711    #[cfg(esp32)]
712    crate::time::time_init();
713
714    crate::gpio::interrupt::bind_default_interrupt_handler();
715
716    #[cfg(feature = "psram")]
717    crate::psram::init_psram(config.psram);
718
719    unsafe {
720        esp_rom_sys::init_syscall_table();
721    }
722
723    #[cfg(all(riscv, write_vec_table_monitoring))]
724    crate::soc::setup_trap_section_protection();
725
726    peripherals
727}