stm32: autogenerate mux config for all chips.

This commit is contained in:
Dario Nieuwenhuis 2024-02-26 03:28:27 +01:00
parent d5c9c611fa
commit 95234cddba
30 changed files with 412 additions and 518 deletions

View file

@ -70,7 +70,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0"
critical-section = "1.1"
#stm32-metapac = { version = "15" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54" }
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d" }
vcell = "0.1.3"
bxcan = "0.7.0"
nb = "1.0.0"
@ -94,7 +94,7 @@ critical-section = { version = "1.1", features = ["std"] }
proc-macro2 = "1.0.36"
quote = "1.0.15"
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d7462d805ef05892531a83cd9ad60c9cba568d54", default-features = false, features = ["metadata"]}
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e853cf944b150898312984d092d63926970c340d", default-features = false, features = ["metadata"]}
[features]

View file

@ -5,7 +5,9 @@ use std::{env, fs};
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote};
use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccKernelClock, StopMode, METADATA};
use stm32_metapac::metadata::{
MemoryRegionKind, PeripheralRccKernelClock, PeripheralRccRegister, PeripheralRegisters, StopMode, METADATA,
};
fn main() {
let target = env::var("TARGET").unwrap();
@ -374,12 +376,130 @@ fn main() {
}
}
let force_refcount = HashSet::from(["usart"]);
let mut refcount_statics = BTreeSet::new();
struct ClockGen<'a> {
rcc_registers: &'a PeripheralRegisters,
chained_muxes: HashMap<&'a str, &'a PeripheralRccRegister>,
force_refcount: HashSet<&'a str>,
let mut clock_names = BTreeSet::new();
refcount_statics: BTreeSet<Ident>,
clock_names: BTreeSet<String>,
muxes: BTreeSet<(Ident, Ident, Ident)>,
}
let mut rcc_cfgr_regs = BTreeSet::new();
let mut clock_gen = ClockGen {
rcc_registers,
chained_muxes: HashMap::new(),
force_refcount: HashSet::from(["usart"]),
refcount_statics: BTreeSet::new(),
clock_names: BTreeSet::new(),
muxes: BTreeSet::new(),
};
if chip_name.starts_with("stm32h5") {
clock_gen.chained_muxes.insert(
"PER",
&PeripheralRccRegister {
register: "CCIPR5",
field: "PERSEL",
},
);
}
if chip_name.starts_with("stm32h7") {
clock_gen.chained_muxes.insert(
"PER",
&PeripheralRccRegister {
register: "D1CCIPR",
field: "PERSEL",
},
);
}
if chip_name.starts_with("stm32u5") {
clock_gen.chained_muxes.insert(
"ICLK",
&PeripheralRccRegister {
register: "CCIPR1",
field: "ICLKSEL",
},
);
}
if chip_name.starts_with("stm32wb") && !chip_name.starts_with("stm32wba") {
clock_gen.chained_muxes.insert(
"CLK48",
&PeripheralRccRegister {
register: "CCIPR",
field: "CLK48SEL",
},
);
}
if chip_name.starts_with("stm32f7") {
clock_gen.chained_muxes.insert(
"CLK48",
&PeripheralRccRegister {
register: "DCKCFGR2",
field: "CLK48SEL",
},
);
}
if chip_name.starts_with("stm32f4") && !chip_name.starts_with("stm32f410") {
clock_gen.chained_muxes.insert(
"CLK48",
&PeripheralRccRegister {
register: "DCKCFGR",
field: "CLK48SEL",
},
);
}
impl<'a> ClockGen<'a> {
fn gen_clock(&mut self, name: &str) -> TokenStream {
let clock_name = format_ident!("{}", name.to_ascii_lowercase());
self.clock_names.insert(name.to_ascii_lowercase());
quote!( unsafe { crate::rcc::get_freqs().#clock_name.unwrap() } )
}
fn gen_mux(&mut self, mux: &PeripheralRccRegister) -> TokenStream {
let ir = &self.rcc_registers.ir;
let fieldset_name = mux.register.to_ascii_lowercase();
let fieldset = ir
.fieldsets
.iter()
.find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
.unwrap();
let field_name = mux.field.to_ascii_lowercase();
let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
let enum_name = field.enumm.unwrap();
let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
let fieldset_name = format_ident!("{}", fieldset_name);
let field_name = format_ident!("{}", field_name);
let enum_name = format_ident!("{}", enum_name);
self.muxes
.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
let mut match_arms = TokenStream::new();
for v in enumm.variants.iter().filter(|v| v.name != "DISABLE") {
let variant_name = format_ident!("{}", v.name);
let expr = if let Some(mux) = self.chained_muxes.get(&v.name) {
self.gen_mux(mux)
} else {
self.gen_clock(&v.name)
};
match_arms.extend(quote! {
crate::pac::rcc::vals::#enum_name::#variant_name => #expr,
});
}
quote! {
match crate::pac::RCC.#fieldset_name().read().#field_name() {
#match_arms
#[allow(unreachable_patterns)]
_ => unreachable!(),
}
}
}
}
for p in METADATA.peripherals {
if !singletons.contains(&p.name.to_string()) {
@ -416,12 +536,12 @@ fn main() {
let set_en_field = format_ident!("set_{}", en.field.to_ascii_lowercase());
let refcount =
force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
clock_gen.force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
let (before_enable, before_disable) = if refcount {
let refcount_static =
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
refcount_statics.insert(refcount_static.clone());
clock_gen.refcount_statics.insert(refcount_static.clone());
(
quote! {
@ -442,63 +562,12 @@ fn main() {
};
let clock_frequency = match &rcc.kernel_clock {
PeripheralRccKernelClock::Mux(mux) => {
let ir = &rcc_registers.ir;
let fieldset_name = mux.register.to_ascii_lowercase();
let fieldset = ir
.fieldsets
.iter()
.find(|i| i.name.eq_ignore_ascii_case(&fieldset_name))
.unwrap();
let field_name = mux.field.to_ascii_lowercase();
let field = fieldset.fields.iter().find(|i| i.name == field_name).unwrap();
let enum_name = field.enumm.unwrap();
let enumm = ir.enums.iter().find(|i| i.name == enum_name).unwrap();
let fieldset_name = format_ident!("{}", fieldset_name);
let field_name = format_ident!("{}", field_name);
let enum_name = format_ident!("{}", enum_name);
rcc_cfgr_regs.insert((fieldset_name.clone(), field_name.clone(), enum_name.clone()));
let match_arms: TokenStream = enumm
.variants
.iter()
.filter(|v| v.name != "DISABLE")
.map(|v| {
let variant_name = format_ident!("{}", v.name);
let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
clock_names.insert(v.name.to_ascii_lowercase());
quote! {
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
}
})
.collect();
quote! {
use crate::pac::rcc::vals::#enum_name;
#[allow(unreachable_patterns)]
match crate::pac::RCC.#fieldset_name().read().#field_name() {
#match_arms
_ => unreachable!(),
}
}
}
PeripheralRccKernelClock::Clock(clock) => {
let clock = clock.to_ascii_lowercase();
let clock_name = format_ident!("{}", clock);
clock_names.insert(clock.to_string());
quote! {
unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }
}
}
PeripheralRccKernelClock::Mux(mux) => clock_gen.gen_mux(mux),
PeripheralRccKernelClock::Clock(clock) => clock_gen.gen_clock(clock),
};
/*
A refcount leak can result if the same field is shared by peripherals with different stop modes
This condition should be checked in stm32-data
*/
// A refcount leak can result if the same field is shared by peripherals with different stop modes
// This condition should be checked in stm32-data
let stop_refcount = match rcc.stop_mode {
StopMode::Standby => None,
StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }),
@ -543,74 +612,79 @@ fn main() {
}
}
if !rcc_cfgr_regs.is_empty() {
println!("cargo:rustc-cfg=clock_mux");
let struct_fields: Vec<_> = clock_gen
.muxes
.iter()
.map(|(_fieldset, fieldname, enum_name)| {
quote! {
pub #fieldname: #enum_name
}
})
.collect();
let struct_fields: Vec<_> = rcc_cfgr_regs
let mut inits = TokenStream::new();
for fieldset in clock_gen
.muxes
.iter()
.map(|(f, _, _)| f)
.collect::<BTreeSet<_>>()
.into_iter()
{
let setters: Vec<_> = clock_gen
.muxes
.iter()
.map(|(_fieldset, fieldname, enum_name)| {
quote! {
pub #fieldname: Option<#enum_name>
}
})
.collect();
let field_names: Vec<_> = rcc_cfgr_regs
.iter()
.map(|(_fieldset, fieldname, _enum_name)| fieldname)
.collect();
let inits: Vec<_> = rcc_cfgr_regs
.iter()
.map(|(fieldset, fieldname, _enum_name)| {
.filter(|(f, _, _)| f == fieldset)
.map(|(_, fieldname, _)| {
let setter = format_ident!("set_{}", fieldname);
quote! {
match self.#fieldname {
None => {}
Some(val) => {
crate::pac::RCC.#fieldset()
.modify(|w| w.#setter(val));
}
};
w.#setter(self.#fieldname);
}
})
.collect();
let enum_names: BTreeSet<_> = rcc_cfgr_regs
.iter()
.map(|(_fieldset, _fieldname, enum_name)| enum_name)
.collect();
g.extend(quote! {
pub mod mux {
#(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
#[derive(Clone, Copy)]
pub struct ClockMux {
#( #struct_fields, )*
}
impl Default for ClockMux {
fn default() -> Self {
Self {
#( #field_names: None, )*
}
}
}
impl ClockMux {
pub fn init(self) {
#( #inits )*
}
}
}
});
inits.extend(quote! {
crate::pac::RCC.#fieldset().modify(|w| {
#(#setters)*
});
})
}
let enum_names: BTreeSet<_> = clock_gen.muxes.iter().map(|(_, _, enum_name)| enum_name).collect();
g.extend(quote! {
pub mod mux {
#(pub use crate::pac::rcc::vals::#enum_names as #enum_names; )*
#[derive(Clone, Copy)]
pub struct ClockMux {
#( #struct_fields, )*
}
impl ClockMux {
pub(crate) const fn default() -> Self {
// safety: zero value is valid for all PAC enums.
unsafe { ::core::mem::zeroed() }
}
}
impl Default for ClockMux {
fn default() -> Self {
Self::default()
}
}
impl ClockMux {
pub(crate) fn init(&self) {
#inits
}
}
}
});
// Generate RCC
clock_names.insert("sys".to_string());
clock_names.insert("rtc".to_string());
let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect();
clock_gen.clock_names.insert("sys".to_string());
clock_gen.clock_names.insert("rtc".to_string());
let clock_idents: Vec<_> = clock_gen.clock_names.iter().map(|n| format_ident!("{}", n)).collect();
g.extend(quote! {
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -640,7 +714,8 @@ fn main() {
}
);
let refcount_mod: TokenStream = refcount_statics
let refcount_mod: TokenStream = clock_gen
.refcount_statics
.iter()
.map(|refcount_static| {
quote! {

View file

@ -7,7 +7,6 @@ use core::task::Poll;
use self::sealed::Instance;
use crate::interrupt;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::rcc::vals::{Lptim1sel, Lptim2sel};
use crate::peripherals::IPCC;
use crate::rcc::sealed::RccPeripheral;
@ -105,7 +104,8 @@ impl Ipcc {
IPCC::enable_and_reset();
IPCC::set_cpu2(true);
_configure_pwr();
// set RF wake-up clock = LSE
crate::pac::RCC.csr().modify(|w| w.set_rfwkpsel(0b01));
let regs = IPCC::regs();
@ -271,18 +271,3 @@ pub(crate) mod sealed {
fn state() -> &'static State;
}
}
fn _configure_pwr() {
// TODO: move the rest of this to rcc
let rcc = crate::pac::RCC;
// TODO: required
// set RF wake-up clock = LSE
rcc.csr().modify(|w| w.set_rfwkpsel(0b01));
// set LPTIM1 & LPTIM2 clock source
rcc.ccipr().modify(|w| {
w.set_lptim1sel(Lptim1sel::PCLK1);
w.set_lptim2sel(Lptim2sel::PCLK1);
});
}

View file

@ -21,6 +21,9 @@ pub struct Config {
pub ahb_pre: AHBPrescaler,
pub apb_pre: APBPrescaler,
pub ls: super::LsConfig,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
}
impl Default for Config {
@ -31,6 +34,7 @@ impl Default for Config {
ahb_pre: AHBPrescaler::DIV1,
apb_pre: APBPrescaler::DIV1,
ls: Default::default(),
mux: Default::default(),
}
}
}
@ -97,28 +101,25 @@ pub(crate) unsafe fn init(config: Config) {
if !set_flash_latency_after {
// Spin until the effective flash latency is compatible with the clock change
while FLASH.acr().read().latency().to_bits() < target_flash_latency.to_bits() {}
while FLASH.acr().read().latency() < target_flash_latency {}
}
// Configure SYSCLK source, HCLK divisor, and PCLK divisor all at once
let (sw, hpre, ppre) = (sw.into(), config.ahb_pre, config.apb_pre);
RCC.cfgr().modify(|w| {
w.set_sw(sw);
w.set_hpre(hpre);
w.set_ppre(ppre);
w.set_hpre(config.ahb_pre);
w.set_ppre(config.apb_pre);
});
if set_flash_latency_after {
// We can make the flash require fewer wait states
// Spin until the SYSCLK changes have taken effect
loop {
let cfgr = RCC.cfgr().read();
if cfgr.sw() == sw && cfgr.hpre() == hpre && cfgr.ppre() == ppre {
break;
}
// Spin until the SYSCLK changes have taken effect
loop {
let cfgr = RCC.cfgr().read();
if cfgr.sw() == sw && cfgr.hpre() == config.ahb_pre && cfgr.ppre() == config.apb_pre {
break;
}
}
// Set the flash latency to require fewer wait states
// Set the flash latency to require fewer wait states
if set_flash_latency_after {
FLASH.acr().modify(|w| w.set_latency(target_flash_latency));
}
@ -132,6 +133,11 @@ pub(crate) unsafe fn init(config: Config) {
}
};
config.mux.init();
// without this, the ringbuffered uart test fails.
cortex_m::asm::dsb();
set_clocks!(
hsi: None,
lse: None,

View file

@ -98,8 +98,8 @@ pub struct Config {
#[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
pub adc34: AdcClockSource,
#[cfg(clock_mux)]
pub mux: crate::rcc::mux::ClockMux,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
pub ls: super::LsConfig,
}
@ -128,7 +128,6 @@ impl Default for Config {
#[cfg(all(stm32f3, not(rcc_f37), adc3_common))]
adc34: AdcClockSource::Hclk(AdcHclkPrescaler::Div1),
#[cfg(clock_mux)]
mux: Default::default(),
}
}
@ -370,7 +369,6 @@ pub(crate) unsafe fn init(config: Config) {
};
*/
#[cfg(clock_mux)]
config.mux.init();
set_clocks!(

View file

@ -95,6 +95,9 @@ pub struct Config {
pub ls: super::LsConfig,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
#[cfg(stm32f2)]
pub voltage: VoltageScale,
}
@ -120,6 +123,7 @@ impl Default for Config {
#[cfg(stm32f2)]
voltage: VoltageScale::Range3,
mux: Default::default(),
}
}
}
@ -256,6 +260,8 @@ pub(crate) unsafe fn init(config: Config) {
});
while RCC.cfgr().read().sws() != config.sys {}
config.mux.init();
set_clocks!(
hsi: hsi,
hse: hse,
@ -286,7 +292,9 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
pllsai1_r: pllsai.r,
clk48: pll.q,
// TODO workaround until f4 rcc is fixed in stm32-data
#[cfg(not(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7)))]
pllsai1_q: None,
hsi_div488: hsi.map(|hsi| hsi/488u32),
hsi_hse: None,

View file

@ -71,22 +71,6 @@ pub enum PllSource {
HSE(Hertz, HseMode),
}
/// Sets the source for the 48MHz clock to the USB peripheral.
#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
pub enum UsbSrc {
/// Use the High Speed Internal Oscillator. The CRS must be used to calibrate the
/// oscillator to comply with the USB specification for oscillator tolerance.
#[cfg(any(stm32g0b1, stm32g0c1))]
Hsi48(super::Hsi48Config),
/// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. The
/// PLL needs to be using the HSE source to comply with the USB specification for oscillator
/// tolerance.
PllQ,
/// Use the HSE source directly. The HSE must be a 48MHz source. The HSE source must comply
/// with the USB specification for oscillator tolerance.
HSE,
}
/// Clocks configutation
pub struct Config {
pub sys: Sysclk,
@ -94,8 +78,10 @@ pub struct Config {
pub apb_pre: APBPrescaler,
pub low_power_run: bool,
pub ls: super::LsConfig,
#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
pub usb_src: Option<UsbSrc>,
#[cfg(crs)]
pub hsi48: Option<super::Hsi48Config>,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
}
impl Default for Config {
@ -107,8 +93,9 @@ impl Default for Config {
apb_pre: APBPrescaler::DIV1,
low_power_run: false,
ls: Default::default(),
#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
usb_src: None,
#[cfg(crs)]
hsi48: Some(Default::default()),
mux: Default::default(),
}
}
}
@ -322,34 +309,12 @@ pub(crate) unsafe fn init(config: Config) {
let lsi_freq = (sw == Sw::LSI).then_some(super::LSI_FREQ);
let hse_freq = (sw == Sw::HSE).then_some(sys_clk);
#[cfg(any(stm32g0b1, stm32g0c1, stm32g0b0))]
let hsi48_freq = config.usb_src.and_then(|config| {
match config {
UsbSrc::PllQ => {
// Make sure the PLLQ is enabled and running at 48Mhz
assert!(pll1_q_freq.is_some() && pll1_q_freq.unwrap().0 == 48_000_000);
RCC.ccipr2()
.modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::PLL1_Q));
None
}
UsbSrc::HSE => {
// Make sure the HSE is enabled and running at 48Mhz
assert!(hse_freq.is_some() && hse_freq.unwrap().0 == 48_000_000);
RCC.ccipr2()
.modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSE));
None
}
#[cfg(any(stm32g0b1, stm32g0c1))]
UsbSrc::Hsi48(config) => {
let freq = super::init_hsi48(config);
RCC.ccipr2()
.modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48));
Some(freq)
}
}
});
#[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))]
let hsi48_freq: Option<Hertz> = None;
#[cfg(crs)]
let hsi48 = config.hsi48.map(super::init_hsi48);
#[cfg(not(crs))]
let hsi48: Option<Hertz> = None;
config.mux.init();
set_clocks!(
sys: Some(sys_clk),
@ -357,7 +322,7 @@ pub(crate) unsafe fn init(config: Config) {
pclk1: Some(apb_freq),
pclk1_tim: Some(apb_tim_freq),
hsi: hsi_freq,
hsi48: hsi48_freq,
hsi48: hsi48,
hsi_div_8: hsi_div_8_freq,
hse: hse_freq,
lse: lse_freq,

View file

@ -1,11 +1,10 @@
use stm32_metapac::flash::vals::Latency;
use stm32_metapac::rcc::vals::{Adcsel, Sw};
use stm32_metapac::rcc::vals::Sw;
use stm32_metapac::FLASH;
pub use crate::pac::rcc::vals::{
Adcsel as AdcClockSource, Clk48sel as Clk48Src, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler,
Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc, Ppre as APBPrescaler,
Sw as Sysclk,
Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp as PllPDiv, Pllq as PllQDiv, Pllr as PllRDiv, Pllsrc,
Ppre as APBPrescaler, Sw as Sysclk,
};
use crate::pac::{PWR, RCC};
use crate::time::Hertz;
@ -82,24 +81,15 @@ pub struct Config {
pub low_power_run: bool,
/// Sets the clock source for the 48MHz clock used by the USB and RNG peripherals.
pub clk48_src: Clk48Src,
/// Low-Speed Clock Configuration
pub ls: super::LsConfig,
/// Clock Source for ADCs 1 and 2
pub adc12_clock_source: AdcClockSource,
/// Clock Source for ADCs 3, 4 and 5
pub adc345_clock_source: AdcClockSource,
/// Clock Source for FDCAN
pub fdcan_clock_source: FdCanClockSource,
/// Enable range1 boost mode
/// Recommended when the SYSCLK frequency is greater than 150MHz.
pub boost: bool,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
}
impl Default for Config {
@ -115,12 +105,9 @@ impl Default for Config {
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
low_power_run: false,
clk48_src: Clk48Src::HSI48,
ls: Default::default(),
adc12_clock_source: Adcsel::DISABLE,
adc345_clock_source: Adcsel::DISABLE,
fdcan_clock_source: FdCanClockSource::PCLK1,
boost: false,
mux: Default::default(),
}
}
}
@ -165,9 +152,7 @@ pub(crate) unsafe fn init(config: Config) {
};
// Configure HSI48 if required
if let Some(hsi48_config) = config.hsi48 {
super::init_hsi48(hsi48_config);
}
let hsi48 = config.hsi48.map(super::init_hsi48);
let pll_freq = config.pll.map(|pll_config| {
let src_freq = match pll_config.source {
@ -176,13 +161,13 @@ pub(crate) unsafe fn init(config: Config) {
_ => unreachable!(),
};
assert!(max::PLL_IN.contains(&src_freq));
// Disable PLL before configuration
RCC.cr().modify(|w| w.set_pllon(false));
while RCC.cr().read().pllrdy() {}
let internal_freq = src_freq / pll_config.prediv * pll_config.mul;
let in_freq = src_freq / pll_config.prediv;
assert!(max::PLL_IN.contains(&in_freq));
let internal_freq = in_freq * pll_config.mul;
assert!(max::PLL_VCO.contains(&internal_freq));
@ -301,42 +286,6 @@ pub(crate) unsafe fn init(config: Config) {
let (apb1_freq, apb1_tim_freq) = super::util::calc_pclk(hclk, config.apb1_pre);
let (apb2_freq, apb2_tim_freq) = super::util::calc_pclk(hclk, config.apb2_pre);
// Configure the 48MHz clock source for USB and RNG peripherals.
RCC.ccipr().modify(|w| {
w.set_clk48sel(match config.clk48_src {
Clk48Src::PLL1_Q => {
// Not checking that PLL1_Q is 48MHz here so as not to require the user to have a 48MHz clock.
// Peripherals which require one (USB, RNG) should check that theyre driven by a valid 48MHz
// clock at init.
crate::pac::rcc::vals::Clk48sel::PLL1_Q
}
Clk48Src::HSI48 => {
// Make sure HSI48 is enabled
assert!(config.hsi48.is_some());
crate::pac::rcc::vals::Clk48sel::HSI48
}
_ => unreachable!(),
})
});
RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
let adc12_ck = match config.adc12_clock_source {
AdcClockSource::DISABLE => None,
AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
AdcClockSource::SYS => Some(sys_clk),
_ => unreachable!(),
};
let adc345_ck = match config.adc345_clock_source {
AdcClockSource::DISABLE => None,
AdcClockSource::PLL1_P => pll_freq.as_ref().unwrap().pll_p,
AdcClockSource::SYS => Some(sys_clk),
_ => unreachable!(),
};
if config.low_power_run {
assert!(sys_clk <= Hertz(2_000_000));
PWR.cr1().modify(|w| w.set_lpr(true));
@ -344,6 +293,8 @@ pub(crate) unsafe fn init(config: Config) {
let rtc = config.ls.init();
config.mux.init();
set_clocks!(
sys: Some(sys_clk),
hclk1: Some(hclk),
@ -353,12 +304,11 @@ pub(crate) unsafe fn init(config: Config) {
pclk1_tim: Some(apb1_tim_freq),
pclk2: Some(apb2_freq),
pclk2_tim: Some(apb2_tim_freq),
adc: adc12_ck,
adc34: adc345_ck,
pll1_p: pll_freq.as_ref().and_then(|pll| pll.pll_p),
pll1_q: pll_freq.as_ref().and_then(|pll| pll.pll_q),
pll1_r: pll_freq.as_ref().and_then(|pll| pll.pll_r),
hse: hse,
hsi48: hsi48,
rtc: rtc,
);
}

View file

@ -2,15 +2,10 @@ use core::ops::RangeInclusive;
use crate::pac;
use crate::pac::pwr::vals::Vos;
#[cfg(stm32h5)]
pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
#[cfg(stm32h7)]
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
pub use crate::pac::rcc::vals::{
Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv,
Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
};
use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
use crate::pac::rcc::vals::{Pllrge, Pllvcosel, Timpre};
use crate::pac::{FLASH, PWR, RCC};
use crate::time::Hertz;
@ -194,16 +189,15 @@ pub struct Config {
#[cfg(stm32h7)]
pub apb4_pre: APBPrescaler,
pub per_clock_source: PerClockSource,
pub adc_clock_source: AdcClockSource,
pub fdcan_clock_source: FdCanClockSource,
pub timer_prescaler: TimerPrescaler,
pub voltage_scale: VoltageScale,
pub ls: super::LsConfig,
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
pub supply_config: SupplyConfig,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
}
impl Default for Config {
@ -227,21 +221,14 @@ impl Default for Config {
#[cfg(stm32h7)]
apb4_pre: APBPrescaler::DIV1,
per_clock_source: PerClockSource::HSI,
#[cfg(stm32h5)]
adc_clock_source: AdcClockSource::HCLK1,
#[cfg(stm32h7)]
adc_clock_source: AdcClockSource::PER,
fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
timer_prescaler: TimerPrescaler::DefaultX2,
voltage_scale: VoltageScale::Scale0,
ls: Default::default(),
#[cfg(any(pwr_h7rm0399, pwr_h7rm0455, pwr_h7rm0468))]
supply_config: SupplyConfig::Default,
mux: Default::default(),
}
}
}
@ -504,31 +491,6 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(stm32h7)]
assert!(apb4 <= pclk_max);
let _per_ck = match config.per_clock_source {
Ckpersel::HSI => hsi,
Ckpersel::CSI => csi,
Ckpersel::HSE => hse,
_ => unreachable!(),
};
#[cfg(stm32h7)]
let adc = match config.adc_clock_source {
AdcClockSource::PLL2_P => pll2.p,
AdcClockSource::PLL3_R => pll3.r,
AdcClockSource::PER => _per_ck,
_ => unreachable!(),
};
#[cfg(stm32h5)]
let adc = match config.adc_clock_source {
AdcClockSource::HCLK1 => Some(hclk),
AdcClockSource::SYS => Some(sys),
AdcClockSource::PLL2_R => pll2.r,
AdcClockSource::HSE => hse,
AdcClockSource::HSI => hsi,
AdcClockSource::CSI => csi,
_ => unreachable!(),
};
flash_setup(hclk, config.voltage_scale);
let rtc = config.ls.init();
@ -550,16 +512,6 @@ pub(crate) unsafe fn init(config: Config) {
RCC.d3cfgr().modify(|w| {
w.set_d3ppre(config.apb4_pre);
});
RCC.d1ccipr().modify(|w| {
w.set_ckpersel(config.per_clock_source);
});
RCC.d3ccipr().modify(|w| {
w.set_adcsel(config.adc_clock_source);
});
RCC.d2ccip1r().modify(|w| {
w.set_fdcansel(config.fdcan_clock_source);
});
}
#[cfg(stm32h5)]
{
@ -573,12 +525,6 @@ pub(crate) unsafe fn init(config: Config) {
w.set_ppre2(config.apb2_pre);
w.set_ppre3(config.apb3_pre);
});
RCC.ccipr5().modify(|w| {
w.set_ckpersel(config.per_clock_source);
w.set_adcdacsel(config.adc_clock_source);
w.set_fdcan12sel(config.fdcan_clock_source)
});
}
RCC.cfgr().modify(|w| w.set_timpre(config.timer_prescaler.into()));
@ -601,6 +547,8 @@ pub(crate) unsafe fn init(config: Config) {
while !pac::SYSCFG.cccsr().read().ready() {}
}
config.mux.init();
set_clocks!(
sys: Some(sys),
hclk1: Some(hclk),
@ -614,7 +562,6 @@ pub(crate) unsafe fn init(config: Config) {
pclk4: Some(apb4),
pclk1_tim: Some(apb1_tim),
pclk2_tim: Some(apb2_tim),
adc: adc,
rtc: rtc,
hsi: hsi,
@ -646,7 +593,6 @@ pub(crate) unsafe fn init(config: Config) {
#[cfg(stm32h5)]
audioclk: None,
per: None,
i2s_ckin: None,
);
}

View file

@ -1,10 +1,6 @@
#[cfg(any(stm32l0, stm32l1))]
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::regs::Cfgr;
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
pub use crate::pac::rcc::vals::Clk48sel as Clk48Src;
#[cfg(any(stm32wb, stm32wl))]
pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as Sysclk};
@ -59,18 +55,14 @@ pub struct Config {
#[cfg(any(stm32wl, stm32wb))]
pub shared_ahb_pre: AHBPrescaler,
// muxes
#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
pub clk48_src: Clk48Src,
// low speed LSI/LSE/RTC
pub ls: super::LsConfig,
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
pub adc_clock_source: AdcClockSource,
#[cfg(any(stm32l0, stm32l1))]
pub voltage_scale: VoltageScale,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
}
impl Default for Config {
@ -95,13 +87,10 @@ impl Default for Config {
pllsai2: None,
#[cfg(crs)]
hsi48: Some(Default::default()),
#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
clk48_src: Clk48Src::HSI48,
ls: Default::default(),
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
adc_clock_source: AdcClockSource::SYS,
#[cfg(any(stm32l0, stm32l1))]
voltage_scale: VoltageScale::RANGE1,
mux: Default::default(),
}
}
}
@ -118,7 +107,6 @@ pub const WPAN_DEFAULT: Config = Config {
hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
msi: None,
hsi: false,
clk48_src: Clk48Src::PLL1_Q,
ls: super::LsConfig::default_lse(),
@ -137,7 +125,8 @@ pub const WPAN_DEFAULT: Config = Config {
shared_ahb_pre: AHBPrescaler::DIV1,
apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1,
adc_clock_source: AdcClockSource::SYS,
mux: super::mux::ClockMux::default(),
};
fn msi_enable(range: MSIRange) {
@ -267,21 +256,6 @@ pub(crate) unsafe fn init(config: Config) {
Sysclk::PLL1_R => pll.r.unwrap(),
};
#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src));
#[cfg(any(rcc_l0_v2))]
let clk48 = match config.clk48_src {
Clk48Src::HSI48 => hsi48,
Clk48Src::PLL1_VCO_DIV_2 => pll.clk48,
};
#[cfg(any(stm32l4, stm32l5, stm32wb))]
let clk48 = match config.clk48_src {
Clk48Src::HSI48 => hsi48,
Clk48Src::MSI => msi,
Clk48Src::PLLSAI1_Q => pllsai1.q,
Clk48Src::PLL1_Q => pll.q,
};
#[cfg(rcc_l4plus)]
assert!(sys_clk.0 <= 120_000_000);
#[cfg(all(stm32l4, not(rcc_l4plus)))]
@ -357,9 +331,6 @@ pub(crate) unsafe fn init(config: Config) {
});
while RCC.cfgr().read().sws() != config.sys {}
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
RCC.ccipr().modify(|w| w.set_adcsel(config.adc_clock_source));
#[cfg(any(stm32wl, stm32wb))]
{
RCC.extcfgr().modify(|w| {
@ -372,6 +343,8 @@ pub(crate) unsafe fn init(config: Config) {
while !RCC.extcfgr().read().c2hpref() {}
}
config.mux.init();
set_clocks!(
sys: Some(sys_clk),
hclk1: Some(hclk1),
@ -388,10 +361,11 @@ pub(crate) unsafe fn init(config: Config) {
hsi: hsi,
hse: hse,
msi: msi,
#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
clk48: clk48,
hsi48: hsi48,
#[cfg(any(stm32l0, stm32l1))]
pll1_vco_div_2: pll.vco.map(|c| c/2u32),
#[cfg(not(any(stm32l0, stm32l1)))]
pll1_p: pll.p,
#[cfg(not(any(stm32l0, stm32l1)))]
@ -511,7 +485,7 @@ mod pll {
#[derive(Default)]
pub(super) struct PllOutput {
pub r: Option<Hertz>,
pub clk48: Option<Hertz>,
pub vco: Option<Hertz>,
}
pub(super) fn init_pll(instance: PllInstance, config: Option<Pll>, input: &PllInput) -> PllOutput {
@ -528,7 +502,6 @@ mod pll {
let vco_freq = pll_src * pll.mul;
let r = vco_freq / pll.div;
let clk48 = (vco_freq == Hertz(96_000_000)).then_some(Hertz(48_000_000));
assert!(r <= Hertz(32_000_000));
@ -541,7 +514,10 @@ mod pll {
// Enable PLL
pll_enable(instance, true);
PllOutput { r: Some(r), clk48 }
PllOutput {
r: Some(r),
vco: Some(vco_freq),
}
}
}

View file

@ -31,9 +31,7 @@ mod _version;
pub use _version::*;
#[cfg(clock_mux)]
pub use crate::_generated::mux;
pub use crate::_generated::Clocks;
pub use crate::_generated::{mux, Clocks};
#[cfg(feature = "low-power")]
/// Must be written within a critical section

View file

@ -85,6 +85,9 @@ pub struct Config {
/// See RM0456 § 10.5.4 for a general overview and § 11.4.10 for clock source frequency limits.
pub voltage_range: VoltageScale,
pub ls: super::LsConfig,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
}
impl Default for Config {
@ -104,6 +107,7 @@ impl Default for Config {
apb3_pre: APBPrescaler::DIV1,
voltage_range: VoltageScale::RANGE1,
ls: Default::default(),
mux: Default::default(),
}
}
}
@ -259,6 +263,8 @@ pub(crate) unsafe fn init(config: Config) {
let rtc = config.ls.init();
config.mux.init();
set_clocks!(
sys: Some(sys_clk),
hclk1: Some(hclk),
@ -289,7 +295,6 @@ pub(crate) unsafe fn init(config: Config) {
lse: None,
lsi: None,
msik: None,
iclk: None,
shsi: None,
shsi_div_2: None,
);

View file

@ -1,8 +1,6 @@
pub use crate::pac::pwr::vals::Vos as VoltageScale;
use crate::pac::rcc::regs::Cfgr1;
pub use crate::pac::rcc::vals::{
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk,
};
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as Sysclk};
use crate::pac::{FLASH, RCC};
use crate::time::Hertz;
@ -32,9 +30,10 @@ pub struct Config {
// low speed LSI/LSE/RTC
pub ls: super::LsConfig,
pub adc_clock_source: AdcClockSource,
pub voltage_scale: VoltageScale,
/// Per-peripheral kernel clock selection muxes
pub mux: super::mux::ClockMux,
}
impl Default for Config {
@ -49,8 +48,8 @@ impl Default for Config {
apb2_pre: APBPrescaler::DIV1,
apb7_pre: APBPrescaler::DIV1,
ls: Default::default(),
adc_clock_source: AdcClockSource::HCLK4,
voltage_scale: VoltageScale::RANGE2,
mux: Default::default(),
}
}
}
@ -152,7 +151,7 @@ pub(crate) unsafe fn init(config: Config) {
w.set_ppre2(config.apb2_pre);
});
RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source));
config.mux.init();
set_clocks!(
sys: Some(sys_clk),

View file

@ -606,13 +606,6 @@ impl<'d, T: Instance> Bus<'d, T> {
// Wait for USB power to stabilize
while !crate::pac::PWR.cr3().read().usb33rdy() {}
// Use internal 48MHz HSI clock. Should be enabled in RCC by default.
critical_section::with(|_| {
crate::pac::RCC
.d2ccip2r()
.modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
});
// Enable ULPI clock if external PHY is used
let ulpien = !self.phy_type.internal();
critical_section::with(|_| {
@ -645,13 +638,6 @@ impl<'d, T: Instance> Bus<'d, T> {
// Wait for USB power to stabilize
while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
// Select HSI48 as USB clock source.
critical_section::with(|_| {
crate::pac::RCC.ccipr1().modify(|w| {
w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
})
});
}
<T as RccPeripheral>::enable_and_reset();

View file

@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
config.rcc.apb1_pre = APBPrescaler::DIV2;
config.rcc.apb2_pre = APBPrescaler::DIV1;
config.rcc.mux.hrtim1sw = Some(embassy_stm32::rcc::mux::Timsw::PLL1_P);
config.rcc.mux.hrtim1sw = embassy_stm32::rcc::mux::Timsw::PLL1_P;
}
let p = embassy_stm32::init(config);

View file

@ -4,37 +4,35 @@
use defmt::info;
use embassy_executor::Spawner;
use embassy_stm32::gpio::OutputType;
use embassy_stm32::pac::rcc::vals::Tim1sel;
use embassy_stm32::rcc::{Config as RccConfig, PllConfig, PllSource, Pllm, Plln, Pllq, Pllr, Sysclk};
use embassy_stm32::time::khz;
use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin};
use embassy_stm32::timer::simple_pwm::PwmPin;
use embassy_stm32::timer::Channel;
use embassy_stm32::{pac, Config as PeripheralConfig};
use embassy_stm32::Config as PeripheralConfig;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut rcc_config = RccConfig::default();
rcc_config.sys = Sysclk::PLL(PllConfig {
source: PllSource::HSI,
m: Pllm::DIV1,
n: Plln::MUL16,
r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz)
q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz)
p: None,
});
let mut config = PeripheralConfig::default();
{
use embassy_stm32::rcc::*;
let mut peripheral_config = PeripheralConfig::default();
peripheral_config.rcc = rcc_config;
config.rcc.sys = Sysclk::PLL(PllConfig {
source: PllSource::HSI,
m: Pllm::DIV1,
n: Plln::MUL16,
r: Pllr::DIV4, // CPU clock comes from PLLR (HSI (16MHz) / 1 * 16 / 4 = 64MHz)
q: Some(Pllq::DIV2), // TIM1 or TIM15 can be sourced from PLLQ (HSI (16MHz) / 1 * 16 / 2 = 128MHz)
p: None,
});
let p = embassy_stm32::init(peripheral_config);
// configure TIM1 mux to select PLLQ as clock source
// https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
// RM0444 page 210
// RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
pac::RCC.ccipr().modify(|w| w.set_tim1sel(Tim1sel::PLL1_Q));
// configure TIM1 mux to select PLLQ as clock source
// https://www.st.com/resource/en/reference_manual/rm0444-stm32g0x1-advanced-armbased-32bit-mcus-stmicroelectronics.pdf
// RM0444 page 210
// RCC - Peripherals Independent Clock Control Register - bit 22 -> 1
config.rcc.mux.tim1sel = embassy_stm32::rcc::mux::Tim1sel::PLL1_Q;
}
let p = embassy_stm32::init(config);
let ch1 = PwmPin::new_ch1(p.PA8, OutputType::PushPull);
let ch1n = ComplementaryPwmPin::new_ch1(p.PA7, OutputType::PushPull);

View file

@ -4,7 +4,6 @@
use defmt::{panic, *};
use embassy_executor::Spawner;
use embassy_futures::join::join;
use embassy_stm32::rcc::{Hsi48Config, UsbSrc};
use embassy_stm32::usb::{Driver, Instance};
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
@ -19,10 +18,11 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.rcc.usb_src = Some(UsbSrc::Hsi48(Hsi48Config {
sync_from_usb: true,
..Default::default()
}));
{
use embassy_stm32::rcc::*;
config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
config.rcc.mux.usbsel = mux::Usbsel::HSI48;
}
let p = embassy_stm32::init(config);
info!("Hello World!");

View file

@ -4,7 +4,6 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, SampleTime};
use embassy_stm32::rcc::{AdcClockSource, Pll, PllMul, PllPreDiv, PllRDiv, Pllsrc, Sysclk};
use embassy_stm32::Config;
use embassy_time::{Delay, Timer};
use {defmt_rtt as _, panic_probe as _};
@ -12,20 +11,20 @@ use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.rcc.pll = Some(Pll {
source: Pllsrc::HSI,
prediv: PllPreDiv::DIV4,
mul: PllMul::MUL85,
divp: None,
divq: None,
// Main system clock at 170 MHz
divr: Some(PllRDiv::DIV2),
});
config.rcc.adc12_clock_source = AdcClockSource::SYS;
config.rcc.sys = Sysclk::PLL1_R;
{
use embassy_stm32::rcc::*;
config.rcc.pll = Some(Pll {
source: Pllsrc::HSI,
prediv: PllPreDiv::DIV4,
mul: PllMul::MUL85,
divp: None,
divq: None,
// Main system clock at 170 MHz
divr: Some(PllRDiv::DIV2),
});
config.rcc.mux.adc12sel = mux::Adcsel::SYS;
config.rcc.sys = Sysclk::PLL1_R;
}
let mut p = embassy_stm32::init(config);
info!("Hello World!");

View file

@ -3,6 +3,7 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::peripherals::*;
use embassy_stm32::time::Hertz;
use embassy_stm32::{bind_interrupts, can, Config};
use embassy_time::Timer;
use static_cell::StaticCell;
@ -15,8 +16,24 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let config = Config::default();
let mut config = Config::default();
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(24_000_000),
mode: HseMode::Oscillator,
});
config.rcc.pll = Some(Pll {
source: Pllsrc::HSE,
prediv: PllPreDiv::DIV6,
mul: PllMul::MUL85,
divp: None,
divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
});
config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
config.rcc.sys = Sysclk::PLL1_R;
}
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);

View file

@ -12,6 +12,7 @@ use {defmt_rtt as _, panic_probe as _};
async fn main(_spawner: Spawner) {
let mut config = Config::default();
config.rcc.hsi = true;
config.rcc.pll = Some(Pll {
source: Pllsrc::HSI,
prediv: PllPreDiv::DIV4,

View file

@ -3,9 +3,6 @@
use defmt::{panic, *};
use embassy_executor::Spawner;
use embassy_stm32::rcc::{
Clk48Src, Hse, HseMode, Hsi48Config, Pll, PllMul, PllPreDiv, PllQDiv, PllRDiv, Pllsrc, Sysclk,
};
use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{self, Driver, Instance};
use embassy_stm32::{bind_interrupts, peripherals, Config};
@ -22,38 +19,27 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let mut config = Config::default();
// Change this to `false` to use the HSE clock source for the USB. This example assumes an 8MHz HSE.
const USE_HSI48: bool = true;
let plldivq = if USE_HSI48 { None } else { Some(PllQDiv::DIV6) };
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Oscillator,
});
config.rcc.pll = Some(Pll {
source: Pllsrc::HSE,
prediv: PllPreDiv::DIV2,
mul: PllMul::MUL72,
divp: None,
divq: plldivq,
// Main system clock at 144 MHz
divr: Some(PllRDiv::DIV2),
});
config.rcc.sys = Sysclk::PLL1_R;
config.rcc.boost = true; // BOOST!
if USE_HSI48 {
{
use embassy_stm32::rcc::*;
// Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true });
config.rcc.clk48_src = Clk48Src::HSI48;
} else {
config.rcc.clk48_src = Clk48Src::PLL1_Q;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Oscillator,
});
config.rcc.pll = Some(Pll {
source: Pllsrc::HSE,
prediv: PllPreDiv::DIV2,
mul: PllMul::MUL72,
divp: None,
divq: Some(PllQDiv::DIV6), // 48mhz
divr: Some(PllRDiv::DIV2), // Main system clock at 144 MHz
});
config.rcc.sys = Sysclk::PLL1_R;
config.rcc.boost = true; // BOOST!
config.rcc.mux.clk48sel = mux::Clk48sel::HSI48;
//config.rcc.mux.clk48sel = mux::Clk48sel::PLL1_Q; // uncomment to use PLL1_Q instead.
}
let p = embassy_stm32::init(config);
info!("Hello World!");

View file

@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
config.rcc.mux.fdcan12sel = rcc::mux::Fdcansel::HSE;
let peripherals = embassy_stm32::init(config);

View file

@ -5,7 +5,7 @@ use defmt::{panic, *};
use embassy_executor::Spawner;
use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{Driver, Instance};
use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
use embassy_stm32::{bind_interrupts, peripherals, usb, Config};
use embassy_usb::class::cdc_acm::{CdcAcmClass, State};
use embassy_usb::driver::EndpointError;
use embassy_usb::Builder;
@ -41,15 +41,12 @@ async fn main(_spawner: Spawner) {
config.rcc.apb3_pre = APBPrescaler::DIV4;
config.rcc.sys = Sysclk::PLL1_P;
config.rcc.voltage_scale = VoltageScale::Scale0;
config.rcc.mux.usbsel = mux::Usbsel::HSI48;
}
let p = embassy_stm32::init(config);
info!("Hello World!");
pac::RCC.ccipr4().write(|w| {
w.set_usbsel(pac::rcc::vals::Usbsel::HSI48);
});
// Create the driver, from the HAL.
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);

View file

@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.voltage_scale = VoltageScale::Scale1;
config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
}
let mut p = embassy_stm32::init(config);

View file

@ -20,7 +20,7 @@ async fn main(_spawner: Spawner) {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
config.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
let peripherals = embassy_stm32::init(config);

View file

@ -40,7 +40,7 @@ fn main() -> ! {
config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.voltage_scale = VoltageScale::Scale1;
config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
}
let p = embassy_stm32::init(config);

View file

@ -42,7 +42,7 @@ async fn main(spawner: Spawner) {
config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.voltage_scale = VoltageScale::Scale1;
config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
}
// Initialize the board and obtain a Peripherals instance

View file

@ -3,7 +3,7 @@
use defmt::*;
use embassy_stm32::adc::{Adc, Resolution};
use embassy_stm32::pac;
use embassy_stm32::Config;
use embassy_time::Delay;
use {defmt_rtt as _, panic_probe as _};
@ -11,12 +11,12 @@ use {defmt_rtt as _, panic_probe as _};
fn main() -> ! {
info!("Hello World!");
pac::RCC.ccipr().modify(|w| {
w.set_adcsel(pac::rcc::vals::Adcsel::SYS);
});
pac::RCC.ahb2enr().modify(|w| w.set_adcen(true));
let p = embassy_stm32::init(Default::default());
let mut config = Config::default();
{
use embassy_stm32::rcc::*;
config.rcc.mux.adcsel = mux::Adcsel::SYS;
}
let p = embassy_stm32::init(config);
let mut adc = Adc::new(p.ADC1, &mut Delay);
//adc.enable_vref();

View file

@ -33,7 +33,7 @@ fn options() -> TestOptions {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(1200),
@ -50,7 +50,7 @@ fn options() -> TestOptions {
freq: embassy_stm32::time::Hertz(25_000_000),
mode: rcc::HseMode::Oscillator,
});
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(1200),

View file

@ -2,6 +2,8 @@
pub use defmt::*;
#[allow(unused)]
use embassy_stm32::rcc::*;
#[allow(unused)]
use embassy_stm32::time::Hertz;
use embassy_stm32::Config;
use {defmt_rtt as _, panic_probe as _};
@ -265,7 +267,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32f091rc")]
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Bypass,
@ -281,7 +282,6 @@ pub fn config() -> Config {
}
#[cfg(feature = "stm32f103c8")]
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Oscillator,
@ -298,7 +298,6 @@ pub fn config() -> Config {
}
#[cfg(feature = "stm32f207zg")]
{
use embassy_stm32::rcc::*;
// By default, HSE on the board comes from a 8 MHz clock signal (not a crystal)
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
@ -327,7 +326,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32f303ze")]
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Bypass,
@ -345,7 +343,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32f429zi")]
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Bypass,
@ -366,7 +363,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32f446re")]
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Oscillator,
@ -387,7 +383,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32f767zi")]
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Bypass,
@ -408,7 +403,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32h563zi")]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = None;
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.hse = Some(Hse {
@ -433,7 +427,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32h503rb")]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = None;
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.hse = Some(Hse {
@ -456,9 +449,26 @@ pub fn config() -> Config {
config.rcc.voltage_scale = VoltageScale::Scale0;
}
#[cfg(feature = "stm32g491re")]
{
config.rcc.hse = Some(Hse {
freq: Hertz(24_000_000),
mode: HseMode::Oscillator,
});
config.rcc.pll = Some(Pll {
source: Pllsrc::HSE,
prediv: PllPreDiv::DIV6,
mul: PllMul::MUL85,
divp: None,
divq: Some(PllQDiv::DIV8), // 42.5 Mhz for fdcan.
divr: Some(PllRDiv::DIV2), // Main system clock at 170 MHz
});
config.rcc.mux.fdcansel = mux::Fdcansel::PLL1_Q;
config.rcc.sys = Sysclk::PLL1_R;
}
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@ -485,7 +495,7 @@ pub fn config() -> Config {
config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
config.rcc.voltage_scale = VoltageScale::Scale1;
config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
#[cfg(any(feature = "stm32h755zi"))]
{
config.rcc.supply_config = SupplyConfig::DirectSMPS;
@ -494,7 +504,6 @@ pub fn config() -> Config {
#[cfg(any(feature = "stm32h7a3zi"))]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true;
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
@ -521,12 +530,11 @@ pub fn config() -> Config {
config.rcc.apb3_pre = APBPrescaler::DIV2; // 140 Mhz
config.rcc.apb4_pre = APBPrescaler::DIV2; // 140 Mhz
config.rcc.voltage_scale = VoltageScale::Scale0;
config.rcc.adc_clock_source = AdcClockSource::PLL2_P;
config.rcc.mux.adcsel = mux::Adcsel::PLL2_P;
}
#[cfg(any(feature = "stm32l496zg", feature = "stm32l4a6zg", feature = "stm32l4r5zi"))]
{
use embassy_stm32::rcc::*;
config.rcc.sys = Sysclk::PLL1_R;
config.rcc.hsi = true;
config.rcc.pll = Some(Pll {
@ -541,7 +549,6 @@ pub fn config() -> Config {
#[cfg(feature = "stm32wl55jc")]
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(32_000_000),
mode: HseMode::Bypass,
@ -560,7 +567,6 @@ pub fn config() -> Config {
#[cfg(any(feature = "stm32l552ze"))]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = true;
config.rcc.sys = Sysclk::PLL1_R;
config.rcc.pll = Some(Pll {
@ -576,7 +582,6 @@ pub fn config() -> Config {
#[cfg(any(feature = "stm32u585ai", feature = "stm32u5a5zj"))]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = true;
config.rcc.pll1 = Some(Pll {
source: PllSource::HSI, // 16 MHz
@ -593,17 +598,12 @@ pub fn config() -> Config {
#[cfg(feature = "stm32wba52cg")]
{
use embassy_stm32::rcc::*;
config.rcc.sys = Sysclk::HSI;
embassy_stm32::pac::RCC.ccipr2().write(|w| {
w.set_rngsel(embassy_stm32::pac::rcc::vals::Rngsel::HSI);
});
config.rcc.mux.rngsel = mux::Rngsel::HSI;
}
#[cfg(feature = "stm32l073rz")]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = true;
config.rcc.pll = Some(Pll {
source: PllSource::HSI,
@ -615,7 +615,6 @@ pub fn config() -> Config {
#[cfg(any(feature = "stm32l152re"))]
{
use embassy_stm32::rcc::*;
config.rcc.hsi = true;
config.rcc.pll = Some(Pll {
source: PllSource::HSI,