1 | use core::marker::PhantomData; |
2 | |
3 | use embassy_hal_internal::into_ref; |
4 | |
5 | use crate::gpio::{AfType, OutputType, Speed}; |
6 | #[cfg (not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] |
7 | pub use crate::pac::rcc::vals::Mcopre as McoPrescaler; |
8 | #[cfg (not(any( |
9 | rcc_f2, |
10 | rcc_f410, |
11 | rcc_f4, |
12 | rcc_f7, |
13 | rcc_h50, |
14 | rcc_h5, |
15 | rcc_h7ab, |
16 | rcc_h7rm0433, |
17 | rcc_h7, |
18 | rcc_h7rs |
19 | )))] |
20 | pub use crate::pac::rcc::vals::Mcosel as McoSource; |
21 | #[cfg (any( |
22 | rcc_f2, |
23 | rcc_f410, |
24 | rcc_f4, |
25 | rcc_f7, |
26 | rcc_h50, |
27 | rcc_h5, |
28 | rcc_h7ab, |
29 | rcc_h7rm0433, |
30 | rcc_h7, |
31 | rcc_h7rs |
32 | ))] |
33 | pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source}; |
34 | use crate::pac::RCC; |
35 | use crate::{peripherals, Peripheral}; |
36 | |
37 | #[cfg (any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37))] |
38 | #[derive (Copy, Clone, Eq, PartialEq, Ord, PartialOrd)] |
39 | pub enum McoPrescaler { |
40 | DIV1, |
41 | } |
42 | |
43 | pub(crate) trait SealedMcoInstance {} |
44 | |
45 | #[allow (private_bounds)] |
46 | pub trait McoInstance: SealedMcoInstance + 'static { |
47 | type Source; |
48 | |
49 | #[doc (hidden)] |
50 | unsafe fn _apply_clock_settings(source: Self::Source, prescaler: super::McoPrescaler); |
51 | } |
52 | |
53 | pin_trait!(McoPin, McoInstance); |
54 | |
55 | macro_rules! impl_peri { |
56 | ($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => { |
57 | impl SealedMcoInstance for peripherals::$peri {} |
58 | impl McoInstance for peripherals::$peri { |
59 | type Source = $source; |
60 | |
61 | unsafe fn _apply_clock_settings(source: Self::Source, _prescaler: McoPrescaler) { |
62 | #[cfg(not(any(stm32u5, stm32wba)))] |
63 | let r = RCC.cfgr(); |
64 | #[cfg(any(stm32u5, stm32wba))] |
65 | let r = RCC.cfgr1(); |
66 | |
67 | r.modify(|w| { |
68 | w.$set_source(source); |
69 | #[cfg(not(any(stm32f1, rcc_f0v1, rcc_f3v1, rcc_f37)))] |
70 | w.$set_prescaler(_prescaler); |
71 | }); |
72 | } |
73 | } |
74 | }; |
75 | } |
76 | |
77 | #[cfg (any(rcc_c0, rcc_g0, rcc_u0))] |
78 | #[allow (unused_imports)] |
79 | use self::{McoSource as Mco1Source, McoSource as Mco2Source}; |
80 | |
81 | #[cfg (mco)] |
82 | impl_peri!(MCO, McoSource, set_mcosel, set_mcopre); |
83 | #[cfg (mco1)] |
84 | impl_peri!(MCO1, Mco1Source, set_mco1sel, set_mco1pre); |
85 | #[cfg (mco2)] |
86 | impl_peri!(MCO2, Mco2Source, set_mco2sel, set_mco2pre); |
87 | |
88 | pub struct Mco<'d, T: McoInstance> { |
89 | phantom: PhantomData<&'d mut T>, |
90 | } |
91 | |
92 | impl<'d, T: McoInstance> Mco<'d, T> { |
93 | /// Create a new MCO instance. |
94 | pub fn new( |
95 | _peri: impl Peripheral<P = T> + 'd, |
96 | pin: impl Peripheral<P = impl McoPin<T>> + 'd, |
97 | source: T::Source, |
98 | prescaler: McoPrescaler, |
99 | ) -> Self { |
100 | into_ref!(pin); |
101 | |
102 | critical_section::with(|_| unsafe { |
103 | T::_apply_clock_settings(source, prescaler); |
104 | pin.set_as_af(pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh)); |
105 | }); |
106 | |
107 | Self { phantom: PhantomData } |
108 | } |
109 | } |
110 | |