aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
authorFelipe Balbi <[email protected]>2025-11-07 11:00:15 -0800
committerGitHub <[email protected]>2025-11-07 11:00:15 -0800
commit5632acec18cc5906b1625a8facf530db56c73300 (patch)
treeabf2897f4b2f9814069c64611896be2d42cf2ce8 /src/lib.rs
parent47e383545f4aac3bfaec0563429cc721540e665a (diff)
parent9590d94ee9ba016f65a13100c429fc56ffe58e40 (diff)
Merge pull request #1 from bogdan-petru/import/mcxa276-initial
feat(mcxa276): initial HAL import
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 000000000..fe27aadba
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,142 @@
1#![no_std]
2
3pub mod clocks; // still provide clock helpers
4pub mod gpio;
5pub mod pins; // pin mux helpers
6pub mod reset; // reset control helpers
7
8pub mod adc;
9pub mod config;
10pub mod interrupt;
11pub mod lpuart;
12pub mod ostimer;
13pub mod rtc;
14pub mod uart;
15
16embassy_hal_internal::peripherals!(LPUART2, OSTIMER0, GPIO, RTC0, ADC1,);
17
18/// Get access to the PAC Peripherals for low-level register access.
19/// This is a lazy-initialized singleton that can be called after init().
20#[allow(static_mut_refs)]
21pub fn pac() -> &'static pac::Peripherals {
22 // SAFETY: We only call this after init(), and the PAC is a singleton.
23 // The embassy peripheral tokens ensure we don't have multiple mutable accesses.
24 unsafe {
25 static mut PAC_INSTANCE: Option<pac::Peripherals> = None;
26 if PAC_INSTANCE.is_none() {
27 PAC_INSTANCE = Some(pac::Peripherals::steal());
28 }
29 PAC_INSTANCE.as_ref().unwrap()
30 }
31}
32
33// Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it.
34
35// Re-export interrupt traits and types
36pub use adc::Adc1 as Adc1Token;
37pub use gpio::pins::*;
38pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output};
39pub use interrupt::InterruptExt;
40#[cfg(feature = "unstable-pac")]
41pub use mcxa_pac as pac;
42#[cfg(not(feature = "unstable-pac"))]
43pub(crate) use mcxa_pac as pac;
44pub use ostimer::Ostimer0 as Ostimer0Token;
45pub use rtc::Rtc0 as Rtc0Token;
46pub use uart::Lpuart2 as Uart2Token;
47
48/// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals.
49/// Also applies configurable NVIC priority for the OSTIMER OS_EVENT interrupt (no enabling).
50#[allow(unused_variables)]
51pub fn init(cfg: crate::config::Config) -> Peripherals {
52 let peripherals = Peripherals::take();
53 // Apply user-configured priority early; enabling is left to examples/apps
54 crate::interrupt::OS_EVENT.set_priority(cfg.time_interrupt_priority);
55 // Apply user-configured priority early; enabling is left to examples/apps
56 crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority);
57 // Apply user-configured priority early; enabling is left to examples/apps
58 crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority);
59 peripherals
60}
61
62/// Optional hook called by cortex-m-rt before RAM init.
63/// We proactively mask and clear all NVIC IRQs to avoid wedges from stale state
64/// left by soft resets/debug sessions.
65///
66/// NOTE: Manual VTOR setup is required for RAM execution. The cortex-m-rt 'set-vtor'
67/// feature is incompatible with our setup because it expects __vector_table to be
68/// defined differently than how our RAM-based linker script arranges it.
69#[no_mangle]
70pub unsafe extern "C" fn __pre_init() {
71 // Set the VTOR to point to the interrupt vector table in RAM
72 // This is required since code runs from RAM on this MCU
73 crate::interrupt::vtor_set_ram_vector_base(0x2000_0000 as *const u32);
74
75 // Mask and clear pending for all NVIC lines (0..127) to avoid stale state across runs.
76 let nvic = &*cortex_m::peripheral::NVIC::PTR;
77 for i in 0..4 {
78 // 4 words x 32 = 128 IRQs
79 nvic.icer[i].write(0xFFFF_FFFF);
80 nvic.icpr[i].write(0xFFFF_FFFF);
81 }
82 // Do NOT touch peripheral registers here: clocks may be off and accesses can fault.
83 crate::interrupt::clear_default_handler_snapshot();
84}
85
86/// Internal helper to dispatch a type-level interrupt handler.
87#[inline(always)]
88#[doc(hidden)]
89pub unsafe fn __handle_interrupt<T, H>()
90where
91 T: crate::interrupt::typelevel::Interrupt,
92 H: crate::interrupt::typelevel::Handler<T>,
93{
94 H::on_interrupt();
95}
96
97/// Macro to bind interrupts to handlers, similar to embassy-imxrt.
98///
99/// Example:
100/// - Bind OS_EVENT to the OSTIMER time-driver handler
101/// bind_interrupts!(struct Irqs { OS_EVENT => crate::ostimer::time_driver::OsEventHandler; });
102#[macro_export]
103macro_rules! bind_interrupts {
104 ($(#[$attr:meta])* $vis:vis struct $name:ident {
105 $(
106 $(#[cfg($cond_irq:meta)])?
107 $irq:ident => $(
108 $(#[cfg($cond_handler:meta)])?
109 $handler:ty
110 ),*;
111 )*
112 }) => {
113 #[derive(Copy, Clone)]
114 $(#[$attr])*
115 $vis struct $name;
116
117 $(
118 #[allow(non_snake_case)]
119 #[no_mangle]
120 $(#[cfg($cond_irq)])?
121 unsafe extern "C" fn $irq() {
122 unsafe {
123 $(
124 $(#[cfg($cond_handler)])?
125 <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
126 )*
127 }
128 }
129
130 $(#[cfg($cond_irq)])?
131 $crate::bind_interrupts!(@inner
132 $(
133 $(#[cfg($cond_handler)])?
134 unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
135 )*
136 );
137 )*
138 };
139 (@inner $($t:tt)*) => {
140 $($t)*
141 }
142}