Skip to main content

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