embassy_nrf/
lib.rs

1#![no_std]
2#![allow(async_fn_in_trait)]
3#![cfg_attr(
4    docsrs,
5    doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.embassy.dev/embassy-nrf'>browse the `embassy-nrf` documentation on the Embassy website</a> instead.</p><p>The documentation here on `docs.rs` is built for a single chip only (nRF52840 in particular), while on the Embassy website you can pick your exact chip from the top menu. Available peripherals and their APIs change depending on the chip.</p></div>\n\n"
6)]
7#![doc = include_str!("../README.md")]
8#![warn(missing_docs)]
9
10//! ## Feature flags
11#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
12
13#[cfg(not(any(
14    feature = "_nrf51",
15    feature = "nrf52805",
16    feature = "nrf52810",
17    feature = "nrf52811",
18    feature = "nrf52820",
19    feature = "nrf52832",
20    feature = "nrf52833",
21    feature = "nrf52840",
22    feature = "nrf5340-app-s",
23    feature = "nrf5340-app-ns",
24    feature = "nrf5340-net",
25    feature = "nrf54l15-app-s",
26    feature = "nrf54l15-app-ns",
27    feature = "nrf9160-s",
28    feature = "nrf9160-ns",
29    feature = "nrf9120-s",
30    feature = "nrf9120-ns",
31    feature = "nrf9151-s",
32    feature = "nrf9151-ns",
33    feature = "nrf9161-s",
34    feature = "nrf9161-ns",
35)))]
36compile_error!(
37    "No chip feature activated. You must activate exactly one of the following features:
38    nrf51,
39    nrf52805,
40    nrf52810,
41    nrf52811,
42    nrf52820,
43    nrf52832,
44    nrf52833,
45    nrf52840,
46    nrf5340-app-s,
47    nrf5340-app-ns,
48    nrf5340-net,
49    nrf54l15-app-s,
50    nrf54l15-app-ns,
51    nrf9160-s,
52    nrf9160-ns,
53    nrf9120-s,
54    nrf9120-ns,
55    nrf9151-s,
56    nrf9151-ns,
57    nrf9161-s,
58    nrf9161-ns,
59    "
60);
61
62#[cfg(all(feature = "reset-pin-as-gpio", not(feature = "_nrf52")))]
63compile_error!("feature `reset-pin-as-gpio` is only valid for nRF52 series chips.");
64
65#[cfg(all(feature = "nfc-pins-as-gpio", not(any(feature = "_nrf52", feature = "_nrf5340-app"))))]
66compile_error!("feature `nfc-pins-as-gpio` is only valid for nRF52, or nRF53's application core.");
67
68#[cfg(all(feature = "lfxo-pins-as-gpio", not(feature = "_nrf5340")))]
69compile_error!("feature `lfxo-pins-as-gpio` is only valid for nRF53 series chips.");
70
71// This mod MUST go first, so that the others see its macros.
72pub(crate) mod fmt;
73pub(crate) mod util;
74
75#[cfg(feature = "_time-driver")]
76mod time_driver;
77
78#[cfg(not(feature = "_nrf54l"))] // TODO
79#[cfg(not(feature = "_nrf51"))]
80pub mod buffered_uarte;
81#[cfg(not(feature = "_nrf54l"))] // TODO
82#[cfg(not(feature = "_nrf51"))]
83pub mod egu;
84pub mod gpio;
85#[cfg(not(feature = "_nrf54l"))] // TODO
86#[cfg(feature = "gpiote")]
87pub mod gpiote;
88#[cfg(not(feature = "_nrf54l"))] // TODO
89#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
90pub mod i2s;
91#[cfg(feature = "_nrf5340")]
92pub mod ipc;
93#[cfg(not(feature = "_nrf54l"))] // TODO
94#[cfg(any(
95    feature = "nrf52832",
96    feature = "nrf52833",
97    feature = "nrf52840",
98    feature = "_nrf5340-app"
99))]
100pub mod nfct;
101#[cfg(not(feature = "_nrf54l"))]
102pub mod nvmc;
103#[cfg(feature = "nrf54l15-app-s")]
104pub mod rramc;
105#[cfg(feature = "nrf54l15-app-s")]
106pub use rramc as nvmc;
107#[cfg(not(feature = "_nrf54l"))] // TODO
108#[cfg(any(
109    feature = "nrf52810",
110    feature = "nrf52811",
111    feature = "nrf52832",
112    feature = "nrf52833",
113    feature = "nrf52840",
114    feature = "_nrf5340-app",
115    feature = "_nrf91",
116))]
117pub mod pdm;
118#[cfg(not(feature = "_nrf54l"))] // TODO
119#[cfg(any(feature = "nrf52840", feature = "nrf9160-s", feature = "nrf9160-ns"))]
120pub mod power;
121#[cfg(not(feature = "_nrf54l"))] // TODO
122pub mod ppi;
123#[cfg(not(feature = "_nrf54l"))] // TODO
124#[cfg(not(any(
125    feature = "_nrf51",
126    feature = "nrf52805",
127    feature = "nrf52820",
128    feature = "_nrf5340-net"
129)))]
130pub mod pwm;
131#[cfg(not(feature = "_nrf54l"))] // TODO
132#[cfg(not(any(feature = "_nrf51", feature = "_nrf91", feature = "_nrf5340-net")))]
133pub mod qdec;
134#[cfg(not(feature = "_nrf54l"))] // TODO
135#[cfg(any(feature = "nrf52840", feature = "_nrf5340-app"))]
136pub mod qspi;
137#[cfg(not(feature = "_nrf54l"))] // TODO
138#[cfg(not(any(feature = "_nrf91", feature = "_nrf5340-app")))]
139pub mod radio;
140
141#[cfg(any(
142    feature = "nrf52811",
143    feature = "nrf52820",
144    feature = "nrf52833",
145    feature = "nrf52840",
146    feature = "_nrf5340-net"
147))]
148#[cfg(feature = "_net-driver")]
149pub mod embassy_net_802154_driver;
150
151#[cfg(not(feature = "_nrf54l"))] // TODO
152#[cfg(feature = "_nrf5340")]
153pub mod reset;
154#[cfg(not(feature = "_nrf54l"))] // TODO
155#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
156pub mod rng;
157#[cfg(not(feature = "_nrf54l"))] // TODO
158pub mod rtc;
159#[cfg(not(feature = "_nrf54l"))] // TODO
160#[cfg(not(any(feature = "_nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
161pub mod saadc;
162#[cfg(not(feature = "_nrf54l"))] // TODO
163#[cfg(not(feature = "_nrf51"))]
164pub mod spim;
165#[cfg(not(feature = "_nrf54l"))] // TODO
166#[cfg(not(feature = "_nrf51"))]
167pub mod spis;
168#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf91")))]
169pub mod temp;
170#[cfg(not(feature = "_nrf54l"))] // TODO
171pub mod timer;
172#[cfg(not(feature = "_nrf54l"))] // TODO
173#[cfg(not(feature = "_nrf51"))]
174pub mod twim;
175#[cfg(not(feature = "_nrf54l"))] // TODO
176#[cfg(not(feature = "_nrf51"))]
177pub mod twis;
178#[cfg(not(feature = "_nrf54l"))] // TODO
179#[cfg(not(feature = "_nrf51"))]
180pub mod uarte;
181#[cfg(not(feature = "_nrf54l"))] // TODO
182#[cfg(any(
183    feature = "_nrf5340-app",
184    feature = "nrf52820",
185    feature = "nrf52833",
186    feature = "nrf52840"
187))]
188pub mod usb;
189pub mod wdt;
190
191// This mod MUST go last, so that it sees all the `impl_foo!` macros
192#[cfg_attr(feature = "_nrf51", path = "chips/nrf51.rs")]
193#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")]
194#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")]
195#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")]
196#[cfg_attr(feature = "nrf52820", path = "chips/nrf52820.rs")]
197#[cfg_attr(feature = "nrf52832", path = "chips/nrf52832.rs")]
198#[cfg_attr(feature = "nrf52833", path = "chips/nrf52833.rs")]
199#[cfg_attr(feature = "nrf52840", path = "chips/nrf52840.rs")]
200#[cfg_attr(feature = "_nrf5340-app", path = "chips/nrf5340_app.rs")]
201#[cfg_attr(feature = "_nrf5340-net", path = "chips/nrf5340_net.rs")]
202#[cfg_attr(feature = "_nrf54l15-app", path = "chips/nrf54l15_app.rs")]
203#[cfg_attr(feature = "_nrf9160", path = "chips/nrf9160.rs")]
204#[cfg_attr(feature = "_nrf9120", path = "chips/nrf9120.rs")]
205mod chip;
206
207/// Macro to bind interrupts to handlers.
208///
209/// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`)
210/// and implements the right [crate::interrupt::typelevel::Binding]s for it. You can pass this struct to drivers to
211/// prove at compile-time that the right interrupts have been bound.
212///
213/// Example of how to bind one interrupt:
214///
215/// ```rust,ignore
216/// use embassy_nrf::{bind_interrupts, spim, peripherals};
217///
218/// bind_interrupts!(
219///     /// Binds the SPIM3 interrupt.
220///     struct Irqs {
221///         SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
222///     }
223/// );
224/// ```
225///
226/// Example of how to bind multiple interrupts in a single macro invocation:
227///
228/// ```rust,ignore
229/// use embassy_nrf::{bind_interrupts, spim, twim, peripherals};
230///
231/// bind_interrupts!(struct Irqs {
232///     SPIM3 => spim::InterruptHandler<peripherals::SPI3>;
233///     TWISPI0 => twim::InterruptHandler<peripherals::TWISPI0>;
234/// });
235/// ```
236
237// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
238#[macro_export]
239macro_rules! bind_interrupts {
240    ($(#[$attr:meta])* $vis:vis struct $name:ident {
241        $(
242            $(#[cfg($cond_irq:meta)])?
243            $irq:ident => $(
244                $(#[cfg($cond_handler:meta)])?
245                $handler:ty
246            ),*;
247        )*
248    }) => {
249        #[derive(Copy, Clone)]
250        $(#[$attr])*
251        $vis struct $name;
252
253        $(
254            #[allow(non_snake_case)]
255            #[no_mangle]
256            $(#[cfg($cond_irq)])?
257            unsafe extern "C" fn $irq() {
258                unsafe {
259                    $(
260                        $(#[cfg($cond_handler)])?
261                        <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
262
263                    )*
264                }
265            }
266
267            $(#[cfg($cond_irq)])?
268            $crate::bind_interrupts!(@inner
269                $(
270                    $(#[cfg($cond_handler)])?
271                    unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
272                )*
273            );
274        )*
275    };
276    (@inner $($t:tt)*) => {
277        $($t)*
278    }
279}
280
281// Reexports
282
283#[cfg(feature = "unstable-pac")]
284pub use chip::pac;
285#[cfg(not(feature = "unstable-pac"))]
286pub(crate) use chip::pac;
287pub use chip::{peripherals, Peripherals, EASY_DMA_SIZE};
288pub use embassy_hal_internal::{Peri, PeripheralType};
289
290pub use crate::chip::interrupt;
291#[cfg(feature = "rt")]
292pub use crate::pac::NVIC_PRIO_BITS;
293
294pub mod config {
295    //! Configuration options used when initializing the HAL.
296
297    /// High frequency clock source.
298    pub enum HfclkSource {
299        /// Internal source
300        Internal,
301        /// External source from xtal.
302        ExternalXtal,
303    }
304
305    /// Low frequency clock source
306    pub enum LfclkSource {
307        /// Internal RC oscillator
308        InternalRC,
309        /// Synthesized from the high frequency clock source.
310        #[cfg(not(feature = "_nrf91"))]
311        Synthesized,
312        /// External source from xtal.
313        #[cfg(not(feature = "lfxo-pins-as-gpio"))]
314        ExternalXtal,
315        /// External source from xtal with low swing applied.
316        #[cfg(not(any(feature = "lfxo-pins-as-gpio", feature = "_nrf91", feature = "_nrf54l")))]
317        ExternalLowSwing,
318        /// External source from xtal with full swing applied.
319        #[cfg(not(any(feature = "lfxo-pins-as-gpio", feature = "_nrf91", feature = "_nrf54l")))]
320        ExternalFullSwing,
321    }
322
323    /// SWD access port protection setting.
324    #[non_exhaustive]
325    pub enum Debug {
326        /// Debugging is allowed (APPROTECT is disabled). Default.
327        Allowed,
328        /// Debugging is not allowed (APPROTECT is enabled).
329        Disallowed,
330        /// APPROTECT is not configured (neither to enable it or disable it).
331        /// This can be useful if you're already doing it by other means and
332        /// you don't want embassy-nrf to touch UICR.
333        NotConfigured,
334    }
335
336    /// Settings for enabling the built in DCDC converters.
337    #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91")))]
338    pub struct DcdcConfig {
339        /// Config for the first stage DCDC (VDDH -> VDD), if disabled LDO will be used.
340        #[cfg(feature = "nrf52840")]
341        pub reg0: bool,
342        /// Configure the voltage of the first stage DCDC. It is stored in non-volatile memory (UICR.REGOUT0 register); pass None to not touch it.
343        #[cfg(any(feature = "nrf52840", feature = "nrf52833"))]
344        pub reg0_voltage: Option<Reg0Voltage>,
345        /// Config for the second stage DCDC (VDD -> DEC4), if disabled LDO will be used.
346        pub reg1: bool,
347    }
348
349    ///  Output voltage setting for REG0 regulator stage.
350    #[cfg(any(feature = "nrf52840", feature = "nrf52833"))]
351    pub enum Reg0Voltage {
352        /// 1.8 V
353        _1V8 = 0,
354        /// 2.1 V
355        _2V1 = 1,
356        /// 2.4 V
357        _2V4 = 2,
358        /// 2.7 V
359        _2V7 = 3,
360        /// 3.0 V
361        _3V0 = 4,
362        /// 3.3 V
363        _3V3 = 5,
364        //ERASED = 7, means 1.8V
365    }
366
367    /// Settings for enabling the built in DCDC converters.
368    #[cfg(feature = "_nrf5340-app")]
369    pub struct DcdcConfig {
370        /// Config for the high voltage stage, if disabled LDO will be used.
371        pub regh: bool,
372        /// Configure the voltage of the high voltage stage. It is stored in non-volatile memory (UICR.VREGHVOUT register); pass None to not touch it.
373        #[cfg(feature = "nrf5340-app-s")]
374        pub regh_voltage: Option<ReghVoltage>,
375        /// Config for the main rail, if disabled LDO will be used.
376        pub regmain: bool,
377        /// Config for the radio rail, if disabled LDO will be used.
378        pub regradio: bool,
379    }
380
381    ///  Output voltage setting for VREGH regulator stage.
382    #[cfg(feature = "nrf5340-app-s")]
383    pub enum ReghVoltage {
384        /// 1.8 V
385        _1V8 = 0,
386        /// 2.1 V
387        _2V1 = 1,
388        /// 2.4 V
389        _2V4 = 2,
390        /// 2.7 V
391        _2V7 = 3,
392        /// 3.0 V
393        _3V0 = 4,
394        /// 3.3 V
395        _3V3 = 5,
396        //ERASED = 7, means 1.8V
397    }
398
399    /// Settings for enabling the built in DCDC converter.
400    #[cfg(feature = "_nrf91")]
401    pub struct DcdcConfig {
402        /// Config for the main rail, if disabled LDO will be used.
403        pub regmain: bool,
404    }
405
406    /// Settings for the internal capacitors.
407    #[cfg(feature = "nrf5340-app-s")]
408    pub struct InternalCapacitors {
409        /// Config for the internal capacitors on pins XC1 and XC2.
410        pub hfxo: Option<HfxoCapacitance>,
411        /// Config for the internal capacitors between pins XL1 and XL2.
412        pub lfxo: Option<LfxoCapacitance>,
413    }
414
415    /// Internal capacitance value for the HFXO.
416    #[cfg(feature = "nrf5340-app-s")]
417    #[derive(Copy, Clone)]
418    pub enum HfxoCapacitance {
419        /// 7.0 pF
420        _7_0pF,
421        /// 7.5 pF
422        _7_5pF,
423        /// 8.0 pF
424        _8_0pF,
425        /// 8.5 pF
426        _8_5pF,
427        /// 9.0 pF
428        _9_0pF,
429        /// 9.5 pF
430        _9_5pF,
431        /// 10.0 pF
432        _10_0pF,
433        /// 10.5 pF
434        _10_5pF,
435        /// 11.0 pF
436        _11_0pF,
437        /// 11.5 pF
438        _11_5pF,
439        /// 12.0 pF
440        _12_0pF,
441        /// 12.5 pF
442        _12_5pF,
443        /// 13.0 pF
444        _13_0pF,
445        /// 13.5 pF
446        _13_5pF,
447        /// 14.0 pF
448        _14_0pF,
449        /// 14.5 pF
450        _14_5pF,
451        /// 15.0 pF
452        _15_0pF,
453        /// 15.5 pF
454        _15_5pF,
455        /// 16.0 pF
456        _16_0pF,
457        /// 16.5 pF
458        _16_5pF,
459        /// 17.0 pF
460        _17_0pF,
461        /// 17.5 pF
462        _17_5pF,
463        /// 18.0 pF
464        _18_0pF,
465        /// 18.5 pF
466        _18_5pF,
467        /// 19.0 pF
468        _19_0pF,
469        /// 19.5 pF
470        _19_5pF,
471        /// 20.0 pF
472        _20_0pF,
473    }
474
475    #[cfg(feature = "nrf5340-app-s")]
476    impl HfxoCapacitance {
477        /// The capacitance value times two.
478        pub(crate) const fn value2(self) -> i32 {
479            match self {
480                HfxoCapacitance::_7_0pF => 14,
481                HfxoCapacitance::_7_5pF => 15,
482                HfxoCapacitance::_8_0pF => 16,
483                HfxoCapacitance::_8_5pF => 17,
484                HfxoCapacitance::_9_0pF => 18,
485                HfxoCapacitance::_9_5pF => 19,
486                HfxoCapacitance::_10_0pF => 20,
487                HfxoCapacitance::_10_5pF => 21,
488                HfxoCapacitance::_11_0pF => 22,
489                HfxoCapacitance::_11_5pF => 23,
490                HfxoCapacitance::_12_0pF => 24,
491                HfxoCapacitance::_12_5pF => 25,
492                HfxoCapacitance::_13_0pF => 26,
493                HfxoCapacitance::_13_5pF => 27,
494                HfxoCapacitance::_14_0pF => 28,
495                HfxoCapacitance::_14_5pF => 29,
496                HfxoCapacitance::_15_0pF => 30,
497                HfxoCapacitance::_15_5pF => 31,
498                HfxoCapacitance::_16_0pF => 32,
499                HfxoCapacitance::_16_5pF => 33,
500                HfxoCapacitance::_17_0pF => 34,
501                HfxoCapacitance::_17_5pF => 35,
502                HfxoCapacitance::_18_0pF => 36,
503                HfxoCapacitance::_18_5pF => 37,
504                HfxoCapacitance::_19_0pF => 38,
505                HfxoCapacitance::_19_5pF => 39,
506                HfxoCapacitance::_20_0pF => 40,
507            }
508        }
509    }
510
511    /// Internal capacitance value for the LFXO.
512    #[cfg(feature = "nrf5340-app-s")]
513    pub enum LfxoCapacitance {
514        /// 6 pF
515        _6pF = 1,
516        /// 7 pF
517        _7pF = 2,
518        /// 9 pF
519        _9pF = 3,
520    }
521
522    #[cfg(feature = "nrf5340-app-s")]
523    impl From<LfxoCapacitance> for super::pac::oscillators::vals::Intcap {
524        fn from(t: LfxoCapacitance) -> Self {
525            match t {
526                LfxoCapacitance::_6pF => Self::C6PF,
527                LfxoCapacitance::_7pF => Self::C7PF,
528                LfxoCapacitance::_9pF => Self::C9PF,
529            }
530        }
531    }
532
533    /// Configuration for peripherals. Default configuration should work on any nRF chip.
534    #[non_exhaustive]
535    pub struct Config {
536        /// High frequency clock source.
537        pub hfclk_source: HfclkSource,
538        /// Low frequency clock source.
539        pub lfclk_source: LfclkSource,
540        #[cfg(feature = "nrf5340-app-s")]
541        /// Internal capacitor configuration, for use with the `ExternalXtal` clock source. See
542        /// nrf5340-PS §4.12.
543        pub internal_capacitors: InternalCapacitors,
544        #[cfg(not(any(feature = "_nrf5340-net", feature = "_nrf54l")))]
545        /// DCDC configuration.
546        pub dcdc: DcdcConfig,
547        /// GPIOTE interrupt priority. Should be lower priority than softdevice if used.
548        #[cfg(feature = "gpiote")]
549        pub gpiote_interrupt_priority: crate::interrupt::Priority,
550        /// Time driver interrupt priority. Should be lower priority than softdevice if used.
551        #[cfg(feature = "_time-driver")]
552        pub time_interrupt_priority: crate::interrupt::Priority,
553        /// Enable or disable the debug port.
554        pub debug: Debug,
555    }
556
557    impl Default for Config {
558        fn default() -> Self {
559            Self {
560                // There are hobby nrf52 boards out there without external XTALs...
561                // Default everything to internal so it Just Works. User can enable external
562                // xtals if they know they have them.
563                hfclk_source: HfclkSource::Internal,
564                lfclk_source: LfclkSource::InternalRC,
565                #[cfg(feature = "nrf5340-app-s")]
566                internal_capacitors: InternalCapacitors { hfxo: None, lfxo: None },
567                #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))]
568                dcdc: DcdcConfig {
569                    #[cfg(feature = "nrf52840")]
570                    reg0: false,
571                    #[cfg(any(feature = "nrf52840", feature = "nrf52833"))]
572                    reg0_voltage: None,
573                    reg1: false,
574                },
575                #[cfg(feature = "_nrf5340-app")]
576                dcdc: DcdcConfig {
577                    regh: false,
578                    #[cfg(feature = "nrf5340-app-s")]
579                    regh_voltage: None,
580                    regmain: false,
581                    regradio: false,
582                },
583                #[cfg(feature = "_nrf91")]
584                dcdc: DcdcConfig { regmain: false },
585                #[cfg(feature = "gpiote")]
586                gpiote_interrupt_priority: crate::interrupt::Priority::P0,
587                #[cfg(feature = "_time-driver")]
588                time_interrupt_priority: crate::interrupt::Priority::P0,
589
590                // In NS mode, default to NotConfigured, assuming the S firmware will do it.
591                #[cfg(feature = "_ns")]
592                debug: Debug::NotConfigured,
593                #[cfg(not(feature = "_ns"))]
594                debug: Debug::Allowed,
595            }
596        }
597    }
598}
599
600#[cfg(feature = "_nrf91")]
601#[allow(unused)]
602mod consts {
603    pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32;
604    pub const UICR_HFXOSRC: *mut u32 = 0x00FF801C as *mut u32;
605    pub const UICR_HFXOCNT: *mut u32 = 0x00FF8020 as *mut u32;
606    pub const UICR_SECUREAPPROTECT: *mut u32 = 0x00FF802C as *mut u32;
607    pub const APPROTECT_ENABLED: u32 = 0x0000_0000;
608    #[cfg(feature = "_nrf9120")]
609    pub const APPROTECT_DISABLED: u32 = 0x50FA50FA;
610}
611
612#[cfg(feature = "_nrf5340-app")]
613#[allow(unused)]
614mod consts {
615    pub const UICR_APPROTECT: *mut u32 = 0x00FF8000 as *mut u32;
616    pub const UICR_VREGHVOUT: *mut u32 = 0x00FF8010 as *mut u32;
617    pub const UICR_SECUREAPPROTECT: *mut u32 = 0x00FF801C as *mut u32;
618    pub const UICR_NFCPINS: *mut u32 = 0x00FF8028 as *mut u32;
619    pub const APPROTECT_ENABLED: u32 = 0x0000_0000;
620    pub const APPROTECT_DISABLED: u32 = 0x50FA50FA;
621}
622
623#[cfg(feature = "_nrf5340-net")]
624#[allow(unused)]
625mod consts {
626    pub const UICR_APPROTECT: *mut u32 = 0x01FF8000 as *mut u32;
627    pub const APPROTECT_ENABLED: u32 = 0x0000_0000;
628    pub const APPROTECT_DISABLED: u32 = 0x50FA50FA;
629}
630
631#[cfg(feature = "_nrf52")]
632#[allow(unused)]
633mod consts {
634    pub const UICR_PSELRESET1: *mut u32 = 0x10001200 as *mut u32;
635    pub const UICR_PSELRESET2: *mut u32 = 0x10001204 as *mut u32;
636    pub const UICR_NFCPINS: *mut u32 = 0x1000120C as *mut u32;
637    pub const UICR_APPROTECT: *mut u32 = 0x10001208 as *mut u32;
638    pub const UICR_REGOUT0: *mut u32 = 0x10001304 as *mut u32;
639    pub const APPROTECT_ENABLED: u32 = 0x0000_0000;
640    pub const APPROTECT_DISABLED: u32 = 0x0000_005a;
641}
642
643#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))]
644#[derive(Debug, Copy, Clone, Eq, PartialEq)]
645#[cfg_attr(feature = "defmt", derive(defmt::Format))]
646enum WriteResult {
647    /// Word was written successfully, needs reset.
648    Written,
649    /// Word was already set to the value we wanted to write, nothing was done.
650    Noop,
651    /// Word is already set to something else, we couldn't write the desired value.
652    Failed,
653}
654
655#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))]
656unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult {
657    uicr_write_masked(address, value, 0xFFFF_FFFF)
658}
659
660#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))]
661unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult {
662    let curr_val = address.read_volatile();
663    if curr_val & mask == value & mask {
664        return WriteResult::Noop;
665    }
666
667    // We can only change `1` bits to `0` bits.
668    if curr_val & value & mask != value & mask {
669        return WriteResult::Failed;
670    }
671
672    // Nrf9151 errata 7, need to disable interrups + use DSB https://docs.nordicsemi.com/bundle/errata_nRF9151_Rev2/page/ERR/nRF9151/Rev2/latest/anomaly_151_7.html
673    cortex_m::interrupt::free(|_cs| {
674        let nvmc = pac::NVMC;
675
676        nvmc.config().write(|w| w.set_wen(pac::nvmc::vals::Wen::WEN));
677        while !nvmc.ready().read().ready() {}
678        address.write_volatile(value | !mask);
679        cortex_m::asm::dsb();
680        while !nvmc.ready().read().ready() {}
681        nvmc.config().write(|_| {});
682        while !nvmc.ready().read().ready() {}
683    });
684
685    WriteResult::Written
686}
687
688/// Initialize the `embassy-nrf` HAL with the provided configuration.
689///
690/// This returns the peripheral singletons that can be used for creating drivers.
691///
692/// This should only be called once at startup, otherwise it panics.
693pub fn init(config: config::Config) -> Peripherals {
694    // Do this first, so that it panics if user is calling `init` a second time
695    // before doing anything important.
696    let peripherals = Peripherals::take();
697
698    #[allow(unused_mut)]
699    let mut needs_reset = false;
700
701    // Workaround used in the nrf mdk: file system_nrf91.c , function SystemInit(), after `#if !defined(NRF_SKIP_UICR_HFXO_WORKAROUND)`
702    #[cfg(all(feature = "_nrf91", feature = "_s"))]
703    {
704        let uicr = pac::UICR_S;
705        let hfxocnt = uicr.hfxocnt().read().hfxocnt().to_bits();
706        let hfxosrc = uicr.hfxosrc().read().hfxosrc().to_bits();
707
708        if hfxosrc == 1 {
709            unsafe {
710                let _ = uicr_write(consts::UICR_HFXOSRC, 0);
711            }
712            needs_reset = true;
713        }
714
715        if hfxocnt == 255 {
716            unsafe {
717                let _ = uicr_write(consts::UICR_HFXOCNT, 32);
718            }
719            needs_reset = true;
720        }
721    }
722
723    // GLITCHDET is only accessible for secure code
724    #[cfg(all(feature = "_nrf54l", feature = "_s"))]
725    {
726        // The voltage glitch detectors are automatically enabled after reset.
727        // To save power, the glitch detectors must be disabled when not in use.
728        pac::GLITCHDET.config().write(|w| w.set_enable(false));
729    }
730
731    // Setup debug protection.
732    #[cfg(not(feature = "_nrf51"))]
733    match config.debug {
734        config::Debug::Allowed => {
735            #[cfg(feature = "_nrf52")]
736            unsafe {
737                let variant = (0x1000_0104 as *mut u32).read_volatile();
738                // Get the letter for the build code (b'A' .. b'F')
739                let build_code = (variant >> 8) as u8;
740
741                if build_code >= chip::APPROTECT_MIN_BUILD_CODE {
742                    // Chips with a certain chip type-specific build code or higher have an
743                    // improved APPROTECT ("hardware and software controlled access port protection")
744                    // which needs explicit action by the firmware to keep it unlocked
745                    // See https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/working-with-the-nrf52-series-improved-approtect
746
747                    // UICR.APPROTECT = SwDisabled
748                    let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED);
749                    needs_reset |= res == WriteResult::Written;
750                    // APPROTECT.DISABLE = SwDisabled
751                    (0x4000_0558 as *mut u32).write_volatile(consts::APPROTECT_DISABLED);
752                } else {
753                    // nothing to do on older chips, debug is allowed by default.
754                }
755            }
756
757            #[cfg(feature = "_nrf5340")]
758            unsafe {
759                let p = pac::CTRLAP;
760
761                let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED);
762                needs_reset |= res == WriteResult::Written;
763                p.approtect().disable().write_value(consts::APPROTECT_DISABLED);
764
765                #[cfg(feature = "_nrf5340-app")]
766                {
767                    let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED);
768                    needs_reset |= res == WriteResult::Written;
769                    p.secureapprotect().disable().write_value(consts::APPROTECT_DISABLED);
770                }
771            }
772
773            // TAMPC is only accessible for secure code
774            #[cfg(all(feature = "_nrf54l", feature = "_s"))]
775            {
776                use crate::pac::tampc::vals;
777
778                // UICR cannot be written here, because it can only be written once after an erase all.
779                // The erase all value means that debug access is allowed if permitted by the firmware.
780
781                // Write to TAMPC to permit debug access
782                //
783                // See https://docs.nordicsemi.com/bundle/ps_nrf54L15/page/debug.html#ariaid-title6
784
785                let p = pac::TAMPC;
786
787                // Unlock dbgen
788                p.protect().domain(0).dbgen().ctrl().write(|w| {
789                    w.set_key(vals::DomainDbgenCtrlKey::KEY);
790                    w.set_writeprotection(vals::DomainDbgenCtrlWriteprotection::CLEAR);
791                });
792                p.protect().domain(0).dbgen().ctrl().write(|w| {
793                    w.set_key(vals::DomainDbgenCtrlKey::KEY);
794                    w.set_value(vals::DomainDbgenCtrlValue::HIGH);
795                });
796
797                // Unlock niden
798                p.protect().domain(0).niden().ctrl().write(|w| {
799                    w.set_key(vals::NidenCtrlKey::KEY);
800                    w.set_writeprotection(vals::NidenCtrlWriteprotection::CLEAR);
801                });
802                p.protect().domain(0).niden().ctrl().write(|w| {
803                    w.set_key(vals::NidenCtrlKey::KEY);
804                    w.set_value(vals::NidenCtrlValue::HIGH);
805                });
806
807                p.protect().domain(0).spiden().ctrl().write(|w| {
808                    w.set_key(vals::SpidenCtrlKey::KEY);
809                    w.set_writeprotection(vals::SpidenCtrlWriteprotection::CLEAR);
810                });
811                p.protect().domain(0).spiden().ctrl().write(|w| {
812                    w.set_key(vals::SpidenCtrlKey::KEY);
813                    w.set_value(vals::SpidenCtrlValue::HIGH);
814                });
815
816                p.protect().domain(0).spniden().ctrl().write(|w| {
817                    w.set_key(vals::SpnidenCtrlKey::KEY);
818                    w.set_writeprotection(vals::SpnidenCtrlWriteprotection::CLEAR);
819                });
820                p.protect().domain(0).spniden().ctrl().write(|w| {
821                    w.set_key(vals::SpnidenCtrlKey::KEY);
822                    w.set_value(vals::SpnidenCtrlValue::HIGH);
823                });
824            }
825
826            // nothing to do on the nrf9160, debug is allowed by default.
827
828            // nrf9151, nrf9161 use the new-style approtect that requires writing a register.
829            #[cfg(feature = "nrf9120-s")]
830            unsafe {
831                let p = pac::APPROTECT_S;
832
833                let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED);
834                needs_reset |= res == WriteResult::Written;
835                p.approtect()
836                    .disable()
837                    .write(|w| w.set_disable(pac::approtect::vals::ApprotectDisableDisable::SW_UNPROTECTED));
838
839                let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED);
840                needs_reset |= res == WriteResult::Written;
841                p.secureapprotect()
842                    .disable()
843                    .write(|w| w.set_disable(pac::approtect::vals::SecureapprotectDisableDisable::SW_UNPROTECTED));
844
845                // TODO: maybe add workaround for this errata
846                // It uses extra power, not sure how to let the user choose.
847                // https://docs.nordicsemi.com/bundle/errata_nRF9151_Rev1/page/ERR/nRF9151/Rev1/latest/anomaly_151_36.html#anomaly_151_36
848            }
849        }
850        config::Debug::Disallowed => {
851            // TODO: Handle nRF54L
852            //       By default, debug access is not allowed if the firmware doesn't allow it.
853            //       Code could be added here to disable debug access in UICR as well.
854            #[cfg(not(feature = "_nrf54l"))]
855            unsafe {
856                // UICR.APPROTECT = Enabled
857                let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED);
858                needs_reset |= res == WriteResult::Written;
859                #[cfg(any(feature = "_nrf5340-app", feature = "_nrf91"))]
860                {
861                    let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED);
862                    needs_reset |= res == WriteResult::Written;
863                }
864
865                #[cfg(feature = "nrf9120-s")]
866                {
867                    let p = pac::APPROTECT_S;
868                    p.approtect().forceprotect().write(|w| w.set_forceprotect(true));
869                    p.secureapprotect().forceprotect().write(|w| w.set_forceprotect(true));
870                }
871            }
872        }
873        config::Debug::NotConfigured => {}
874    }
875
876    #[cfg(feature = "_nrf52")]
877    unsafe {
878        let value = if cfg!(feature = "reset-pin-as-gpio") {
879            !0
880        } else {
881            chip::RESET_PIN
882        };
883        let res1 = uicr_write(consts::UICR_PSELRESET1, value);
884        let res2 = uicr_write(consts::UICR_PSELRESET2, value);
885        needs_reset |= res1 == WriteResult::Written || res2 == WriteResult::Written;
886        if res1 == WriteResult::Failed || res2 == WriteResult::Failed {
887            #[cfg(not(feature = "reset-pin-as-gpio"))]
888            warn!(
889                "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\
890                However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
891                To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
892            );
893            #[cfg(feature = "reset-pin-as-gpio")]
894            warn!(
895                "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\
896                However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
897                To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
898            );
899        }
900    }
901
902    #[cfg(any(feature = "_nrf52", feature = "_nrf5340-app"))]
903    unsafe {
904        let value = if cfg!(feature = "nfc-pins-as-gpio") { 0 } else { 1 };
905        let res = uicr_write_masked(consts::UICR_NFCPINS, value, 1);
906        needs_reset |= res == WriteResult::Written;
907        if res == WriteResult::Failed {
908            // with nfc-pins-as-gpio, this can never fail because we're writing all zero bits.
909            #[cfg(not(feature = "nfc-pins-as-gpio"))]
910            warn!(
911                "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\
912                However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
913                To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
914            );
915        }
916    }
917
918    #[cfg(any(feature = "nrf52840", feature = "nrf52833"))]
919    unsafe {
920        if let Some(value) = config.dcdc.reg0_voltage {
921            let value = value as u32;
922            let res = uicr_write_masked(consts::UICR_REGOUT0, value, 0b00000000_00000000_00000000_00000111);
923            needs_reset |= res == WriteResult::Written;
924            if res == WriteResult::Failed {
925                warn!(
926                    "Failed to set regulator voltage, as UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
927                    To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
928                );
929            }
930        }
931    }
932
933    #[cfg(feature = "nrf5340-app-s")]
934    unsafe {
935        if let Some(value) = config.dcdc.regh_voltage {
936            let value = value as u32;
937            let res = uicr_write_masked(consts::UICR_VREGHVOUT, value, 0b00000000_00000000_00000000_00000111);
938            needs_reset |= res == WriteResult::Written;
939            if res == WriteResult::Failed {
940                warn!(
941                    "Failed to set regulator voltage, as UICR is already programmed to some other setting, and can't be changed without erasing it.\n\
942                    To fix this, erase UICR manually, for example using `probe-rs erase` or `nrfjprog --eraseuicr`."
943                );
944            }
945        }
946    }
947
948    if needs_reset {
949        cortex_m::peripheral::SCB::sys_reset();
950    }
951
952    // Configure internal capacitors
953    #[cfg(feature = "nrf5340-app-s")]
954    {
955        if let Some(cap) = config.internal_capacitors.hfxo {
956            let mut slope = pac::FICR.xosc32mtrim().read().slope() as i32;
957            let offset = pac::FICR.xosc32mtrim().read().offset() as i32;
958            // slope is a signed 5-bit integer
959            if slope >= 16 {
960                slope -= 32;
961            }
962            let capvalue = (((slope + 56) * (cap.value2() - 14)) + ((offset - 8) << 4) + 32) >> 6;
963            pac::OSCILLATORS.xosc32mcaps().write(|w| {
964                w.set_capvalue(capvalue as u8);
965                w.set_enable(true);
966            });
967        }
968        if let Some(cap) = config.internal_capacitors.lfxo {
969            pac::OSCILLATORS.xosc32ki().intcap().write(|w| w.set_intcap(cap.into()));
970        }
971    }
972
973    let r = pac::CLOCK;
974
975    // Start HFCLK.
976    match config.hfclk_source {
977        config::HfclkSource::Internal => {}
978        config::HfclkSource::ExternalXtal => {
979            #[cfg(feature = "_nrf54l")]
980            {
981                r.events_xostarted().write_value(0);
982                r.tasks_xostart().write_value(1);
983                while r.events_xostarted().read() == 0 {}
984            }
985
986            #[cfg(not(feature = "_nrf54l"))]
987            {
988                // Datasheet says this is likely to take 0.36ms
989                r.events_hfclkstarted().write_value(0);
990                r.tasks_hfclkstart().write_value(1);
991                while r.events_hfclkstarted().read() == 0 {}
992            }
993        }
994    }
995
996    // Workaround for anomaly 140
997    #[cfg(feature = "nrf5340-app-s")]
998    if unsafe { (0x50032420 as *mut u32).read_volatile() } & 0x80000000 != 0 {
999        r.events_lfclkstarted().write_value(0);
1000        r.lfclksrc()
1001            .write(|w| w.set_src(nrf_pac::clock::vals::Lfclksrc::LFSYNT));
1002        r.tasks_lfclkstart().write_value(1);
1003        while r.events_lfclkstarted().read() == 0 {}
1004        r.events_lfclkstarted().write_value(0);
1005        r.tasks_lfclkstop().write_value(1);
1006        r.lfclksrc().write(|w| w.set_src(nrf_pac::clock::vals::Lfclksrc::LFRC));
1007    }
1008
1009    // Configure LFCLK.
1010    #[cfg(not(any(feature = "_nrf51", feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))]
1011    match config.lfclk_source {
1012        config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::RC)),
1013        config::LfclkSource::Synthesized => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::SYNTH)),
1014        config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::XTAL)),
1015        config::LfclkSource::ExternalLowSwing => r.lfclksrc().write(|w| {
1016            w.set_src(pac::clock::vals::Lfclksrc::XTAL);
1017            w.set_external(true);
1018            w.set_bypass(false);
1019        }),
1020        config::LfclkSource::ExternalFullSwing => r.lfclksrc().write(|w| {
1021            w.set_src(pac::clock::vals::Lfclksrc::XTAL);
1022            w.set_external(true);
1023            w.set_bypass(true);
1024        }),
1025    }
1026    #[cfg(feature = "_nrf5340")]
1027    {
1028        #[allow(unused_mut)]
1029        let mut lfxo = false;
1030        match config.lfclk_source {
1031            config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)),
1032            config::LfclkSource::Synthesized => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFSYNT)),
1033            #[cfg(not(feature = "lfxo-pins-as-gpio"))]
1034            config::LfclkSource::ExternalXtal => lfxo = true,
1035            #[cfg(not(feature = "lfxo-pins-as-gpio"))]
1036            config::LfclkSource::ExternalLowSwing => lfxo = true,
1037            #[cfg(not(feature = "lfxo-pins-as-gpio"))]
1038            config::LfclkSource::ExternalFullSwing => {
1039                #[cfg(feature = "_nrf5340-app")]
1040                pac::OSCILLATORS.xosc32ki().bypass().write(|w| w.set_bypass(true));
1041                lfxo = true;
1042            }
1043        }
1044        if lfxo {
1045            if cfg!(feature = "_s") {
1046                // MCUSEL is only accessible from secure code.
1047                let p0 = pac::P0;
1048                p0.pin_cnf(0)
1049                    .write(|w| w.set_mcusel(pac::gpio::vals::Mcusel::PERIPHERAL));
1050                p0.pin_cnf(1)
1051                    .write(|w| w.set_mcusel(pac::gpio::vals::Mcusel::PERIPHERAL));
1052            }
1053            r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO));
1054        }
1055    }
1056    #[cfg(feature = "_nrf91")]
1057    match config.lfclk_source {
1058        config::LfclkSource::InternalRC => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)),
1059        config::LfclkSource::ExternalXtal => r.lfclksrc().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)),
1060    }
1061    #[cfg(feature = "_nrf54l")]
1062    match config.lfclk_source {
1063        config::LfclkSource::InternalRC => r.lfclk().src().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFRC)),
1064        config::LfclkSource::Synthesized => r.lfclk().src().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFSYNT)),
1065        config::LfclkSource::ExternalXtal => r.lfclk().src().write(|w| w.set_src(pac::clock::vals::Lfclksrc::LFXO)),
1066    }
1067
1068    // Start LFCLK.
1069    // Datasheet says this could take 100us from synth source
1070    // 600us from rc source, 0.25s from an external source.
1071    r.events_lfclkstarted().write_value(0);
1072    r.tasks_lfclkstart().write_value(1);
1073    while r.events_lfclkstarted().read() == 0 {}
1074
1075    #[cfg(not(any(feature = "_nrf5340", feature = "_nrf91", feature = "_nrf54l")))]
1076    {
1077        // Setup DCDCs.
1078        #[cfg(feature = "nrf52840")]
1079        if config.dcdc.reg0 {
1080            pac::POWER.dcdcen0().write(|w| w.set_dcdcen(true));
1081        }
1082        if config.dcdc.reg1 {
1083            pac::POWER.dcdcen().write(|w| w.set_dcdcen(true));
1084        }
1085    }
1086    #[cfg(feature = "_nrf91")]
1087    {
1088        // Setup DCDC.
1089        if config.dcdc.regmain {
1090            pac::REGULATORS.dcdcen().write(|w| w.set_dcdcen(true));
1091        }
1092    }
1093    #[cfg(feature = "_nrf5340-app")]
1094    {
1095        // Setup DCDC.
1096        let reg = pac::REGULATORS;
1097        if config.dcdc.regh {
1098            reg.vregh().dcdcen().write(|w| w.set_dcdcen(true));
1099        }
1100        if config.dcdc.regmain {
1101            reg.vregmain().dcdcen().write(|w| w.set_dcdcen(true));
1102        }
1103        if config.dcdc.regradio {
1104            reg.vregradio().dcdcen().write(|w| w.set_dcdcen(true));
1105        }
1106    }
1107    #[cfg(feature = "_nrf54l")]
1108    {
1109        // Turn on DCDC
1110        // From Product specification:
1111        // "Once the device starts, the DC/DC regulator must be enabled using register VREGMAIN.DCDCEN.
1112        // When enabling the DC/DC regulator, the device checks if an inductor is connected to the DCC pin.
1113        // If an inductor is not detected, the device remains in LDO mode"
1114        pac::REGULATORS.vregmain().dcdcen().write(|w| w.set_val(true));
1115    }
1116
1117    // Init GPIOTE
1118    #[cfg(not(feature = "_nrf54l"))] // TODO
1119    #[cfg(feature = "gpiote")]
1120    gpiote::init(config.gpiote_interrupt_priority);
1121
1122    // init RTC time driver
1123    #[cfg(feature = "_time-driver")]
1124    time_driver::init(config.time_interrupt_priority);
1125
1126    // Disable UARTE (enabled by default for some reason)
1127    #[cfg(feature = "_nrf91")]
1128    {
1129        use pac::uarte::vals::Enable;
1130        pac::UARTE0.enable().write(|w| w.set_enable(Enable::DISABLED));
1131        pac::UARTE1.enable().write(|w| w.set_enable(Enable::DISABLED));
1132    }
1133
1134    peripherals
1135}
1136
1137/// Operating modes for peripherals.
1138pub mod mode {
1139    trait SealedMode {}
1140
1141    /// Operating mode for a peripheral.
1142    #[allow(private_bounds)]
1143    pub trait Mode: SealedMode {}
1144
1145    macro_rules! impl_mode {
1146        ($name:ident) => {
1147            impl SealedMode for $name {}
1148            impl Mode for $name {}
1149        };
1150    }
1151
1152    /// Blocking mode.
1153    pub struct Blocking;
1154    /// Async mode.
1155    pub struct Async;
1156
1157    impl_mode!(Blocking);
1158    impl_mode!(Async);
1159}