#![no_std] #![allow(async_fn_in_trait)] #![doc = include_str!("../README.md")] #![warn(missing_docs)] //! ## Feature flags #![doc = document_features::document_features!(feature_label = r#"{feature}"#)] #[cfg(not(any(feature = "mimxrt633s", feature = "mimxrt685s",)))] compile_error!( "No chip feature activated. You must activate exactly one of the following features: mimxrt633s, mimxrt685s, " ); // This mod MUST go first, so that the others see its macros. pub(crate) mod fmt; pub mod clocks; pub mod crc; pub mod dma; pub mod flexcomm; pub mod gpio; pub mod iopctl; pub mod rng; #[cfg(feature = "_time-driver")] pub mod time_driver; // This mod MUST go last, so that it sees all the `impl_foo!' macros #[cfg_attr(feature = "mimxrt633s", path = "chips/mimxrt633s.rs")] #[cfg_attr(feature = "mimxrt685s", path = "chips/mimxrt685s.rs")] mod chip; // Reexports pub use chip::interrupts::*; #[cfg(feature = "unstable-pac")] pub use chip::pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use chip::pac; pub use chip::{peripherals, Peripherals}; pub use embassy_hal_internal::{Peri, PeripheralType}; #[cfg(feature = "rt")] pub use crate::pac::NVIC_PRIO_BITS; /// Macro to bind interrupts to handlers. /// /// This defines the right interrupt handlers, and creates a unit struct (like `struct Irqs;`) /// and implements the right \[`Binding`\]s for it. You can pass this struct to drivers to /// prove at compile-time that the right interrupts have been bound. /// /// Example of how to bind one interrupt: /// /// ```rust,ignore /// use embassy_imxrt::{bind_interrupts, flexspi, peripherals}; /// /// bind_interrupts!(struct Irqs { /// FLEXSPI_IRQ => flexspi::InterruptHandler; /// }); /// ``` /// // developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`. #[macro_export] macro_rules! bind_interrupts { ($vis:vis struct $name:ident { $($irq:ident => $($handler:ty),*;)* }) => { #[derive(Copy, Clone)] $vis struct $name; $( #[allow(non_snake_case)] #[no_mangle] unsafe extern "C" fn $irq() { $( <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt(); )* } $( unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {} )* )* }; } /// HAL configuration for iMX RT600. pub mod config { use crate::clocks::ClockConfig; /// HAL configuration passed when initializing. #[non_exhaustive] pub struct Config { /// Clock configuration. pub clocks: ClockConfig, /// RTC Time driver interrupt priority. #[cfg(feature = "_time-driver")] pub time_interrupt_priority: crate::interrupt::Priority, } impl Default for Config { fn default() -> Self { Self { clocks: ClockConfig::crystal(), #[cfg(feature = "_time-driver")] time_interrupt_priority: crate::interrupt::Priority::P0, } } } impl Config { /// Create a new configuration with the provided clock config. pub fn new(clocks: ClockConfig) -> Self { Self { clocks, #[cfg(feature = "_time-driver")] time_interrupt_priority: crate::interrupt::Priority::P0, } } } } /// Initialize the `embassy-imxrt` HAL with the provided configuration. /// /// This returns the peripheral singletons that can be used for creating drivers. /// /// This should only be called once at startup, otherwise it panics. pub fn init(config: config::Config) -> Peripherals { // Do this first, so that it panics if user is calling `init` a second time // before doing anything important. let peripherals = Peripherals::take(); #[cfg(feature = "_time-driver")] time_driver::init(config.time_interrupt_priority); unsafe { if let Err(e) = clocks::init(config.clocks) { error!("unable to initialize Clocks for reason: {:?}", e); // Panic here? } dma::init(); } gpio::init(); peripherals } pub(crate) mod sealed { pub trait Sealed {} } #[cfg(feature = "rt")] struct BitIter(u32); #[cfg(feature = "rt")] impl Iterator for BitIter { type Item = u32; fn next(&mut self) -> Option { match self.0.trailing_zeros() { 32 => None, b => { self.0 &= !(1 << b); Some(b) } } } }