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