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
#![doc = concat!("**", chip_pretty!(), "**")]
9
//! . Please ensure you are reading the correct [documentation] for your target
10
//! device.
11
//!
12
//! ## Overview
13
//!
14
//! esp-hal is a Hardware Abstraction Layer (HAL) for Espressif's ESP32 lineup of
15
//! microcontrollers offering safe, idiomatic APIs to control hardware peripherals.
16
//!
17
//! ### Peripheral drivers
18
//!
19
//! The HAL implements both [`Blocking`] _and_ [`Async`] APIs for all applicable peripherals.
20
//! Where applicable, driver implement the [embedded-hal] and
21
//! [embedded-hal-async] traits. Drivers that do not currently have a stable API
22
//! are marked as `unstable` in the documentation.
23
//!
24
//! ### Peripheral singletons
25
//!
26
//! Each peripheral driver needs a peripheral singleton that tells the driver
27
//! which hardware block to use. The peripheral singletons are created by the
28
//! HAL initialization, and are returned from [`init`] as fields of the
29
//! [`Peripherals`] struct.
30
//!
31
//! These singletons, by default, represent peripherals for the entire lifetime
32
//! of the program. To allow for reusing peripherals, the HAL provides a
33
//! `reborrow` method on each peripheral singleton. This method creates a new
34
//! handle to the peripheral with a shorter lifetime. This lets the handle be
35
//! passed to a driver while keeping the original handle alive. Once the driver
36
//! is dropped, the peripheral can be reborrowed again.
37
#![cfg_attr(
38
    // Feature-gated so that this doesn't prevent gradual device bringup. Any
39
    // stable driver would serve the purpose here, so this block will be part
40
    // of the released documentation.
41
    i2c_master_driver_supported,
42
    doc = r#"
43
For example, if you want to use the [`I2c`](i2c::master::I2c) driver and you
44
do not intend to drop the driver, you can pass the peripheral singleton to
45
the driver by value:
46

            
47
```rust, ignore
48
// Peripheral singletons are returned from the `init` function.
49
let peripherals = esp_hal::init(esp_hal::Config::default());
50

            
51
let mut i2c = I2c::new(peripherals.I2C0, /* ... */);
52
```
53
"#
54
)]
55
//! If you want to use the peripheral in multiple places (for example, you want
56
//! to drop the driver for some period of time to minimize power consumption),
57
//! you can reborrow the peripheral singleton and pass it to the driver by
58
//! reference:
59
//!
60
//! ```rust, ignore
61
//! // Note that in this case, `peripherals` needs to be mutable.
62
//! let mut peripherals = esp_hal::init(esp_hal::Config::default());
63
//!
64
//! let i2c = I2C::new(peripherals.I2C0.reborrow(), /* ... */);
65
//!
66
//! // Do something with the I2C driver...
67
//!
68
//! core::mem::drop(i2c); // Drop the driver to minimize power consumption.
69
//!
70
//! // Do something else...
71
//!
72
//! // You can then take or reborrow the peripheral singleton again.
73
//! let i2c = I2C::new(peripherals.I2C0.reborrow(), /* ... */);
74
//! ```
75
//!
76
//! ## Examples
77
//!
78
//! We have a plethora of [examples] in the esp-hal repository. We use
79
//! an [xtask] to automate the building, running, and testing of code and
80
//! examples within esp-hal.
81
//!
82
//! Invoke the following command in the root of the esp-hal repository to get
83
//! started:
84
//!
85
//! ```bash
86
//! cargo xtask help
87
//! ```
88
//!
89
//! ## Creating a Project
90
//!
91
//! We have a [book] that explains the full esp-hal ecosystem
92
//! and how to get started, it is advisable to give that a read
93
//! before proceeding. We also have a [training] that covers some common
94
//! scenarios with examples.
95
//!
96
//! We have developed a project generation tool, [esp-generate], which we
97
//! recommend when starting new projects. It can be installed and run, e.g.
98
//! for the ESP32-C6, as follows:
99
//!
100
//! ```bash
101
//! cargo install esp-generate
102
//! esp-generate --chip=esp32c6 your-project
103
//! ```
104
#![cfg_attr(
105
    // Feature-gated so that this doesn't prevent gradual device bringup. Any
106
    // stable driver would serve the purpose here, so this block will be part
107
    // of the released documentation.
108
    gpio_driver_supported,
109
    doc = r#"
110
## Blinky
111

            
112
Some minimal code to blink an LED looks like this:
113

            
114
```rust, no_run
115
#![no_std]
116
#![no_main]
117

            
118
use esp_hal::{
119
    clock::CpuClock,
120
    gpio::{Io, Level, Output, OutputConfig},
121
    main,
122
    time::{Duration, Instant},
123
};
124

            
125
// You need a panic handler. Usually, you would use esp_backtrace, panic-probe, or
126
// something similar, but you can also bring your own like this:
127
#[panic_handler]
128
fn panic(_: &core::panic::PanicInfo) -> ! {
129
    esp_hal::system::software_reset()
130
}
131

            
132
#[main]
133
fn main() -> ! {
134
    let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
135
    let peripherals = esp_hal::init(config);
136

            
137
    // Set GPIO0 as an output, and set its state high initially.
138
    let mut led = Output::new(peripherals.GPIO0, Level::High, OutputConfig::default());
139

            
140
    loop {
141
        led.toggle();
142
        // Wait for half a second
143
        let delay_start = Instant::now();
144
        while delay_start.elapsed() < Duration::from_millis(500) {}
145
    }
146
}
147
```
148
"#
149
)]
150
//! ## Additional configuration
151
//!
152
//! Some configuration options do not fit into cargo
153
//! features. These can be set via environment variables, or via cargo's `[env]`
154
//! section inside `.cargo/config.toml`. Unstable options can only be
155
//! enabled when the `unstable` feature is enabled for the crate. Below is a
156
//! table of tunable parameters for this crate:
157
#![doc = ""]
158
#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_hal_config_table.md"))]
159
#![doc = ""]
160
//! ## Don't use `core::mem::forget`
161
//!
162
//! You should never use `core::mem::forget` on any type defined in [esp crates].
163
//! Many types heavily rely on their `Drop` implementation to not leave the
164
//! hardware in undefined state which can cause undefined behavior in your program.
165
//!
166
//! 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.
167
//!
168
//! ## Library usage
169
//!
170
//! If you intend to write a library that uses esp-hal, you should import it as follows:
171
//!
172
//! ```toml
173
//! [dependencies]
174
//! esp-hal = { version = "1", default-features = false } }
175
//! ```
176
//!
177
//! This ensures that the `rt` feature is not enabled, nor any chip features. The application that
178
//! uses your library will then be able to choose the chip feature it needs and enable `rt` such
179
//! that only the final user application calls [`init`].
180
//!
181
//! If your library depends on `unstable` features, you *must* use the `requires-unstable` feature,
182
//! and *not* the unstable feature itself. Doing so, improves the quality of the error messages if a
183
//! user hasn't enabled the unstable feature of esp-hal.
184
//!
185
//! [documentation]: https://docs.espressif.com/projects/rust/esp-hal/latest/
186
//! [examples]: https://github.com/esp-rs/esp-hal/tree/main/examples
187
//! [embedded-hal]: https://docs.rs/embedded-hal/latest/embedded_hal/
188
//! [embedded-hal-async]: https://docs.rs/embedded-hal-async/latest/embedded_hal_async/
189
//! [xtask]: https://github.com/matklad/cargo-xtask
190
//! [esp-generate]: https://github.com/esp-rs/esp-generate
191
//! [book]: https://docs.espressif.com/projects/rust/book/
192
//! [training]: https://docs.espressif.com/projects/rust/no_std-training/
193
//! [esp crates]: https://docs.espressif.com/projects/rust/book/introduction/ancillary-crates.html#esp-hal-ecosystem
194
//!
195
//! ## Feature Flags
196
#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
197
#![doc(html_logo_url = "https://docs.espressif.com/projects/rust/esp-rs-grey-bg.svg")]
198
#![allow(asm_sub_register, async_fn_in_trait, stable_features)]
199
#![cfg_attr(xtensa, feature(asm_experimental_arch))]
200
#![deny(missing_docs, rust_2018_idioms, rustdoc::all)]
201
#![allow(rustdoc::private_doc_tests)] // compile tests are done via rustdoc
202
#![cfg_attr(docsrs, feature(doc_cfg, custom_inner_attributes, proc_macro_hygiene))]
203
// Don't trip up on broken/private links when running semver-checks
204
#![cfg_attr(
205
    semver_checks,
206
    allow(rustdoc::private_intra_doc_links, rustdoc::broken_intra_doc_links)
207
)]
208
// Do not document `cfg` gates by default.
209
#![cfg_attr(docsrs, allow(invalid_doc_attributes))] // doc(auto_cfg = false) requires a new nightly (~2025-10-09+)
210
#![cfg_attr(docsrs, doc(auto_cfg = false))]
211
#![no_std]
212

            
213
// MUST be the first module
214
mod fmt;
215

            
216
#[macro_use]
217
extern crate esp_metadata_generated;
218

            
219
// can't use instability on inline module definitions, see https://github.com/rust-lang/rust/issues/54727
220
#[doc(hidden)]
221
macro_rules! unstable_module {
222
    ($(
223
        $(#[$meta:meta])*
224
        pub mod $module:ident;
225
    )*) => {
226
        $(
227
            $(#[$meta])*
228
            #[cfg(feature = "unstable")]
229
            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
230
            pub mod $module;
231

            
232
            $(#[$meta])*
233
            #[cfg(not(feature = "unstable"))]
234
            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
235
            #[allow(unused)]
236
            pub(crate) mod $module;
237
        )*
238
    };
239
}
240

            
241
// can't use instability on inline module definitions, see https://github.com/rust-lang/rust/issues/54727
242
// we don't want unstable drivers to be compiled even, unless enabled
243
#[doc(hidden)]
244
macro_rules! unstable_driver {
245
    ($(
246
        $(#[$meta:meta])*
247
        pub mod $module:ident;
248
    )*) => {
249
        $(
250
            $(#[$meta])*
251
            #[cfg(feature = "unstable")]
252
            #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
253
            pub mod $module;
254
        )*
255
    };
256
}
257

            
258
use core::marker::PhantomData;
259

            
260
pub use esp_metadata_generated::chip;
261
use esp_rom_sys as _;
262
#[allow(unused)]
263
pub(crate) use unstable_driver;
264
pub(crate) use unstable_module;
265

            
266
metadata!("build_info", CHIP_NAME, chip!());
267
metadata!(
268
    "build_info",
269
    MIN_CHIP_REVISION,
270
    esp_config::esp_config_str!("ESP_HAL_CONFIG_MIN_CHIP_REVISION")
271
);
272

            
273
#[cfg(feature = "rt")]
274
cfg_select! {
275
    riscv => {
276
        #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", feature = "rt"))))]
277
        #[cfg_attr(not(feature = "unstable"), doc(hidden))]
278
        pub use esp_riscv_rt::{self, riscv};
279
    }
280
    xtensa => {
281
        #[cfg_attr(docsrs, doc(cfg(all(feature = "unstable", feature = "rt"))))]
282
        #[cfg_attr(not(feature = "unstable"), doc(hidden))]
283
        pub use xtensa_lx_rt::{self, xtensa_lx};
284
    }
285
}
286

            
287
pub(crate) use peripherals::pac;
288
pub(crate) mod private;
289

            
290
#[cfg(any(soc_has_dport, soc_has_hp_sys, soc_has_pcr, soc_has_system))]
291
pub mod clock;
292
#[cfg(gpio_driver_supported)]
293
pub mod gpio;
294
#[cfg(i2c_master_driver_supported)]
295
pub mod i2c;
296
// The I2S driver is unstable, but its clock tree nodes are part of every build.
297
#[cfg(i2s_driver_supported)]
298
#[path = "i2s/clocks/mod.rs"]
299
mod i2s_clocks;
300
pub mod peripherals;
301
#[cfg(all(
302
    feature = "unstable",
303
    any(
304
        hmac_driver_supported,
305
        sha_driver_supported,
306
        ethernet_driver_supported,
307
        mipi_dsi_driver_supported
308
    )
309
))]
310
mod reg_access;
311
#[cfg(rng_driver_supported)]
312
pub mod rng;
313
#[cfg(any(spi_master_driver_supported, spi_slave_driver_supported))]
314
pub mod spi;
315
pub mod system;
316
pub mod time;
317
#[cfg(uart_driver_supported)]
318
pub mod uart;
319

            
320
mod macros;
321

            
322
#[instability::unstable]
323
pub use procmacros::handler;
324
#[instability::unstable]
325
#[cfg(ulp_riscv_driver_supported)]
326
pub use procmacros::load_lp_code;
327
#[cfg(feature = "rt")]
328
pub use procmacros::main;
329
pub use procmacros::ram;
330

            
331
#[instability::unstable]
332
#[cfg(ulp_riscv_driver_supported)]
333
pub use self::soc::lp_core;
334

            
335
#[cfg(all(feature = "rt", feature = "exception-handler"))]
336
mod exception_handler;
337

            
338
pub mod efuse;
339
pub mod interrupt;
340

            
341
unstable_module! {
342
    pub mod asynch;
343
    pub mod debugger;
344
    pub mod rom;
345
    #[doc(hidden)]
346
    pub mod sync;
347
    // Drivers needed for initialization or they are tightly coupled to something else.
348
    #[cfg(any(adc_driver_supported, dac_driver_supported))]
349
    pub mod analog;
350
    #[cfg(any(systimer_driver_supported, timergroup_driver_supported))]
351
    pub mod timer;
352
    #[cfg(soc_has_lpwr)]
353
    pub mod rtc_cntl;
354
    #[cfg(dma_driver_supported)]
355
    pub mod dma;
356
    #[cfg(etm_driver_supported)]
357
    pub mod etm;
358
    #[cfg(soc_has_psram)] // DMA needs some things from here
359
    pub mod psram;
360
}
361

            
362
#[cfg(any(
363
    sha_driver_supported,
364
    rsa_driver_supported,
365
    aes_driver_supported,
366
    ecc_driver_supported
367
))]
368
mod work_queue;
369

            
370
unstable_driver! {
371
    #[cfg(aes_driver_supported)]
372
    pub mod aes;
373
    #[cfg(assist_debug_driver_supported)]
374
    pub mod assist_debug;
375
    #[cfg(canfd_driver_supported)]
376
    pub mod canfd;
377
    pub mod delay;
378
    #[cfg(ecc_driver_supported)]
379
    pub mod ecc;
380
    #[cfg(flash_driver_supported)]
381
    pub mod flash;
382
    #[cfg(hmac_driver_supported)]
383
    pub mod hmac;
384
    #[cfg(i2s_driver_supported)]
385
    pub mod i2s;
386
    #[cfg(soc_has_lcd_cam)]
387
    pub mod lcd_cam;
388
    #[cfg(ledc_driver_supported)]
389
    pub mod ledc;
390
    #[cfg(mcpwm_driver_supported)]
391
    pub mod mcpwm;
392
    #[cfg(parl_io_driver_supported)]
393
    pub mod parl_io;
394
    #[cfg(pcnt_driver_supported)]
395
    pub mod pcnt;
396
    #[cfg(rmt_driver_supported)]
397
    pub mod rmt;
398
    #[cfg(rsa_driver_supported)]
399
    pub mod rsa;
400
    #[cfg(sdmmc_driver_supported)]
401
    pub mod sdmmc;
402
    #[cfg(sha_driver_supported)]
403
    pub mod sha;
404
    #[cfg(sdm_driver_supported)]
405
    pub mod sdm;
406
    #[cfg(touch_driver_supported)]
407
    pub mod touch;
408
    #[cfg(soc_has_trace0)]
409
    pub mod trace;
410
    #[cfg(soc_has_tsens)]
411
    pub mod tsens;
412
    #[cfg(twai_driver_supported)]
413
    pub mod twai;
414
    #[cfg(any(
415
        usb_otg_driver_supported,
416
        usb_otg_hs_driver_supported,
417
        usb_serial_jtag_driver_supported,
418
    ))]
419
    pub mod usb;
420
    #[cfg(ethernet_driver_supported)]
421
    pub mod ethernet;
422
    #[cfg(mipi_dsi_driver_supported)]
423
    pub mod mipi_dsi;
424
}
425

            
426
/// State of the CPU saved when entering exception or interrupt
427
#[instability::unstable]
428
#[cfg(feature = "rt")]
429
#[allow(unused_imports)]
430
pub mod trapframe {
431
    #[cfg(riscv)]
432
    pub use esp_riscv_rt::TrapFrame;
433
    #[cfg(xtensa)]
434
    pub use xtensa_lx_rt::exception::Context as TrapFrame;
435
}
436

            
437
// The `soc` module contains chip-specific implementation details and should not
438
// be directly exposed.
439
mod soc;
440

            
441
// Some PAC-related utility
442
use crate::pac::generic::{Readable, Reg, Resettable, W, Writable};
443

            
444
#[allow(unused)]
445
trait RegisterToggle {
446
    type Reg: Readable + Resettable + Writable;
447

            
448
    /// Toggles bits in the register, applying the given operation to set and clear them.
449
    ///
450
    /// More efficient than two modify calls, because it does not read the register
451
    /// value twice.
452
    fn toggle(&self, op: impl Fn(&mut W<Self::Reg>, bool) -> &mut W<Self::Reg>);
453
}
454

            
455
impl<REG> RegisterToggle for Reg<REG>
456
where
457
    REG: Readable + Resettable + Writable,
458
{
459
    type Reg = REG;
460

            
461
    fn toggle(&self, op: impl Fn(&mut W<REG>, bool) -> &mut W<REG>) {
462
        let bits = self.modify(|_, w| op(w, true));
463

            
464
        self.write(|w| {
465
            unsafe { w.bits(bits) };
466
            op(w, false)
467
        });
468
    }
469
}
470

            
471
#[cfg(is_debug_build)]
472
procmacros::warning! {"
473
WARNING: use --release
474
  We *strongly* recommend using release profile when building esp-hal.
475
  The dev profile can potentially be one or more orders of magnitude
476
  slower than release, and may cause issues with timing-sensitive
477
  peripherals or devices.
478
"}
479

            
480
/// A marker trait for driver modes.
481
///
482
/// Different driver modes offer different features and different API. Using
483
/// this trait as a generic parameter ensures that the driver is initialized in
484
/// the correct mode.
485
pub trait DriverMode: crate::private::Sealed {}
486

            
487
#[procmacros::doc_replace]
488
/// Marker type signaling that a driver is initialized in blocking mode.
489
///
490
/// Drivers are constructed in blocking mode by default. To learn about the
491
/// differences between blocking and async drivers, see the [`Async`] mode
492
/// documentation.
493
///
494
/// [`Async`] drivers can be converted to a [`Blocking`] driver using the
495
/// `into_blocking` method, for example:
496
#[cfg_attr(
497
    // Feature-gated so that this doesn't prevent gradual device bringup. Any
498
    // stable driver would serve the purpose here, so this block will be part
499
    // of the released documentation.
500
    all(uart_driver_supported, gpio_driver_supported),
501
    doc = r#"
502
```rust, no_run
503
# {before_snippet}
504
# use esp_hal::uart::{Config, Uart};
505
let uart = Uart::new(peripherals.UART0, Config::default())?
506
    .with_rx(peripherals.GPIO1)
507
    .with_tx(peripherals.GPIO2)
508
    .into_async();
509
let blocking_uart = uart.into_blocking();
510
# {after_snippet}
511
```
512
"#
513
)]
514
#[derive(Debug)]
515
#[non_exhaustive]
516
pub struct Blocking;
517

            
518
#[procmacros::doc_replace]
519
/// Marker type signaling that a driver is initialized in async mode.
520
///
521
/// Drivers are constructed in blocking mode by default. To set up an async
522
/// driver, a [`Blocking`] driver must be converted to an `Async` driver using
523
/// the `into_async` method, for example:
524
#[cfg_attr(
525
    // Feature-gated so that this doesn't prevent gradual device bringup. Any
526
    // stable driver would serve the purpose here, so this block will be part
527
    // of the released documentation.
528
    all(uart_driver_supported, gpio_driver_supported),
529
    doc = r#"
530
```rust, no_run
531
# {before_snippet}
532
# use esp_hal::uart::{Config, Uart};
533
let uart = Uart::new(peripherals.UART0, Config::default())?
534
    .with_rx(peripherals.GPIO1)
535
    .with_tx(peripherals.GPIO2)
536
    .into_async();
537
///
538
# {after_snippet}
539
```
540
"#
541
)]
542
/// Drivers can be converted back to blocking mode using the `into_blocking`
543
/// method, see [`Blocking`] documentation for more details.
544
///
545
/// Async mode drivers offer most of the same features as blocking drivers, but
546
/// with the addition of async APIs. Interrupt-related functions are not
547
/// available in async mode, as they are handled by the driver's interrupt
548
/// handlers.
549
///
550
/// Async functions usually take up more space than their blocking counterparts,
551
/// and they are generally slower. This is because async functions are implemented
552
/// using a state machine that is driven by interrupts and is polled by a runtime.
553
/// For short operations, the overhead of the state machine can be significant.
554
/// Consider using the blocking functions on the async driver for small transfers.
555
///
556
/// When initializing an async driver, the driver disables user-specified
557
/// interrupt handlers, and sets up internal interrupt handlers that drive the
558
/// driver's async API. The driver's interrupt handlers run on the same core as
559
/// the driver was initialized on. This means that the driver can not be sent
560
/// across threads, to prevent incorrect concurrent access to the peripheral.
561
///
562
/// Switching back to blocking mode will disable the interrupt handlers and
563
/// return the driver to a state where it can be sent across threads.
564
#[derive(Debug)]
565
#[non_exhaustive]
566
pub struct Async(PhantomData<*const ()>);
567

            
568
unsafe impl Sync for Async {}
569

            
570
impl crate::DriverMode for Blocking {}
571
impl crate::DriverMode for Async {}
572
impl crate::private::Sealed for Blocking {}
573
impl crate::private::Sealed for Async {}
574

            
575
#[doc(hidden)]
576
pub use private::Internal;
577

            
578
/// Marker trait for types that can be safely used in `#[ram(unstable(persistent))]`.
579
///
580
/// # Safety
581
///
582
/// - The type must be inhabited
583
/// - The type must be valid for any bit pattern of its backing memory in case a reset occurs during
584
///   a write or a reset interrupts the zero initialization on first boot.
585
/// - Structs must contain only `Persistable` fields and padding
586
#[instability::unstable]
587
pub unsafe trait Persistable: Sized {}
588

            
589
/// Marker trait for types that can be safely used in `#[ram(reclaimed)]`.
590
///
591
/// # Safety
592
///
593
/// - The type must be some form of `MaybeUninit<T>`
594
#[doc(hidden)]
595
pub unsafe trait Uninit: Sized {}
596

            
597
macro_rules! impl_persistable {
598
    ($($t:ty),+) => {$(
599
        unsafe impl Persistable for $t {}
600
    )+};
601
    (atomic $($t:ident),+) => {$(
602
        unsafe impl Persistable for portable_atomic::$t {}
603
    )+};
604
}
605

            
606
impl_persistable!(
607
    u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize, f32, f64
608
);
609
impl_persistable!(atomic AtomicU8, AtomicI8, AtomicU16, AtomicI16, AtomicU32, AtomicI32, AtomicUsize, AtomicIsize);
610

            
611
unsafe impl<T: Persistable, const N: usize> Persistable for [T; N] {}
612

            
613
unsafe impl<T> Uninit for core::mem::MaybeUninit<T> {}
614
unsafe impl<T, const N: usize> Uninit for [core::mem::MaybeUninit<T>; N] {}
615

            
616
#[doc(hidden)]
617
pub mod __macro_implementation {
618
    //! Private implementation details of esp-hal-procmacros.
619

            
620
    #[instability::unstable]
621
    pub const fn assert_is_zeroable<T: bytemuck::Zeroable>() {}
622

            
623
    #[instability::unstable]
624
    pub const fn assert_is_persistable<T: super::Persistable>() {}
625

            
626
    pub const fn assert_is_uninit<T: super::Uninit>() {}
627

            
628
    #[cfg(feature = "rt")]
629
    #[cfg(riscv)]
630
    pub use esp_riscv_rt::entry as __entry;
631
    pub use static_cell;
632
    #[cfg(feature = "rt")]
633
    #[cfg(xtensa)]
634
    pub use xtensa_lx_rt::entry as __entry;
635
}
636

            
637
use crate::clock::{ClockConfig, CpuClock};
638
#[cfg(feature = "rt")]
639
use crate::peripherals::Peripherals;
640

            
641
/// A spinlock for seldom called stuff. Users assume that lock contention is not an issue.
642
#[cfg(feature = "rt")]
643
pub(crate) static ESP_HAL_LOCK: esp_sync::RawMutex = esp_sync::RawMutex::new();
644

            
645
#[procmacros::doc_replace]
646
/// System configuration.
647
///
648
/// This `struct` is marked with `#[non_exhaustive]` and cannot be instantiated
649
/// directly. This is done to prevent breaking changes when new fields are added
650
/// to the `struct`. Instead, use the [`Config::default()`] method to create a
651
/// new instance.
652
///
653
/// # Examples
654
///
655
/// ### Default initialization
656
///
657
/// ```rust, no_run
658
/// # {before_snippet}
659
/// let peripherals = esp_hal::init(esp_hal::Config::default());
660
/// # {after_snippet}
661
/// ```
662
///
663
/// ### Custom initialization
664
/// ```rust, no_run
665
/// # {before_snippet}
666
/// use esp_hal::{clock::CpuClock, time::Duration};
667
/// let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
668
/// let peripherals = esp_hal::init(config);
669
/// # {after_snippet}
670
/// ```
671
#[non_exhaustive]
672
144
#[derive(Default, Clone, Copy, procmacros::BuilderLite)]
673
pub struct Config {
674
    /// The CPU clock configuration.
675
    #[builder_lite(skip)]
676
    cpu_clock: ClockConfig,
677
}
678

            
679
impl Config {
680
    /// Applies a clock configuration.
681
    #[cfg_attr(
682
        feature = "unstable",
683
        doc = r"
684

            
685
With the `unstable` feature enabled, this function accepts both [`ClockConfig`] and [`CpuClock`].
686
"
687
    )]
688
    #[cfg(feature = "unstable")]
689
    pub fn with_cpu_clock(self, cpu_clock: impl Into<ClockConfig>) -> Self {
690
67
        Self {
691
            cpu_clock: cpu_clock.into(),
692
            ..self
693
        }
694
    }
695

            
696
    /// Applies a clock configuration.
697
    #[cfg(not(feature = "unstable"))]
698
    pub fn with_cpu_clock(self, cpu_clock: CpuClock) -> Self {
699
        Self {
700
            cpu_clock: cpu_clock.into(),
701
            ..self
702
        }
703
    }
704

            
705
    /// The CPU clock configuration preset.
706
    ///
707
    /// # Panics
708
    ///
709
    /// Panics if the CPU clock configuration is not **exactly** one of the [`CpuClock`] presets
710
    #[cfg_attr(feature = "unstable", deprecated(note = "Use `clock_config` instead."))] // TODO: mention ClockTree APIs once they are exposed to the user.
711
    pub fn cpu_clock(&self) -> CpuClock {
712
        unwrap!(
713
            self.cpu_clock.try_get_preset(),
714
            "CPU clock configuration is not a preset"
715
        )
716
    }
717

            
718
    /// The CPU clock configuration.
719
    #[instability::unstable]
720
    pub fn clock_config(&self) -> ClockConfig {
721
325
        self.cpu_clock
722
    }
723
}
724

            
725
#[procmacros::doc_replace]
726
/// Initializes the system.
727
///
728
/// Sets up the CPU clock and watchdog, then returns the peripherals and clocks.
729
///
730
/// # Examples
731
///
732
/// ```rust, no_run
733
/// # {before_snippet}
734
/// use esp_hal::{Config, init};
735
/// let peripherals = init(Config::default());
736
/// # {after_snippet}
737
/// ```
738
#[cfg_attr(docsrs, doc(cfg(feature = "rt")))]
739
#[cfg(feature = "rt")]
740
325
pub fn init(config: Config) -> Peripherals {
741
    crate::soc::pre_init();
742

            
743
    let min_rev = esp_config::esp_config_int!(u16, "ESP_HAL_CONFIG_MIN_CHIP_REVISION");
744
    assert!(
745
        crate::efuse::chip_revision() >= crate::efuse::ChipRevision::from_combined(min_rev),
746
        "This chip's hardware revision is older than the minimum required \
747
         v{}.{} (ESP_HAL_CONFIG_MIN_CHIP_REVISION).",
748
        min_rev / 100,
749
        min_rev % 100,
750
    );
751

            
752
    #[cfg(soc_cpu_has_branch_predictor)]
753
    crate::soc::enable_branch_predictor();
754

            
755
    // Have we already overflown the stack?
756
    #[cfg(init_stack_ptr_range_check)]
757
    crate::soc::ensure_stack_pointer_in_range();
758

            
759
    #[cfg(stack_guard_monitoring)]
760
    crate::soc::enable_main_stack_guard_monitoring();
761

            
762
    #[cfg(all(feature = "rt", enable_pmp, riscv))]
763
    crate::soc::enable_pmp();
764

            
765
    system::disable_peripherals();
766

            
767
    let mut peripherals = Peripherals::take();
768

            
769
    crate::clock::init(config.clock_config());
770

            
771
    // RTC domain must be enabled before we try to disable
772
    let mut rtc = crate::rtc_cntl::Rtc::new(peripherals.RTC_TIMER.reborrow());
773

            
774
    #[cfg(sleep_driver_supported)]
775
    crate::rtc_cntl::sleep::init(&rtc);
776

            
777
    // Disable watchdog timers
778
    #[cfg(soc_has_swd_watchdog)]
779
    rtc.swd.disable();
780

            
781
    rtc.rwdt.disable();
782

            
783
    #[cfg(timergroup_timg0)]
784
    crate::timer::timg::Wdt::<crate::peripherals::TIMG0<'static>>::new().disable();
785

            
786
    #[cfg(timergroup_timg1)]
787
    crate::timer::timg::Wdt::<crate::peripherals::TIMG1<'static>>::new().disable();
788

            
789
    crate::time::implem::time_init();
790

            
791
    #[cfg(gpio_driver_supported)]
792
    crate::gpio::interrupt::bind_default_interrupt_handler();
793

            
794
    unsafe {
795
        esp_rom_sys::init_syscall_table();
796
    }
797

            
798
    #[cfg(all(riscv, write_vec_table_monitoring))]
799
    crate::soc::setup_trap_section_protection();
800

            
801
    #[cfg(all(feature = "unstable", multi_core))]
802
    crate::interrupt::ipc::install();
803

            
804
    peripherals
805
325
}