py32_hal/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![allow(async_fn_in_trait)]
3
4// This must go FIRST so that all the other modules see its macros.
5mod fmt;
6include!(concat!(env!("OUT_DIR"), "/_macros.rs"));
7
8mod macros;
9#[cfg(dma)]
10use embassy_hal_internal::interrupt::Priority;
11pub use py32_metapac as pac;
12
13/// Operating modes for peripherals.
14pub mod mode {
15    trait SealedMode {}
16
17    /// Operating mode for a peripheral.
18    #[allow(private_bounds)]
19    pub trait Mode: SealedMode {}
20
21    macro_rules! impl_mode {
22        ($name:ident) => {
23            impl SealedMode for $name {}
24            impl Mode for $name {}
25        };
26    }
27
28    /// Blocking mode.
29    pub struct Blocking;
30    /// Async mode.
31    pub struct Async;
32
33    impl_mode!(Blocking);
34    impl_mode!(Async);
35}
36
37pub mod adc;
38#[cfg(dma)]
39pub mod dma;
40pub mod flash;
41pub mod gpio;
42pub mod i2c;
43pub mod rcc;
44pub mod timer;
45pub mod usart;
46
47#[cfg(any(feature = "embassy-usb-driver-impl", feature = "usb-device-impl"))]
48pub mod usb;
49
50#[cfg(feature = "exti")]
51pub mod exti;
52
53pub mod embassy;
54pub mod time;
55#[cfg(feature = "time-driver-systick")]
56pub use embassy::systick_time_driver;
57#[cfg(all(feature = "_time-driver", not(feature = "time-driver-systick")))]
58pub use embassy::time_driver;
59
60#[cfg(feature = "time-driver-systick")]
61use cortex_m::peripheral::SYST;
62
63/// `py32-hal` global configuration.
64#[non_exhaustive]
65#[derive(Clone, Copy)]
66pub struct Config {
67    /// RCC config.
68    pub rcc: rcc::Config,
69    /// Enable debug during sleep and stop.
70    ///
71    /// May increase power consumption. Defaults to true.
72    #[cfg(dbgmcu)]
73    pub enable_debug_during_sleep: bool,
74
75    // /// BDMA interrupt priority.
76    // ///
77    // /// Defaults to P0 (highest).
78    // #[cfg(bdma)]
79    // pub bdma_interrupt_priority: Priority,
80    /// DMA interrupt priority.
81    ///
82    /// Defaults to P0 (highest).
83    #[cfg(dma)]
84    pub dma_interrupt_priority: Priority,
85    // /// GPDMA interrupt priority.
86    // ///
87    // /// Defaults to P0 (highest).
88    // #[cfg(gpdma)]
89    // pub gpdma_interrupt_priority: Priority,
90}
91
92impl Default for Config {
93    fn default() -> Self {
94        Self {
95            rcc: Default::default(),
96            #[cfg(dbgmcu)]
97            enable_debug_during_sleep: true,
98            // #[cfg(any(stm32l4, stm32l5, stm32u5))]
99            // enable_independent_io_supply: true,
100            // #[cfg(bdma)]
101            // bdma_interrupt_priority: Priority::P0,
102            #[cfg(dma)]
103            dma_interrupt_priority: Priority::P0,
104            // #[cfg(gpdma)]
105            // gpdma_interrupt_priority: Priority::P0,
106        }
107    }
108}
109
110/// Initialize the `embassy-stm32` HAL with the provided configuration.
111///
112/// This returns the peripheral singletons that can be used for creating drivers.
113///
114/// This should only be called once at startup, otherwise it panics.
115pub fn init(config: Config, #[cfg(feature = "time-driver-systick")] systick: SYST) -> Peripherals {
116    critical_section::with(|cs| {
117        let p = Peripherals::take_with_cs(cs);
118        
119        rcc::enable_and_reset_with_cs::<peripherals::DBGMCU>(cs);
120        crate::pac::DBGMCU.cr().modify(|cr| {
121            #[cfg(dbgmcu_f072)]
122            cr.set_dbg_sleep(config.enable_debug_during_sleep);
123            cr.set_dbg_stop(config.enable_debug_during_sleep);
124        });
125
126        unsafe {
127            rcc::init(config.rcc);
128            crate::_generated::init_syscfg();
129
130            gpio::init(cs);
131
132            // must be after rcc init
133            #[cfg(all(feature = "_time-driver", not(feature = "time-driver-systick")))]
134            time_driver::init(cs);
135
136            #[cfg(feature = "time-driver-systick")]
137            systick_time_driver::init(cs, systick);
138
139            #[cfg(feature = "exti")]
140            exti::init(cs);
141
142            #[cfg(dma)]
143            dma::init(cs, config.dma_interrupt_priority);
144        };
145        rcc::enable_and_reset_with_cs::<peripherals::FLASH>(cs);
146
147        p
148    })
149}
150
151// This must go last, so that it sees all the impl_foo! macros defined earlier.
152pub(crate) mod _generated {
153    #![allow(dead_code)]
154    #![allow(unused_imports)]
155    #![allow(non_snake_case)]
156    #![allow(missing_docs)]
157
158    include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
159}
160
161pub use crate::_generated::interrupt;
162
163pub use _generated::{peripherals, Peripherals};
164pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
165
166// developer note: this macro can't be in `embassy-hal-internal` due to the use of `$crate`.
167#[macro_export]
168macro_rules! bind_interrupts {
169    ($vis:vis struct $name:ident {
170        $(
171            $(#[cfg($cond_irq:meta)])?
172            $irq:ident => $(
173                $(#[cfg($cond_handler:meta)])?
174                $handler:ty
175            ),*;
176        )*
177    }) => {
178        #[derive(Copy, Clone)]
179        $vis struct $name;
180
181        $(
182            #[allow(non_snake_case)]
183            #[no_mangle]
184            $(#[cfg($cond_irq)])?
185            unsafe extern "C" fn $irq() {
186                $(
187                    $(#[cfg($cond_handler)])?
188                    <$handler as $crate::interrupt::typelevel::Handler<$crate::interrupt::typelevel::$irq>>::on_interrupt();
189
190                )*
191            }
192            $(#[cfg($cond_irq)])?
193            $crate::bind_interrupts!(@inner
194                $(
195                    $(#[cfg($cond_handler)])?
196                    unsafe impl $crate::interrupt::typelevel::Binding<$crate::interrupt::typelevel::$irq, $handler> for $name {}
197                )*
198            );
199        )*
200    };
201    (@inner $($t:tt)*) => {
202        $($t)*
203    }
204}