imxrt-hal 0.5.14

Hardware abstraction layer for NXP i.MX RT microcontrollers.
Documentation
//! Modules shared across all i.MX RT 11xx processors.
//!
//! Shared modules may rely on configurations from the `config` module.

pub mod ccm;
#[path = "dma.rs"]
pub mod dma;
#[path = "ocotp.rs"]
pub mod ocotp;
pub mod usbphy;

cfg_if::cfg_if! {
    if #[cfg(chip = "imxrt1170")] {
        #[path = "imxrt11xx/imxrt1170.rs"]
        pub(crate) mod config;
    }
}

pub(crate) mod reexports {
    pub use super::{ocotp, usbphy};
}

pub(crate) mod iomuxc {
    pub use super::config::pads;
    use crate::ral;

    /// Transform the `imxrt-ral` IOMUXC instances into pad objects.
    pub fn into_pads(_: ral::iomuxc::IOMUXC, _: ral::iomuxc_lpsr::IOMUXC_LPSR) -> pads::Pads {
        // Safety: acquiring pads has the same safety implications
        // as acquiring the IOMUXC instances. The user has already
        // assumed the unsafety.
        unsafe { pads::Pads::new() }
    }
}

impl ocotp::Ocotp {
    #[inline(always)]
    fn read_fuse_data(&self) -> u32 {
        crate::ral::read_reg!(crate::ral::ocotp, self.ocotp, READ_FUSE_DATA0)
    }

    #[inline(always)]
    fn check_end_fuse_read(&mut self) -> Result<(), ocotp::Error> {
        if crate::ral::read_reg!(crate::ral::ocotp, self.ocotp, OUT_STATUS, DED == 1) {
            // Clear DED by writing to SCT space, not by a general write.
            crate::ral::write_reg!(crate::ral::ocotp, self.ocotp, OUT_STATUS_SET, DED: 1);
            return Err(ocotp::Error::DedRead);
        }
        Ok(())
    }

    #[inline(always)]
    fn check_end_fuse_write(&mut self) -> Result<(), ocotp::Error> {
        let (progfail, locked) =
            crate::ral::read_reg!(crate::ral::ocotp, self.ocotp, OUT_STATUS, PROGFAIL, LOCKED);
        crate::ral::write_reg!(crate::ral::ocotp, self.ocotp, OUT_STATUS_SET, PROGFAIL: progfail, LOCKED: locked);

        if 0 != progfail {
            return Err(ocotp::Error::Programming);
        }
        if 0 != locked {
            return Err(ocotp::Error::LockedRegionAccess);
        }
        Ok(())
    }

    /// Returns `true` if the last read had a single bit corrected.
    ///
    /// This automatically clears the SEC bit. You can sequence this
    /// after a read to check if there was a correction. SEC only
    /// applies if the fuse is ECC redundant.
    ///
    /// If you do not call [`clear_read_sec()`](Self::clear_read_sec),
    /// then this bit may latch `true` if there was ever *any* SEC.
    pub fn has_read_sec(&self) -> bool {
        crate::ral::read_reg!(crate::ral::ocotp, self.ocotp, OUT_STATUS, SEC == 1)
    }

    /// Clear the status that indicates a SEC during read.
    pub fn clear_read_sec(&self) {
        crate::ral::write_reg!(crate::ral::ocotp, self.ocotp, OUT_STATUS_SET, SEC: 1);
    }

    const FUSE_ADDRESS_OFFSET: u16 = 0x800;
}

#[cfg(test)]
mod tests {
    use super::ocotp::FuseAddress;

    #[test]
    fn fuse_address_from_rm_example() {
        let fuse = FuseAddress::new(0x960).unwrap();
        assert_eq!(fuse.raw(), 0x16);
    }

    #[test]
    fn fuse_address_from_min_fuse() {
        // A low address, non-reserved fuse shown in one
        // reference manual.
        let fuse = FuseAddress::new(0x840).unwrap();
        assert_eq!(fuse.raw(), 4);
    }

    #[test]
    fn fuse_address_from_max_fuse() {
        // Similar to the min test, but using a high address.
        let fuse = FuseAddress::new(0x1800).unwrap();
        assert_eq!(fuse.raw(), 0x100);
    }
}