Skip to main content

ra_hal/
lib.rs

1#![no_std]
2#![doc = include_str!("../README.md")]
3#![warn(missing_docs)]
4
5//! ## Feature flags
6#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
7
8// This needs to come first so the macros are visible everywhere else.
9#[doc(hidden)]
10pub mod fmt;
11
12#[cfg(any(adc12, adc14, adc16))]
13pub mod adc;
14
15pub mod clock;
16pub mod crc;
17#[cfg(dac12)]
18pub mod dac;
19#[cfg(dmac)]
20pub mod dmac;
21pub mod dtc;
22pub mod event_link;
23pub mod gpio;
24#[cfg(iic)]
25pub mod i2c;
26pub mod mcu_info;
27pub mod module_stop;
28#[cfg(not(feature = "skip-osm"))]
29pub mod osm;
30#[cfg(gpt)]
31pub mod pwm;
32#[cfg(gpt)]
33pub mod qdec;
34// #[cfg(feature = "_enable-rtc-beware-of-dragons")]
35// pub mod rtc;
36#[cfg(any(agt, agtw))]
37pub mod timer_agt;
38#[cfg(gpt)]
39pub mod timer_gpt;
40#[cfg(ulpt)]
41pub mod timer_ulpt;
42pub mod watchdog;
43// pub mod sce5;
44#[cfg(slcdc)]
45pub mod slcdc;
46#[cfg(ra4m1)]
47pub mod spi;
48#[cfg(trust_zone)]
49pub mod trust_zone;
50
51// This uses cfg_select explicitly so we can avoid defining a time_driver module if the feature
52// isn't enabled, but still fail if we don't enable a specific time driver.
53cfg_select! {
54    feature = "time-driver" => {
55        #[cfg_attr(feature = "time-driver-agt", path = "time_driver_agt.rs")]
56        #[cfg_attr(any(feature = "time-driver-gpt0", feature = "time-driver-gpt1"), path = "time_driver_gpt.rs")]
57        #[cfg_attr(feature = "time-driver-ulpt", path = "time_driver_ulpt.rs")]
58        pub mod time_driver;
59    }
60    _ => {}
61}
62
63pub mod uart;
64
65pub mod write_protect;
66
67#[cfg(feature = "usb-driver")]
68pub mod usb;
69
70// Re-exports
71#[cfg(feature = "chrono")]
72pub use chrono;
73
74pub use embassy_hal_internal::Peri;
75
76cfg_select! {
77    feature = "unstable-pac" => {
78        pub use ra_metapac as pac;
79    }
80    _ => {
81        pub(crate) use ra_metapac as pac;
82    }
83}
84
85use crate::mcu_info::McuInfo;
86
87/// Coarse indication of why the processor reset.
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89#[allow(unused)]
90pub enum ResetCause {
91    /// Power was turned on.
92    PowerOn,
93
94    /// Low voltage monitor 0, 1, or 2 tripped.
95    LowVoltage,
96
97    /// Watchdog or independent watchdog.
98    Watchdog,
99
100    /// Bus error, parity error, or ECC error.
101    HadwareError,
102
103    /// Stack pointer error.
104    StackPointer,
105
106    /// Software reset requested.
107    SoftwareReset,
108
109    /// Should never be here.
110    Unknown,
111}
112
113/// Initializes the MCU.
114///
115/// # Returns
116///
117/// The available peripherals as a [`Peripherals`] struct.
118pub fn init(clocks: clock::ClockConfig) -> Peripherals {
119    critical_section::with(|cs| {
120        debug!("Starting board init");
121
122        let mcu_info = McuInfo::info();
123
124        #[cfg(feature = "defmt")]
125        mcu_info.print_info();
126
127        // Check if the crate was configured correctly
128        mcu_info.validate_package();
129
130        {
131            let osm = pac::OSM;
132            debug!("OFS0: {}", osm.ofs0().read());
133            debug!("OFS1: {}", osm.ofs1().read());
134        }
135
136        #[cfg(trust_zone)]
137        trust_zone::init();
138
139        if clock::init(clocks).is_err() {
140            panic!("Clocks were already initialized?");
141        }
142        info!("{}", clock::clock_status());
143
144        #[cfg(feature = "time-driver")]
145        time_driver::init();
146
147        event_link::init();
148
149        dtc::init();
150
151        #[cfg(dmac)]
152        dmac::init();
153
154        Peripherals::take_with_cs(cs)
155    })
156}
157
158// NOTE: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
159/// Macro to bind interrupts to interrupt handlers.
160///
161/// For example:
162///
163/// ```rust,ignore
164/// use ra_hal::{bind_interrupts, peripherals::SCI1, uart};
165///
166/// bind_interrupts!(struct Irqs {
167///     IEL2 => uart::RxInterruptHandler<SCI1>;
168///     IEL3 => uart::TxInterruptHandler<SCI1>;
169///     IEL4 => uart::TeInterruptHandler<SCI1>;
170/// });
171///```
172///
173/// Any interrupt `IEL2..=IEL31` can be assigned to any one handler.
174/// Note that `IEL0` and `IEL1` are used by the [time driver](crate::time_driver) and are unavailable for general use.
175#[macro_export]
176macro_rules! bind_interrupts {
177    ($(#[$outer:meta])* $vis:vis struct $name:ident {
178        $(
179            $(#[doc = $doc:literal])*
180            $(#[cfg($cond_irq:meta)])?
181            $irq:ident => $(
182                $(#[cfg($cond_handler:meta)])?
183                $handler:ty
184            ),*;
185        )*
186    }) => {
187        #[derive(Copy, Clone)]
188        $(#[$outer])*
189        $vis struct $name;
190
191        $(
192            #[allow(non_snake_case)]
193            #[unsafe(no_mangle)]
194            $(#[cfg($cond_irq)])?
195            $(#[doc = $doc])*
196            unsafe extern "C" fn $irq() {
197                unsafe {
198                    $(
199                        $(#[cfg($cond_handler)])?
200                        <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
201
202                    )*
203                }
204            }
205
206            $(#[cfg($cond_irq)])?
207            $crate::bind_interrupts!(@inner
208                $(
209                    $(#[cfg($cond_handler)])?
210                    unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
211                )*
212            );
213        )*
214    };
215    (@inner $($t:tt)*) => {
216        $($t)*
217    }
218}
219
220include!(concat!(env!("OUT_DIR"), "/misc.rs"));
221include!(concat!(env!("OUT_DIR"), "/interrupts.rs"));
222include!(concat!(env!("OUT_DIR"), "/peripherals.rs"));
223include!(concat!(env!("OUT_DIR"), "/module_stops.rs"));
224
225#[allow(missing_docs)]
226pub mod constants {
227    include!(concat!(env!("OUT_DIR"), "/constants.rs"));
228}
229
230#[cfg(not(feature = "skip-osm"))]
231mod _osm_config {
232    use crate::osm::{ofs0::Ofs0, ofs1::Ofs1, sec_mpu::SecurityMpu};
233
234    // Option Function Select Register 0
235    #[unsafe(no_mangle)]
236    #[unsafe(link_section = ".ofs0")]
237    static OFS0: Ofs0 = Ofs0::default();
238
239    // Option Function Select Register 1
240    #[unsafe(no_mangle)]
241    #[unsafe(link_section = ".ofs1")]
242    static OFS1: Ofs1 = Ofs1::default();
243
244    // Security MPU
245    #[unsafe(no_mangle)]
246    #[unsafe(link_section = ".sec_mpu")]
247    static SEC_MPU: SecurityMpu = SecurityMpu::disabled();
248}
249
250/// Calls the semihosting exit hook.
251/// Will cause an exception without a semihosting implementation on the host side.
252#[macro_export]
253macro_rules! exit {
254    () => {
255        unsafe {
256            cortex_m::asm::semihosting_syscall(0x18, 0x20026);
257        };
258    };
259}