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//! [documentation]: https://docs.esp-rs.org/esp-hal
164//! [examples]: https://github.com/esp-rs/esp-hal/tree/main/examples
165//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
166//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
167//! [xtask]: https://github.com/matklad/cargo-xtask
168//! [esp-generate]: https://github.com/esp-rs/esp-generate
169//! [book]: https://docs.esp-rs.org/book/
170//! [training]: https://docs.esp-rs.org/no_std-training/
171//!
172//! ## Feature Flags
173#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
174#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
175#![allow(asm_sub_register, async_fn_in_trait, stable_features)]
176#![cfg_attr(xtensa, feature(asm_experimental_arch))]
177#![deny(missing_docs, rust_2018_idioms, rustdoc::all)]
178#![allow(rustdoc::private_doc_tests)] // compile tests are done via rustdoc
179#![cfg_attr(docsrs, feature(doc_cfg))]
180#![no_std]
181
182// MUST be the first module
183mod fmt;
184
185use core::marker::PhantomData;
186
187metadata!("build_info", CHIP_NAME, crate::chip!());
188
189#[cfg(riscv)]
190#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
191#[cfg_attr(not(feature = "unstable"), doc(hidden))]
192pub use esp_riscv_rt::{self, riscv};
193#[cfg(xtensa)]
194#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
195#[cfg_attr(not(feature = "unstable"), doc(hidden))]
196pub use xtensa_lx_rt::{self, xtensa_lx};
197
198#[cfg(efuse)]
199#[instability::unstable]
200#[cfg_attr(not(feature = "unstable"), allow(unused))]
201pub use self::soc::efuse;
202#[cfg(lp_core)]
203#[instability::unstable]
204#[cfg_attr(not(feature = "unstable"), allow(unused))]
205pub use self::soc::lp_core;
206pub use self::soc::peripherals;
207pub(crate) use self::soc::peripherals::pac;
208#[instability::unstable]
209#[cfg(feature = "psram")]
210pub use self::soc::psram;
211#[cfg(ulp_riscv_core)]
212#[instability::unstable]
213#[cfg_attr(not(feature = "unstable"), allow(unused))]
214pub use self::soc::ulp_core;
215
216#[cfg(any(dport, hp_sys, pcr, system))]
217pub mod clock;
218#[cfg(gpio)]
219pub mod gpio;
220#[cfg(any(i2c0, i2c1))]
221pub mod i2c;
222pub mod peripheral;
223#[cfg(all(feature = "unstable", any(hmac, sha)))]
224mod reg_access;
225#[cfg(any(spi0, spi1, spi2, spi3))]
226pub mod spi;
227pub mod system;
228pub mod time;
229#[cfg(any(uart0, uart1, uart2))]
230pub mod uart;
231
232mod macros;
233
234pub use procmacros::blocking_main as main;
235#[cfg(any(lp_core, ulp_riscv_core))]
236#[cfg(feature = "unstable")]
237#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
238pub use procmacros::load_lp_code;
239#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
240#[instability::unstable]
241#[cfg_attr(not(feature = "unstable"), allow(unused))]
242pub use procmacros::{handler, ram};
243
244// can't use instability on inline module definitions, see https://github.com/rust-lang/rust/issues/54727
245#[doc(hidden)]
246macro_rules! unstable_module {
247    ($(
248        $(#[$meta:meta])*
249        pub mod $module:ident;
250    )*) => {
251        $(
252            $(#[$meta])*
253            #[cfg(feature = "unstable")]
254            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
255            pub mod $module;
256
257            $(#[$meta])*
258            #[cfg(not(feature = "unstable"))]
259            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
260            #[allow(unused)]
261            pub(crate) mod $module;
262        )*
263    };
264}
265
266// can't use instability on inline module definitions, see https://github.com/rust-lang/rust/issues/54727
267// we don't want unstable drivers to be compiled even, unless enabled
268#[doc(hidden)]
269macro_rules! unstable_driver {
270    ($(
271        $(#[$meta:meta])*
272        pub mod $module:ident;
273    )*) => {
274        $(
275            $(#[$meta])*
276            #[cfg(feature = "unstable")]
277            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
278            pub mod $module;
279        )*
280    };
281}
282
283pub(crate) use unstable_driver;
284pub(crate) use unstable_module;
285
286unstable_module! {
287    pub mod asynch;
288    pub mod config;
289    pub mod debugger;
290    #[cfg(any(dport, interrupt_core0, interrupt_core1))]
291    pub mod interrupt;
292    pub mod rom;
293    #[doc(hidden)]
294    pub mod sync;
295    // Drivers needed for initialization or they are tightly coupled to something else.
296    #[cfg(any(adc1, adc2, dac))]
297    pub mod analog;
298    #[cfg(any(systimer, timg0, timg1))]
299    pub mod timer;
300    #[cfg(any(lp_clkrst, rtc_cntl))]
301    pub mod rtc_cntl;
302    #[cfg(any(gdma, pdma))]
303    pub mod dma;
304    #[cfg(soc_etm)]
305    pub mod etm;
306    #[cfg(usb0)]
307    pub mod otg_fs;
308}
309
310unstable_driver! {
311    #[cfg(aes)]
312    pub mod aes;
313    #[cfg(assist_debug)]
314    pub mod assist_debug;
315    #[cfg(any(xtensa, all(riscv, systimer)))]
316    pub mod delay;
317    #[cfg(ecc)]
318    pub mod ecc;
319    #[cfg(hmac)]
320    pub mod hmac;
321    #[cfg(any(i2s0, i2s1))]
322    pub mod i2s;
323    #[cfg(lcd_cam)]
324    pub mod lcd_cam;
325    #[cfg(ledc)]
326    pub mod ledc;
327    #[cfg(any(mcpwm0, mcpwm1))]
328    pub mod mcpwm;
329    #[cfg(parl_io)]
330    pub mod parl_io;
331    #[cfg(pcnt)]
332    pub mod pcnt;
333    #[cfg(rmt)]
334    pub mod rmt;
335    #[cfg(rng)]
336    pub mod rng;
337    #[cfg(rsa)]
338    pub mod rsa;
339    #[cfg(sha)]
340    pub mod sha;
341    #[cfg(touch)]
342    pub mod touch;
343    #[cfg(trace0)]
344    pub mod trace;
345    #[cfg(tsens)]
346    pub mod tsens;
347    #[cfg(any(twai0, twai1))]
348    pub mod twai;
349    #[cfg(usb_device)]
350    pub mod usb_serial_jtag;
351}
352
353/// State of the CPU saved when entering exception or interrupt
354#[instability::unstable]
355#[allow(unused_imports)]
356pub mod trapframe {
357    #[cfg(riscv)]
358    pub use esp_riscv_rt::TrapFrame;
359    #[cfg(xtensa)]
360    pub use xtensa_lx_rt::exception::Context as TrapFrame;
361}
362
363// The `soc` module contains chip-specific implementation details and should not
364// be directly exposed.
365mod soc;
366
367#[cfg(is_debug_build)]
368esp_build::warning! {"
369WARNING: use --release
370  We *strongly* recommend using release profile when building esp-hal.
371  The dev profile can potentially be one or more orders of magnitude
372  slower than release, and may cause issues with timing-senstive
373  peripherals and/or devices.
374"}
375
376/// A marker trait for driver modes.
377///
378/// Different driver modes offer different features and different API. Using
379/// this trait as a generic parameter ensures that the driver is initialized in
380/// the correct mode.
381pub trait DriverMode: crate::private::Sealed {}
382
383/// Marker type signalling that a driver is initialized in blocking mode.
384///
385/// Drivers are constructed in blocking mode by default. To learn about the
386/// differences between blocking and async drivers, see the [`Async`] mode
387/// documentation.
388#[derive(Debug)]
389#[non_exhaustive]
390pub struct Blocking;
391
392/// Marker type signalling that a driver is initialized in async mode.
393///
394/// Drivers are constructed in blocking mode by default. To set up an async
395/// driver, a [`Blocking`] driver must be converted to an `Async` driver using
396/// the `into_async` method. Drivers can be converted back to blocking mode
397/// using the `into_blocking` method.
398///
399/// Async mode drivers offer most of the same features as blocking drivers, but
400/// with the addition of async APIs. Interrupt-related functions are not
401/// available in async mode, as they are handled by the driver's interrupt
402/// handlers.
403///
404/// Note that async functions usually take up more space than their blocking
405/// counterparts, and they are generally slower. This is because async functions
406/// are implemented using a state machine that is driven by interrupts and is
407/// polled by a runtime. For short operations, the overhead of the state machine
408/// can be significant. Consider using the blocking functions on the async
409/// driver for small transfers.
410///
411/// When initializing an async driver, the driver disables user-specified
412/// interrupt handlers, and sets up internal interrupt handlers that drive the
413/// driver's async API. The driver's interrupt handlers run on the same core as
414/// the driver was initialized on. This means that the driver can not be sent
415/// across threads, to prevent incorrect concurrent access to the peripheral.
416///
417/// Switching back to blocking mode will disable the interrupt handlers and
418/// return the driver to a state where it can be sent across threads.
419#[derive(Debug)]
420#[non_exhaustive]
421pub struct Async(PhantomData<*const ()>);
422
423unsafe impl Sync for Async {}
424
425impl crate::DriverMode for Blocking {}
426impl crate::DriverMode for Async {}
427impl crate::private::Sealed for Blocking {}
428impl crate::private::Sealed for Async {}
429
430pub(crate) mod private {
431    use core::mem::ManuallyDrop;
432
433    pub trait Sealed {}
434
435    #[non_exhaustive]
436    #[doc(hidden)]
437    /// Magical incantation to gain access to internal APIs.
438    pub struct Internal;
439
440    impl Internal {
441        /// Obtain magical powers to access internal APIs.
442        ///
443        /// # Safety
444        ///
445        /// By calling this function, you accept that you are using an internal
446        /// API that is not guaranteed to be documented, stable, working
447        /// and may change at any time.
448        ///
449        /// You declare that you have tried to look for other solutions, that
450        /// you have opened a feature request or an issue to discuss the
451        /// need for this function.
452        pub unsafe fn conjure() -> Self {
453            Self
454        }
455    }
456
457    pub(crate) struct OnDrop<F: FnOnce()>(ManuallyDrop<F>);
458    impl<F: FnOnce()> OnDrop<F> {
459        pub fn new(cb: F) -> Self {
460            Self(ManuallyDrop::new(cb))
461        }
462
463        pub fn defuse(self) {
464            core::mem::forget(self);
465        }
466    }
467
468    impl<F: FnOnce()> Drop for OnDrop<F> {
469        fn drop(&mut self) {
470            unsafe { (ManuallyDrop::take(&mut self.0))() }
471        }
472    }
473}
474
475#[cfg(feature = "unstable")]
476#[doc(hidden)]
477pub use private::Internal;
478
479/// Marker trait for types that can be safely used in `#[ram(persistent)]`.
480///
481/// # Safety
482///
483/// - The type must be inhabited
484/// - The type must be valid for any bit pattern of its backing memory in case a
485///   reset occurs during a write or a reset interrupts the zero initialization
486///   on first boot.
487/// - Structs must contain only `Persistable` fields and padding
488#[instability::unstable]
489pub unsafe trait Persistable: Sized {}
490
491macro_rules! impl_persistable {
492    ($($t:ty),+) => {$(
493        unsafe impl Persistable for $t {}
494    )+};
495    (atomic $($t:ident),+) => {$(
496        unsafe impl Persistable for portable_atomic::$t {}
497    )+};
498}
499
500impl_persistable!(
501    u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64
502);
503impl_persistable!(atomic AtomicU8, AtomicI8, AtomicU16, AtomicI16, AtomicU32, AtomicI32, AtomicUsize, AtomicIsize);
504
505unsafe impl<T: Persistable, const N: usize> Persistable for [T; N] {}
506
507#[doc(hidden)]
508pub mod __macro_implementation {
509    //! Private implementation details of esp-hal-procmacros.
510
511    #[instability::unstable]
512    pub const fn assert_is_zeroable<T: bytemuck::Zeroable>() {}
513
514    #[instability::unstable]
515    pub const fn assert_is_persistable<T: super::Persistable>() {}
516
517    #[cfg(riscv)]
518    pub use esp_riscv_rt::entry as __entry;
519    #[cfg(xtensa)]
520    pub use xtensa_lx_rt::entry as __entry;
521}
522
523#[cfg(riscv)]
524#[unsafe(export_name = "hal_main")]
525fn hal_main(a0: usize, a1: usize, a2: usize) -> ! {
526    unsafe extern "Rust" {
527        // This symbol will be provided by the user via `#[entry]`
528        fn main(a0: usize, a1: usize, a2: usize) -> !;
529    }
530
531    unsafe extern "C" {
532        static mut __stack_chk_guard: u32;
533    }
534
535    unsafe {
536        let stack_chk_guard = core::ptr::addr_of_mut!(__stack_chk_guard);
537        // we _should_ use a random value but we don't have a good source for random
538        // numbers here
539        stack_chk_guard.write_volatile(esp_config::esp_config_int!(
540            u32,
541            "ESP_HAL_CONFIG_STACK_GUARD_VALUE"
542        ));
543
544        main(a0, a1, a2);
545    }
546}
547
548#[unsafe(export_name = "__stack_chk_fail")]
549unsafe extern "C" fn stack_chk_fail() {
550    panic!("Stack corruption detected");
551}
552
553#[cfg(feature = "unstable")]
554use crate::config::{WatchdogConfig, WatchdogStatus};
555use crate::{
556    clock::{Clocks, CpuClock},
557    peripherals::Peripherals,
558};
559
560/// System configuration.
561///
562/// This `struct` is marked with `#[non_exhaustive]` and can't be instantiated
563/// directly. This is done to prevent breaking changes when new fields are added
564/// to the `struct`. Instead, use the [`Config::default()`] method to create a
565/// new instance.
566///
567/// For usage examples, see the [config module documentation](crate::config).
568#[non_exhaustive]
569#[derive(Default, Clone, Copy, procmacros::BuilderLite)]
570pub struct Config {
571    /// The CPU clock configuration.
572    cpu_clock: CpuClock,
573
574    /// Enable watchdog timer(s).
575    #[cfg(feature = "unstable")]
576    #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
577    #[builder_lite(unstable)]
578    watchdog: WatchdogConfig,
579
580    /// PSRAM configuration.
581    #[cfg(feature = "unstable")]
582    #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
583    #[cfg(feature = "psram")]
584    #[builder_lite(unstable)]
585    psram: psram::PsramConfig,
586}
587
588/// Initialize the system.
589///
590/// This function sets up the CPU clock and watchdog, then, returns the
591/// peripherals and clocks.
592pub fn init(config: Config) -> Peripherals {
593    crate::soc::pre_init();
594
595    system::disable_peripherals();
596
597    let mut peripherals = Peripherals::take();
598
599    // RTC domain must be enabled before we try to disable
600    let mut rtc = crate::rtc_cntl::Rtc::new(peripherals.LPWR.reborrow());
601
602    // Handle watchdog configuration with defaults
603    cfg_if::cfg_if! {
604        if #[cfg(feature = "unstable")]
605        {
606            #[cfg(not(any(esp32, esp32s2)))]
607            if config.watchdog.swd() {
608                rtc.swd.enable();
609            } else {
610                rtc.swd.disable();
611            }
612
613            match config.watchdog.rwdt() {
614                WatchdogStatus::Enabled(duration) => {
615                    rtc.rwdt.enable();
616                    rtc.rwdt
617                        .set_timeout(crate::rtc_cntl::RwdtStage::Stage0, duration);
618                }
619                WatchdogStatus::Disabled => {
620                    rtc.rwdt.disable();
621                }
622            }
623
624            match config.watchdog.timg0() {
625                WatchdogStatus::Enabled(duration) => {
626                    let mut timg0_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new();
627                    timg0_wd.enable();
628                    timg0_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration);
629                }
630                WatchdogStatus::Disabled => {
631                    crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new().disable();
632                }
633            }
634
635            #[cfg(timg1)]
636            match config.watchdog.timg1() {
637                WatchdogStatus::Enabled(duration) => {
638                    let mut timg1_wd = crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new();
639                    timg1_wd.enable();
640                    timg1_wd.set_timeout(crate::timer::timg::MwdtStage::Stage0, duration);
641                }
642                WatchdogStatus::Disabled => {
643                    crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new().disable();
644                }
645            }
646        }
647        else
648        {
649            #[cfg(not(any(esp32, esp32s2)))]
650            rtc.swd.disable();
651
652            rtc.rwdt.disable();
653
654            crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new().disable();
655
656            #[cfg(timg1)]
657            crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new().disable();
658        }
659    }
660
661    Clocks::init(config.cpu_clock);
662
663    #[cfg(esp32)]
664    crate::time::time_init();
665
666    crate::gpio::interrupt::bind_default_interrupt_handler();
667
668    #[cfg(feature = "psram")]
669    crate::psram::init_psram(config.psram);
670
671    peripherals
672}