#![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 gpio; pub mod pins; // pin mux helpers pub mod adc; pub mod clkout; pub mod config; pub mod i2c; pub mod interrupt; pub mod lpuart; pub mod ostimer; pub mod rtc; pub use crate::pac::NVIC_PRIO_BITS; #[rustfmt::skip] embassy_hal_internal::peripherals!( ADC0, ADC1, 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, 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, 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, ); // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. // Re-export interrupt traits and types pub use adc::Adc1 as Adc1Token; pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; pub use interrupt::InterruptExt; #[cfg(feature = "unstable-pac")] pub use mcxa_pac as pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use mcxa_pac as pac; pub use rtc::Rtc0 as Rtc0Token; /// 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::ADC1.set_priority(cfg.adc_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::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 } // /// Optional hook called by cortex-m-rt before RAM init. // /// We proactively mask and clear all NVIC IRQs to avoid wedges from stale state // /// left by soft resets/debug sessions. // /// // /// NOTE: Manual VTOR setup is required for RAM execution. The cortex-m-rt 'set-vtor' // /// feature is incompatible with our setup because it expects __vector_table to be // /// defined differently than how our RAM-based linker script arranges it. // #[no_mangle] // pub unsafe extern "C" fn __pre_init() { // // Set the VTOR to point to the interrupt vector table in RAM // // This is required since code runs from RAM on this MCU // crate::interrupt::vtor_set_ram_vector_base(0x2000_0000 as *const u32); // // Mask and clear pending for all NVIC lines (0..127) to avoid stale state across runs. // let nvic = &*cortex_m::peripheral::NVIC::PTR; // for i in 0..4 { // // 4 words x 32 = 128 IRQs // nvic.icer[i].write(0xFFFF_FFFF); // nvic.icpr[i].write(0xFFFF_FFFF); // } // // Do NOT touch peripheral registers here: clocks may be off and accesses can fault. // crate::interrupt::clear_default_handler_snapshot(); // } /// Internal helper to dispatch a type-level interrupt handler. #[inline(always)] #[doc(hidden)] pub unsafe fn __handle_interrupt() where T: crate::interrupt::typelevel::Interrupt, H: crate::interrupt::typelevel::Handler, { H::on_interrupt(); } /// 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)* } }