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

@ -59,7 +59,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f0f06b4c95bd9e185e4aa5f2e1d4b76ba84f1594" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7bf7f02d1e0bc720c24dbb8881677a298890365" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -78,7 +78,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-f0f06b4c95bd9e185e4aa5f2e1d4b76ba84f1594", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-a7bf7f02d1e0bc720c24dbb8881677a298890365", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -52,7 +52,11 @@ fn main() {
"rcc" => { "rcc" => {
for pin in p.pins { for pin in p.pins {
if pin.signal.starts_with("MCO") { if pin.signal.starts_with("MCO") {
singletons.push(pin.signal.replace('_', "").to_string()); let name = pin.signal.replace('_', "").to_string();
if !singletons.contains(&name) {
println!("cargo:rustc-cfg={}", name.to_ascii_lowercase());
singletons.push(name);
}
} }
} }
singletons.push(p.name.to_string()); singletons.push(p.name.to_string());

View File

@ -1,16 +1,8 @@
use core::marker::PhantomData;
use embassy_hal_internal::into_ref;
use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre};
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; use crate::pac::rcc::vals::{Hpre, Ppre, Sw};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Peripheral};
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
@ -197,164 +189,6 @@ fn setup_pll(
} }
} }
pub enum McoClock {
DIV1,
DIV2,
DIV3,
DIV4,
DIV5,
}
impl McoClock {
fn into_raw(&self) -> Mcopre {
match self {
McoClock::DIV1 => Mcopre::DIV1,
McoClock::DIV2 => Mcopre::DIV2,
McoClock::DIV3 => Mcopre::DIV3,
McoClock::DIV4 => Mcopre::DIV4,
McoClock::DIV5 => Mcopre::DIV5,
}
}
}
#[derive(Copy, Clone)]
pub enum Mco1Source {
Hsi,
Lse,
Hse,
Pll,
}
impl Default for Mco1Source {
fn default() -> Self {
Self::Hsi
}
}
pub trait McoSource {
type Raw;
fn into_raw(&self) -> Self::Raw;
}
impl McoSource for Mco1Source {
type Raw = Mco1;
fn into_raw(&self) -> Self::Raw {
match self {
Mco1Source::Hsi => Mco1::HSI,
Mco1Source::Lse => Mco1::LSE,
Mco1Source::Hse => Mco1::HSE,
Mco1Source::Pll => Mco1::PLL,
}
}
}
#[derive(Copy, Clone)]
pub enum Mco2Source {
SysClk,
Plli2s,
Hse,
Pll,
}
impl Default for Mco2Source {
fn default() -> Self {
Self::SysClk
}
}
impl McoSource for Mco2Source {
type Raw = Mco2;
fn into_raw(&self) -> Self::Raw {
match self {
Mco2Source::SysClk => Mco2::SYSCLK,
Mco2Source::Plli2s => Mco2::PLLI2S,
Mco2Source::Hse => Mco2::HSE,
Mco2Source::Pll => Mco2::PLL,
}
}
}
pub(crate) mod sealed {
use stm32_metapac::rcc::vals::Mcopre;
pub trait McoInstance {
type Source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre);
}
}
pub trait McoInstance: sealed::McoInstance + 'static {}
pin_trait!(McoPin, McoInstance);
impl sealed::McoInstance for peripherals::MCO1 {
type Source = Mco1;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
RCC.cfgr().modify(|w| {
w.set_mco1(source);
w.set_mco1pre(prescaler);
});
match source {
Mco1::PLL => {
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
Mco1::HSI => {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
}
_ => {}
}
}
}
impl McoInstance for peripherals::MCO1 {}
impl sealed::McoInstance for peripherals::MCO2 {
type Source = Mco2;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
RCC.cfgr().modify(|w| {
w.set_mco2(source);
w.set_mco2pre(prescaler);
});
match source {
Mco2::PLL => {
RCC.cr().modify(|w| w.set_pllon(true));
while !RCC.cr().read().pllrdy() {}
}
#[cfg(not(stm32f410))]
Mco2::PLLI2S => {
RCC.cr().modify(|w| w.set_plli2son(true));
while !RCC.cr().read().plli2srdy() {}
}
_ => {}
}
}
}
impl McoInstance for peripherals::MCO2 {}
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: McoInstance> Mco<'d, T> {
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: impl McoSource<Raw = T::Source>,
prescaler: McoClock,
) -> Self {
into_ref!(pin);
critical_section::with(|_| unsafe {
T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh);
});
Self { phantom: PhantomData }
}
}
fn flash_setup(sysclk: u32) { fn flash_setup(sysclk: u32) {
use crate::pac::flash::vals::Latency; use crate::pac::flash::vals::Latency;

View File

@ -1,18 +1,11 @@
use core::marker::PhantomData;
use embassy_hal_internal::into_ref;
use stm32_metapac::rcc::regs::Cfgr; use stm32_metapac::rcc::regs::Cfgr;
use stm32_metapac::rcc::vals::{Mcopre, Mcosel};
pub use super::bus::{AHBPrescaler, APBPrescaler}; pub use super::bus::{AHBPrescaler, APBPrescaler};
use crate::gpio::sealed::AFType;
use crate::gpio::Speed;
use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw};
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, RCC};
use crate::rcc::bd::{BackupDomain, RtcClockSource}; use crate::rcc::bd::{BackupDomain, RtcClockSource};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
use crate::{peripherals, Peripheral};
/// HSI speed /// HSI speed
pub const HSI_FREQ: Hertz = Hertz(16_000_000); pub const HSI_FREQ: Hertz = Hertz(16_000_000);
@ -263,131 +256,6 @@ impl Default for Config {
} }
} }
pub enum McoClock {
DIV1,
DIV2,
DIV4,
DIV8,
DIV16,
}
impl McoClock {
fn into_raw(&self) -> Mcopre {
match self {
McoClock::DIV1 => Mcopre::DIV1,
McoClock::DIV2 => Mcopre::DIV2,
McoClock::DIV4 => Mcopre::DIV4,
McoClock::DIV8 => Mcopre::DIV8,
McoClock::DIV16 => Mcopre::DIV16,
}
}
}
#[derive(Copy, Clone)]
pub enum Mco1Source {
Disabled,
Lse,
Lsi,
Hse,
Hsi16,
PllClk,
SysClk,
Msi,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
Hsi48,
}
impl Default for Mco1Source {
fn default() -> Self {
Self::Hsi16
}
}
pub trait McoSource {
type Raw;
fn into_raw(&self) -> Self::Raw;
}
impl McoSource for Mco1Source {
type Raw = Mcosel;
fn into_raw(&self) -> Self::Raw {
match self {
Mco1Source::Disabled => Mcosel::NOCLOCK,
Mco1Source::Lse => Mcosel::LSE,
Mco1Source::Lsi => Mcosel::LSI,
Mco1Source::Hse => Mcosel::HSE,
Mco1Source::Hsi16 => Mcosel::HSI16,
Mco1Source::PllClk => Mcosel::PLL,
Mco1Source::SysClk => Mcosel::SYSCLK,
Mco1Source::Msi => Mcosel::MSI,
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
Mco1Source::Hsi48 => Mcosel::HSI48,
}
}
}
pub(crate) mod sealed {
use stm32_metapac::rcc::vals::Mcopre;
pub trait McoInstance {
type Source;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre);
}
}
pub trait McoInstance: sealed::McoInstance + 'static {}
pin_trait!(McoPin, McoInstance);
impl sealed::McoInstance for peripherals::MCO {
type Source = Mcosel;
unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) {
RCC.cfgr().modify(|w| {
w.set_mcosel(source);
w.set_mcopre(prescaler);
});
match source {
Mcosel::HSI16 => {
RCC.cr().modify(|w| w.set_hsion(true));
while !RCC.cr().read().hsirdy() {}
}
#[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))]
Mcosel::HSI48 => {
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
_ => {}
}
}
}
impl McoInstance for peripherals::MCO {}
pub struct Mco<'d, T: McoInstance> {
phantom: PhantomData<&'d mut T>,
}
impl<'d, T: McoInstance> Mco<'d, T> {
pub fn new(
_peri: impl Peripheral<P = T> + 'd,
pin: impl Peripheral<P = impl McoPin<T>> + 'd,
source: impl McoSource<Raw = T::Source>,
prescaler: McoClock,
) -> Self {
into_ref!(pin);
critical_section::with(|_| unsafe {
T::apply_clock_settings(source.into_raw(), prescaler.into_raw());
pin.set_as_af(pin.af_num(), AFType::OutputPushPull);
pin.set_speed(Speed::VeryHigh);
});
Self { phantom: PhantomData }
}
}
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
// Switch to MSI to prevent problems with PLL configuration. // Switch to MSI to prevent problems with PLL configuration.
if !RCC.cr().read().msion() { if !RCC.cr().read().msion() {

View File

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

View File

@ -7,9 +7,7 @@ use crate::time::Hertz;
pub(crate) mod bd; pub(crate) mod bd;
mod bus; mod bus;
#[cfg(any(stm32h5, stm32h7, stm32wl))]
mod mco; mod mco;
#[cfg(any(stm32h5, stm32h7, stm32wl))]
pub use mco::*; pub use mco::*;
#[cfg_attr(rcc_f0, path = "f0.rs")] #[cfg_attr(rcc_f0, path = "f0.rs")]

View File

@ -5,7 +5,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoClock}; use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoPrescaler};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -14,8 +14,8 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); let p = embassy_stm32::init(Default::default());
info!("Hello World!"); info!("Hello World!");
let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::DIV1); let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV1);
let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::Pll, McoClock::DIV4); let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::PLL, McoPrescaler::DIV4);
let mut led = Output::new(p.PB7, Level::High, Speed::Low); let mut led = Output::new(p.PB7, Level::High, Speed::Low);
loop { loop {

View File

@ -6,7 +6,7 @@ use embassy_executor::Spawner;
use embassy_stm32::dcmi::{self, *}; use embassy_stm32::dcmi::{self, *};
use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::i2c::I2c; use embassy_stm32::i2c::I2c;
use embassy_stm32::rcc::{Mco, Mco1Source}; use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler};
use embassy_stm32::time::khz; use embassy_stm32::time::khz;
use embassy_stm32::{bind_interrupts, i2c, peripherals, Config}; use embassy_stm32::{bind_interrupts, i2c, peripherals, Config};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
@ -49,7 +49,7 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
defmt::info!("Hello World!"); defmt::info!("Hello World!");
let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 3); let mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV3);
let mut led = Output::new(p.PE3, Level::High, Speed::Low); let mut led = Output::new(p.PE3, Level::High, Speed::Low);
let cam_i2c = I2c::new( let cam_i2c = I2c::new(

View File

@ -5,7 +5,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::rcc::{Mco, Mco1Source}; use embassy_stm32::rcc::{Mco, Mco1Source, McoPrescaler};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -16,7 +16,7 @@ async fn main(_spawner: Spawner) {
let mut led = Output::new(p.PB14, Level::High, Speed::Low); let mut led = Output::new(p.PB14, Level::High, Speed::Low);
let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, 8); let _mco = Mco::new(p.MCO1, p.PA8, Mco1Source::HSI, McoPrescaler::DIV8);
loop { loop {
info!("high"); info!("high");

View File

@ -5,7 +5,7 @@
use defmt::*; use defmt::*;
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; use embassy_stm32::rcc::{Mco, McoPrescaler, McoSource};
use embassy_time::{Duration, Timer}; use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _}; use {defmt_rtt as _, panic_probe as _};
@ -14,7 +14,7 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Default::default()); let p = embassy_stm32::init(Default::default());
info!("Hello World!"); info!("Hello World!");
let _mco = Mco::new(p.MCO, p.PA8, Mco1Source::Hsi16, McoClock::DIV1); let _mco = Mco::new(p.MCO, p.PA8, McoSource::HSI16, McoPrescaler::DIV1);
let mut led = Output::new(p.PB14, Level::High, Speed::Low); let mut led = Output::new(p.PB14, Level::High, Speed::Low);