#![no_std] #![allow(async_fn_in_trait)] #![doc = include_str!("../README.md")] // //! ## Feature flags // #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] pub mod clocks; // still provide clock helpers pub mod dma; pub mod gpio; pub mod adc; pub mod clkout; pub mod config; pub mod crc; pub mod i2c; pub mod interrupt; pub mod lpuart; pub mod ostimer; pub mod reset_reason; pub mod rtc; use crate::interrupt::InterruptExt; pub use crate::pac::NVIC_PRIO_BITS; #[rustfmt::skip] embassy_hal_internal::peripherals!( ADC0, ADC1, ADC2, ADC3, AOI0, AOI1, CAN0, CAN1, CDOG0, CDOG1, // CLKOUT is not specifically a peripheral (it's part of SYSCON), // but we still want it to be a singleton. CLKOUT, CMC, CMP0, CMP1, CRC0, CTIMER0, CTIMER1, CTIMER2, CTIMER3, CTIMER4, DBGMAILBOX, DMA0, DMA_CH0, DMA_CH1, DMA_CH2, DMA_CH3, DMA_CH4, DMA_CH5, DMA_CH6, DMA_CH7, EDMA0_TCD0, EIM0, EQDC0, EQDC1, ERM0, FLEXIO0, FLEXPWM0, FLEXPWM1, FMC0, FMU0, FREQME0, GLIKEY0, GPIO0, GPIO1, GPIO2, GPIO3, GPIO4, I3C0, INPUTMUX0, LPI2C0, LPI2C1, LPI2C2, LPI2C3, LPSPI0, LPSPI1, LPTMR0, LPUART0, LPUART1, LPUART2, LPUART3, LPUART4, LPUART5, MAU0, MBC0, MRCC0, OPAMP0, #[cfg(not(feature = "time"))] OSTIMER0, P0_0, P0_1, P0_2, P0_3, P0_4, P0_5, P0_6, P0_7, P0_8, P0_9, P0_10, P0_11, P0_12, P0_13, P0_14, P0_15, P0_16, P0_17, P0_18, P0_19, P0_20, P0_21, P0_22, P0_23, P0_24, P0_25, P0_26, P0_27, P0_28, P0_29, P0_30, P0_31, P1_0, P1_1, P1_2, P1_3, P1_4, P1_5, P1_6, P1_7, P1_8, P1_9, P1_10, P1_11, P1_12, P1_13, P1_14, P1_15, P1_16, P1_17, P1_18, P1_19, P1_20, P1_21, P1_22, P1_23, P1_24, P1_25, P1_26, P1_27, P1_28, P1_29, // TODO: These pins are optionally used as the clock sources for SOSC. // Ideally, we'd want to have a custom version of the `peripheral!` macro // that presented these as `Option>` instead of `Peri<'_, P1_30>` // when the user DOES enable the external SOSC. For now, I'm guessing MOST designs // will have an external clock sitting on these pins anyway, so we just notch them // out from the `Peripherals` struct given to users. // // If you find this and want your extra two pins to be available: please open an // embassy issue to discuss how we could do this. // // P1_30, // P1_31, P2_0, P2_1, P2_2, P2_3, P2_4, P2_5, P2_6, P2_7, P2_8, P2_9, P2_10, P2_11, P2_12, P2_13, P2_14, P2_15, P2_16, P2_17, P2_18, P2_19, P2_20, P2_21, P2_22, P2_23, P2_24, P2_25, P2_26, P2_27, P2_28, P2_29, P2_30, P2_31, P3_0, P3_1, P3_2, P3_3, P3_4, P3_5, P3_6, P3_7, P3_8, P3_9, P3_10, P3_11, P3_12, P3_13, P3_14, P3_15, P3_16, P3_17, P3_18, P3_19, P3_20, P3_21, P3_22, P3_23, P3_24, P3_25, P3_26, P3_27, P3_28, P3_29, P3_30, P3_31, P4_0, P4_1, P4_2, P4_3, P4_4, P4_5, P4_6, P4_7, P4_8, P4_9, P4_10, P4_11, P4_12, P4_13, P4_14, P4_15, P4_16, P4_17, P4_18, P4_19, P4_20, P4_21, P4_22, P4_23, P4_24, P4_25, P4_26, P4_27, P4_28, P4_29, P4_30, P4_31, P5_0, P5_1, P5_2, P5_3, P5_4, P5_5, P5_6, P5_7, P5_8, P5_9, P5_10, P5_11, P5_12, P5_13, P5_14, P5_15, P5_16, P5_17, P5_18, P5_19, P5_20, P5_21, P5_22, P5_23, P5_24, P5_25, P5_26, P5_27, P5_28, P5_29, P5_30, P5_31, PKC0, PORT0, PORT1, PORT2, PORT3, PORT4, RTC0, SAU, SCG0, SCN_SCB, SGI0, SMARTDMA0, SPC0, SYSCON, TDET0, TRNG0, UDF0, USB0, UTICK0, VBAT0, WAKETIMER0, WUU0, WWDT0, ); // See commented out items above to understand why we create the instances // here but don't give them to the user. pub(crate) mod internal_peripherals { embassy_hal_internal::peripherals_definition!(P1_30, P1_31,); pub(crate) use peripherals::*; } // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. // Re-export interrupt traits and types #[cfg(feature = "unstable-pac")] pub use mcxa_pac as pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use mcxa_pac as pac; /// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals. /// Also applies configurable NVIC priority for the OSTIMER OS_EVENT interrupt (no enabling). pub fn init(cfg: crate::config::Config) -> Peripherals { let peripherals = Peripherals::take(); // Apply user-configured priority early; enabling is left to examples/apps #[cfg(feature = "time")] crate::interrupt::OS_EVENT.set_priority(cfg.time_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO2.set_priority(cfg.gpio_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO3.set_priority(cfg.gpio_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::GPIO4.set_priority(cfg.gpio_interrupt_priority); // Configure clocks crate::clocks::init(cfg.clock_cfg).unwrap(); unsafe { crate::gpio::interrupt_init(); } // Initialize DMA controller (clock, reset, configuration) crate::dma::init(); // Initialize embassy-time global driver backed by OSTIMER0 #[cfg(feature = "time")] crate::ostimer::time_driver::init(crate::config::Config::default().time_interrupt_priority, 1_000_000); // Enable GPIO clocks unsafe { _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); } peripherals } /// Macro to bind interrupts to handlers, similar to embassy-imxrt. /// /// Example: /// - Bind OS_EVENT to the OSTIMER time-driver handler /// bind_interrupts!(struct Irqs { OS_EVENT => crate::ostimer::time_driver::OsEventHandler; }); #[macro_export] macro_rules! bind_interrupts { ($(#[$attr:meta])* $vis:vis struct $name:ident { $( $(#[cfg($cond_irq:meta)])? $irq:ident => $( $(#[cfg($cond_handler:meta)])? $handler:ty ),*; )* }) => { #[derive(Copy, Clone)] $(#[$attr])* $vis struct $name; $( #[allow(non_snake_case)] #[no_mangle] $(#[cfg($cond_irq)])? unsafe extern "C" fn $irq() { unsafe { $( $(#[cfg($cond_handler)])? <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); )* } } $(#[cfg($cond_irq)])? $crate::bind_interrupts!(@inner $( $(#[cfg($cond_handler)])? unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* ); )* }; (@inner $($t:tt)*) => { $($t)* } }