stm32: implement MCO for all chips.

This commit is contained in:
Dario Nieuwenhuis
2023-10-07 01:15:24 +02:00
parent 68c4820dde
commit 3a8e0d4a27
10 changed files with 48 additions and 338 deletions

View File

@ -4,18 +4,19 @@ use embassy_hal_internal::into_ref;
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
#[cfg(not(stm32wl))]
pub use crate::pac::rcc::vals::{Mco1 as Mco1Source, Mco2 as Mco2Source};
#[cfg(stm32wl)]
pub use crate::pac::rcc::vals::{Mcopre, Mcosel};
#[cfg(not(stm32f1))]
pub use crate::pac::rcc::vals::Mcopre as McoPrescaler;
#[cfg(not(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7)))]
pub use crate::pac::rcc::vals::Mcosel as McoSource;
#[cfg(any(rcc_f2, rcc_f410, rcc_f4, rcc_f7, rcc_h50, rcc_h5, rcc_h7ab, rcc_h7rm0433, rcc_h7))]
pub use crate::pac::rcc::vals::{Mco1sel as Mco1Source, Mco2sel as Mco2Source};
use crate::pac::RCC;
use crate::{peripherals, Peripheral};
pub(crate) mod sealed {
pub trait McoInstance {
type Source;
type Prescaler;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Self::Prescaler);
unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: super::McoPrescaler);
}
}
@ -24,14 +25,19 @@ pub trait McoInstance: sealed::McoInstance + 'static {}
pin_trait!(McoPin, McoInstance);
macro_rules! impl_peri {
($peri:ident, $source:ident, $prescaler:ident, $set_source:ident, $set_prescaler:ident) => {
($peri:ident, $source:ident, $set_source:ident, $set_prescaler:ident) => {
impl sealed::McoInstance for peripherals::$peri {
type Source = $source;
type Prescaler = $prescaler;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Self::Prescaler) {
RCC.cfgr().modify(|w| {
unsafe fn apply_clock_settings(source: Self::Source, #[cfg(not(stm32f1))] prescaler: McoPrescaler) {
#[cfg(not(any(stm32u5, stm32wba)))]
let r = RCC.cfgr();
#[cfg(any(stm32u5, stm32wba))]
let r = RCC.cfgr1();
r.modify(|w| {
w.$set_source(source);
#[cfg(not(stm32f1))]
w.$set_prescaler(prescaler);
});
}
@ -41,12 +47,16 @@ macro_rules! impl_peri {
};
}
#[cfg(not(stm32wl))]
impl_peri!(MCO1, Mco1Source, u8, set_mco1, set_mco1pre);
#[cfg(not(stm32wl))]
impl_peri!(MCO2, Mco2Source, u8, set_mco2, set_mco2pre);
#[cfg(stm32wl)]
impl_peri!(MCO, Mcosel, Mcopre, set_mcosel, set_mcopre);
#[cfg(any(rcc_c0, rcc_g0))]
#[allow(unused_imports)]
use self::{McoSource as Mco1Source, McoSource as Mco2Source};
#[cfg(mco)]
impl_peri!(MCO, McoSource, set_mcosel, set_mcopre);
#[cfg(mco1)]
impl_peri!(MCO1, Mco1Source, set_mco1sel, set_mco1pre);
#[cfg(mco2)]
impl_peri!(MCO2, Mco2Source, set_mco2sel, set_mco2pre);
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
@ -54,24 +64,20 @@ pub struct Mco<'d, T: McoInstance> {
impl<'d, T: McoInstance> Mco<'d, T> {
/// Create a new MCO instance.
///
/// `prescaler` must be between 1 and 15 for implementations not using Presel enum.
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: T::Source,
prescaler: T::Prescaler,
#[cfg(not(stm32f1))] prescaler: McoPrescaler,
) -> Self {
into_ref!(pin);
#[cfg(not(stm32wl))]
assert!(
1 <= prescaler && prescaler <= 15,
"Mco prescaler must be between 1 and 15. Refer to the reference manual for more information."
);
critical_section::with(|_| unsafe {
T::apply_clock_settings(source, prescaler);
T::apply_clock_settings(
source,
#[cfg(not(stm32f1))]
prescaler,
);
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh);
});