aboutsummaryrefslogtreecommitdiff
path: root/board/src
diff options
context:
space:
mode:
Diffstat (limited to 'board/src')
-rw-r--r--board/src/imxrt1010evk.rs36
-rw-r--r--board/src/imxrt1170evk_cm7.rs38
-rw-r--r--board/src/lib.rs107
-rw-r--r--board/src/shared/imxrt10xx.rs35
-rw-r--r--board/src/shared/imxrt11xx.rs52
-rw-r--r--board/src/teensy4.rs37
6 files changed, 305 insertions, 0 deletions
diff --git a/board/src/imxrt1010evk.rs b/board/src/imxrt1010evk.rs
new file mode 100644
index 0000000..9a596e9
--- /dev/null
+++ b/board/src/imxrt1010evk.rs
@@ -0,0 +1,36 @@
+//! iMXRT1010EVK support.
+
+use crate::ral;
+
+#[cfg(target_arch = "arm")]
+use imxrt1010evk_fcb as _;
+#[cfg(target_arch = "arm")]
+use panic_rtt_target as _;
+
+const LED_OFFSET: u32 = 11;
+
+pub mod rtic_support {
+ pub use crate::ral::*;
+}
+
+/// Prepare the board for the examples.
+///
+/// Call this first. Panics if something went wrong.
+pub fn prepare(timer_delay_microseconds: u32) -> Option<crate::Resources> {
+ #[cfg(target_arch = "arm")]
+ rtt_target::rtt_init_print!();
+
+ let iomuxc = unsafe { ral::iomuxc::IOMUXC::instance() };
+ // Set the GPIO pad to a GPIO function (ALT 5)
+ ral::write_reg!(ral::iomuxc, iomuxc, SW_MUX_CTL_PAD_GPIO_11, 5);
+ // Increase drive strength, but leave other fields at their current value...
+ ral::modify_reg!(ral::iomuxc, iomuxc, SW_PAD_CTL_PAD_GPIO_11, DSE: DSE_7_R0_7);
+
+ let pit = crate::prepare_pit(timer_delay_microseconds)?;
+
+ let gpio1 = unsafe { ral::gpio::GPIO1::instance() };
+ Some(crate::Resources {
+ led: crate::Led::new(LED_OFFSET, &gpio1),
+ pit,
+ })
+}
diff --git a/board/src/imxrt1170evk_cm7.rs b/board/src/imxrt1170evk_cm7.rs
new file mode 100644
index 0000000..7d966eb
--- /dev/null
+++ b/board/src/imxrt1170evk_cm7.rs
@@ -0,0 +1,38 @@
+//! Support for booting the Cortex M7 on the i.MX RT 1170 EVK.
+
+use crate::ral;
+
+#[cfg(target_arch = "arm")]
+use imxrt1170evk_fcb as _;
+#[cfg(target_arch = "arm")]
+use panic_rtt_target as _;
+
+const LED_OFFSET: u32 = 3;
+
+pub mod rtic_support {
+ pub use crate::ral::NVIC_PRIO_BITS;
+ #[allow(non_snake_case)] // For RTIC trickery...
+ pub mod Interrupt {
+ pub const PIT: crate::ral::Interrupt = crate::ral::Interrupt::PIT1;
+ }
+ pub use Interrupt as interrupt;
+}
+
+pub fn prepare(timer_delay_microseconds: u32) -> Option<crate::Resources> {
+ #[cfg(target_arch = "arm")]
+ rtt_target::rtt_init_print!();
+
+ let iomuxc = unsafe { ral::iomuxc::IOMUXC::instance() };
+ ral::modify_reg!(ral::iomuxc, iomuxc, SW_MUX_CTL_PAD_GPIO_AD_04, MUX_MODE: 5);
+
+ let ccm = unsafe { ral::ccm::CCM::instance() };
+ // Enable LPCG for GPIOs.
+ ral::write_reg!(ral::ccm, ccm, LPCG51_DIRECT, 1);
+
+ let gpio = unsafe { ral::gpio::GPIO3::instance() };
+ let pit = crate::prepare_pit(timer_delay_microseconds)?;
+ Some(crate::Resources {
+ pit,
+ led: crate::Led::new(LED_OFFSET, &gpio),
+ })
+}
diff --git a/board/src/lib.rs b/board/src/lib.rs
new file mode 100644
index 0000000..24d746a
--- /dev/null
+++ b/board/src/lib.rs
@@ -0,0 +1,107 @@
+//! A very simple, multi-board BSP for imxrt-rt-support examples.
+#![no_std]
+
+use imxrt_ral as ral;
+
+cfg_if::cfg_if! {
+ if #[cfg(feature = "teensy4")] {
+ mod shared { pub mod imxrt10xx; }
+ use shared::imxrt10xx::prepare_pit;
+
+ mod teensy4;
+ pub use teensy4::*;
+ } else if #[cfg(feature = "imxrt1010evk")] {
+ mod shared { pub mod imxrt10xx; }
+ use shared::imxrt10xx::prepare_pit;
+
+ mod imxrt1010evk;
+ pub use imxrt1010evk::*;
+ } else if #[cfg(feature = "imxrt1170evk-cm7")] {
+ mod shared { pub mod imxrt11xx; }
+ use shared::imxrt11xx::prepare_pit;
+
+ mod imxrt1170evk_cm7;
+ pub use imxrt1170evk_cm7::*;
+ } else {
+ compile_error!("No board feature selected!");
+ }
+}
+
+pub struct Pit(&'static ral::pit::RegisterBlock);
+
+impl Pit {
+ fn new(pit: &ral::pit::RegisterBlock, timer_delay_microseconds: u32) -> Self {
+ // Disable the PIT, just in case it was used by the boot ROM
+ ral::write_reg!(ral::pit, pit, MCR, MDIS: 1);
+ let timer = &pit.TIMER[0];
+ // Reset channel 0 control; we'll use channel 0 for our timer
+ ral::write_reg!(ral::pit::timer, timer, TCTRL, 0);
+ // Set the counter value
+ ral::write_reg!(ral::pit::timer, timer, LDVAL, timer_delay_microseconds);
+ // Enable the PIT timer
+ ral::modify_reg!(ral::pit, pit, MCR, MDIS: 0);
+ Self(unsafe { core::mem::transmute(pit) })
+ }
+ pub fn blocking_delay(&mut self) {
+ let timer = &self.0.TIMER[0];
+ // Start counting!
+ ral::write_reg!(ral::pit::timer, timer, TCTRL, TEN: 1);
+ // Are we done?
+ while ral::read_reg!(ral::pit::timer, timer, TFLG, TIF == 0) {}
+ // We're done; clear the flag
+ ral::write_reg!(ral::pit::timer, timer, TFLG, TIF: 1);
+ // Turn off the timer
+ ral::write_reg!(ral::pit::timer, timer, TCTRL, TEN: 0);
+ }
+ pub fn loop_with_interrupts(&mut self) {
+ let timer = &self.0.TIMER[0];
+ // Enable interrupts and start counting
+ ral::write_reg!(ral::pit::timer, timer, TCTRL, TIE: 1);
+ ral::modify_reg!(ral::pit::timer, timer, TCTRL, TEN: 1);
+ }
+ pub fn clear_interrupts(&mut self) {
+ let timer = &self.0.TIMER[0];
+ while ral::read_reg!(ral::pit::timer, timer, TFLG, TIF == 1) {
+ ral::write_reg!(ral::pit::timer, timer, TFLG, TIF: 1);
+ }
+ }
+}
+
+unsafe impl Send for Pit {}
+
+pub struct Led {
+ offset: u32,
+ port: &'static ral::gpio::RegisterBlock,
+}
+
+impl Led {
+ fn new(offset: u32, port: &ral::gpio::RegisterBlock) -> Self {
+ let led = Led {
+ offset,
+ port: unsafe { core::mem::transmute(port) },
+ };
+ ral::modify_reg!(ral::gpio, port, GDIR, |gdir| gdir | led.mask());
+ led
+ }
+ fn mask(&self) -> u32 {
+ 1 << self.offset
+ }
+ pub fn set(&self) {
+ ral::write_reg!(ral::gpio, self.port, DR_SET, self.mask());
+ }
+
+ pub fn clear(&self) {
+ ral::write_reg!(ral::gpio, self.port, DR_CLEAR, self.mask());
+ }
+
+ pub fn toggle(&self) {
+ ral::write_reg!(ral::gpio, self.port, DR_TOGGLE, self.mask());
+ }
+}
+
+unsafe impl Send for Led {}
+
+pub struct Resources {
+ pub led: crate::Led,
+ pub pit: crate::Pit,
+}
diff --git a/board/src/shared/imxrt10xx.rs b/board/src/shared/imxrt10xx.rs
new file mode 100644
index 0000000..5ba44eb
--- /dev/null
+++ b/board/src/shared/imxrt10xx.rs
@@ -0,0 +1,35 @@
+//! Code shared across all i.MX RT 10xx chips.
+use crate::ral;
+
+pub(crate) fn prepare_pit(timer_delay_microseconds: u32) -> Option<crate::Pit> {
+ #[cfg(feature = "rtic")]
+ {
+ extern "C" {
+ // Not actually mut in cortex-m. But, no one is reading it...
+ static __INTERRUPTS: [core::cell::UnsafeCell<unsafe extern "C" fn()>; 240];
+ fn PIT();
+ }
+ unsafe {
+ __INTERRUPTS[crate::ral::interrupt::PIT as usize]
+ .get()
+ .write_volatile(PIT);
+ }
+ }
+ let ccm = unsafe { ral::ccm::CCM::instance() };
+ // Disable the PIT clock gate while we change the clock...
+ ral::modify_reg!(ral::ccm, ccm, CCGR1, CG6: 0b00);
+ // Set the periodic clock divider, selection.
+ // 24MHz crystal oscillator, divided by 24 == 1MHz PIT clock
+ ral::modify_reg!(
+ ral::ccm,
+ ccm,
+ CSCMR1,
+ PERCLK_PODF: DIVIDE_24,
+ PERCLK_CLK_SEL: PERCLK_CLK_SEL_1 // Oscillator clock
+ );
+ // Re-enable PIT clock
+ ral::modify_reg!(ral::ccm, ccm, CCGR1, CG6: 0b11);
+
+ let pit = unsafe { ral::pit::PIT::instance() };
+ Some(crate::Pit::new(&pit, timer_delay_microseconds))
+}
diff --git a/board/src/shared/imxrt11xx.rs b/board/src/shared/imxrt11xx.rs
new file mode 100644
index 0000000..e0d1074
--- /dev/null
+++ b/board/src/shared/imxrt11xx.rs
@@ -0,0 +1,52 @@
+//! Code shared across all i.MX RT 11xx chips.
+
+use crate::ral;
+
+pub(crate) fn prepare_pit(timer_delay_microseconds: u32) -> Option<crate::Pit> {
+ #[cfg(feature = "rtic")]
+ {
+ extern "C" {
+ // Not actually mut in cortex-m. But, no one is reading it...
+ static __INTERRUPTS: [core::cell::UnsafeCell<unsafe extern "C" fn()>; 240];
+ fn PIT();
+ }
+ unsafe {
+ __INTERRUPTS[crate::ral::Interrupt::PIT1 as usize]
+ .get()
+ .write_volatile(PIT);
+ }
+ }
+
+ let ccm = unsafe { ral::ccm::CCM::instance() };
+
+ // Change the bus clock to the 24 MHz XTAL.
+ // Wouldn't recommend doing this in a real system,
+ // since the bus clock is running rather slowly.
+ // But, it's good enough for a demo, and it lets us match
+ // the behaviors of the 10xx examples.
+ //
+ // If we decrease the bus speed too much, we seem to reach a condition
+ // where we can't re-flash the device. Haven't dug too deeply; only
+ // observed that keeping the bus clock faster lets us flash more reliably,
+ // at least with pyOCD.
+ let clock_root_2 = &ccm.CLOCK_ROOT[2];
+ ral::modify_reg!(ral::ccm::clockroot, clock_root_2, CLOCK_ROOT_CONTROL, MUX: 0b001, DIV: 0);
+ while ral::read_reg!(
+ ral::ccm::clockroot,
+ clock_root_2,
+ CLOCK_ROOT_STATUS0,
+ CHANGING == 1
+ ) {}
+
+ // Enable the clock gate to PIT1.
+ ral::write_reg!(ral::ccm, ccm, LPCG61_DIRECT, 1);
+
+ let pit = unsafe { ral::pit::PIT1::instance() };
+ // 24x scaling accounts for the 24x faster PIT clock.
+ // Looks like it's blinking at 1Hz, but I'm not pulling out
+ // my scope or stopwatch or anything.
+ Some(crate::Pit::new(
+ &pit,
+ timer_delay_microseconds.saturating_mul(24),
+ ))
+}
diff --git a/board/src/teensy4.rs b/board/src/teensy4.rs
new file mode 100644
index 0000000..28587cd
--- /dev/null
+++ b/board/src/teensy4.rs
@@ -0,0 +1,37 @@
+//! Teensy4 support.
+
+use crate::ral;
+
+#[cfg(target_arch = "arm")]
+use teensy4_fcb as _;
+#[cfg(target_arch = "arm")]
+use teensy4_panic as _;
+
+const LED_OFFSET: u32 = 3;
+
+pub mod rtic_support {
+ pub use crate::ral::*;
+}
+
+/// Prepare the board for the examples.
+///
+/// Call this first. Panics if something went wrong.
+pub fn prepare(timer_delay_microseconds: u32) -> Option<crate::Resources> {
+ let iomuxc = unsafe { ral::iomuxc::IOMUXC::instance() };
+ // Set the GPIO pad to a GPIO function (ALT 5)
+ ral::write_reg!(ral::iomuxc, iomuxc, SW_MUX_CTL_PAD_GPIO_B0_03, 5);
+ // Increase drive strength, but leave other fields at their current value...
+ ral::modify_reg!(
+ ral::iomuxc,
+ iomuxc,
+ SW_PAD_CTL_PAD_GPIO_B0_03,
+ DSE: DSE_7_R0_7
+ );
+
+ let pit = crate::prepare_pit(timer_delay_microseconds)?;
+ let gpio2 = unsafe { ral::gpio::GPIO2::instance() };
+ Some(crate::Resources {
+ led: crate::Led::new(LED_OFFSET, &gpio2),
+ pit,
+ })
+}