Provide a way for a peripheral to query its clock frequency

Currently this looks up the frequency in the global singleton that must
be initialized by the per-chip RCC implementation. At present, this is
only done for the L0 family of chips.
This commit is contained in:
Ulf Lilleengen 2021-06-11 09:19:02 +02:00
parent 85f172dd93
commit 952f525af5
6 changed files with 44 additions and 28 deletions

View File

@ -17,9 +17,7 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream
); );
let clock = unsafe { make_static(&mut c) }; let clock = unsafe { make_static(&mut c) };
// TODO: Is TIM2 always APB1? clock.start();
let timer_freq = unsafe { #embassy_stm32_path::rcc::get_freqs().apb1_clk };
clock.start(timer_freq);
let mut alarm = clock.alarm1(); let mut alarm = clock.alarm1();
unsafe { #embassy_path::time::set_clock(clock) }; unsafe { #embassy_path::time::set_clock(clock) };

View File

@ -77,12 +77,14 @@ impl<T: Instance> Clock<T> {
} }
} }
pub fn start(&'static self, timer_freq: Hertz) { pub fn start(&'static self) {
let inner = T::inner(); let inner = T::inner();
T::enable(); T::enable();
T::reset(); T::reset();
let timer_freq = T::frequency();
// NOTE(unsafe) Critical section to use the unsafe methods // NOTE(unsafe) Critical section to use the unsafe methods
critical_section::with(|_| { critical_section::with(|_| {
unsafe { unsafe {

View File

@ -469,35 +469,31 @@ impl RccExt for RCC {
} }
}; };
let (apb1_freq, apb1_tim_freq, apb1_pre) = match cfgr.apb1_pre { let apb1_freq = match cfgr.apb1_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), APBPrescaler::NotDivided => ahb_freq,
pre => { pre => {
let pre: Ppre = pre.into(); let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3); let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / pre as u32; let freq = ahb_freq / pre as u32;
(freq, freq * 2, pre as u8) freq
} }
}; };
let (apb2_freq, apb2_tim_freq, apb2_pre) = match cfgr.apb2_pre { let apb2_freq = match cfgr.apb2_pre {
APBPrescaler::NotDivided => (ahb_freq, ahb_freq, 1), APBPrescaler::NotDivided => ahb_freq,
pre => { pre => {
let pre: Ppre = pre.into(); let pre: Ppre = pre.into();
let pre: u8 = 1 << (pre.0 - 3); let pre: u8 = 1 << (pre.0 - 3);
let freq = ahb_freq / (1 << (pre as u8 - 3)); let freq = ahb_freq / (1 << (pre as u8 - 3));
(freq, freq * 2, pre as u8) freq
} }
}; };
Clocks { Clocks {
sys_clk: sys_clk.hz(), sys: sys_clk.hz(),
ahb_clk: ahb_freq.hz(), ahb: ahb_freq.hz(),
apb1_clk: apb1_freq.hz(), apb1: apb1_freq.hz(),
apb2_clk: apb2_freq.hz(), apb2: apb2_freq.hz(),
apb1_tim_clk: apb1_tim_freq.hz(),
apb2_tim_clk: apb2_tim_freq.hz(),
apb1_pre,
apb2_pre,
} }
} }
} }

View File

@ -9,14 +9,10 @@ use core::mem::MaybeUninit;
/// The existence of this value indicates that the clock configuration can no longer be changed /// The existence of this value indicates that the clock configuration can no longer be changed
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct Clocks { pub struct Clocks {
pub sys_clk: Hertz, pub sys: Hertz,
pub ahb_clk: Hertz, pub ahb: Hertz,
pub apb1_clk: Hertz, pub apb1: Hertz,
pub apb1_tim_clk: Hertz, pub apb2: Hertz,
pub apb2_clk: Hertz,
pub apb2_tim_clk: Hertz,
pub apb1_pre: u8,
pub apb2_pre: u8,
} }
static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit(); static mut CLOCK_FREQS: MaybeUninit<Clocks> = MaybeUninit::uninit();
@ -50,6 +46,7 @@ cfg_if::cfg_if! {
pub(crate) mod sealed { pub(crate) mod sealed {
pub trait RccPeripheral { pub trait RccPeripheral {
fn frequency() -> crate::time::Hertz;
fn reset(); fn reset();
fn enable(); fn enable();
fn disable(); fn disable();
@ -59,8 +56,16 @@ pub(crate) mod sealed {
pub trait RccPeripheral: sealed::RccPeripheral + 'static {} pub trait RccPeripheral: sealed::RccPeripheral + 'static {}
crate::pac::peripheral_rcc!( crate::pac::peripheral_rcc!(
($inst:ident, $enable:ident, $reset:ident, $perien:ident, $perirst:ident) => { ($inst:ident, $clk:ident, $enable:ident, $reset:ident, $perien:ident, $perirst:ident) => {
impl sealed::RccPeripheral for peripherals::$inst { impl sealed::RccPeripheral for peripherals::$inst {
fn frequency() -> crate::time::Hertz {
critical_section::with(|_| {
unsafe {
let freqs = get_freqs();
freqs.$clk
}
})
}
fn enable() { fn enable() {
critical_section::with(|_| { critical_section::with(|_| {
unsafe { unsafe {

View File

@ -37,7 +37,6 @@ pub struct Spi<'d, T: Instance> {
impl<'d, T: Instance> Spi<'d, T> { impl<'d, T: Instance> Spi<'d, T> {
pub fn new<F>( pub fn new<F>(
pclk: Hertz,
_peri: impl Unborrow<Target = T> + 'd, _peri: impl Unborrow<Target = T> + 'd,
sck: impl Unborrow<Target = impl SckPin<T>>, sck: impl Unborrow<Target = impl SckPin<T>>,
mosi: impl Unborrow<Target = impl MosiPin<T>>, mosi: impl Unborrow<Target = impl MosiPin<T>>,
@ -60,6 +59,7 @@ impl<'d, T: Instance> Spi<'d, T> {
let mosi = mosi.degrade(); let mosi = mosi.degrade();
let miso = miso.degrade(); let miso = miso.degrade();
let pclk = T::frequency();
let br = Self::compute_baud_rate(pclk, freq.into()); let br = Self::compute_baud_rate(pclk, freq.into());
unsafe { unsafe {

View File

@ -287,8 +287,23 @@ pub fn gen(options: Options) {
match (en, rst) { match (en, rst) {
(Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => {
let clock = if clock_prefix == "" {
let re = Regex::new("([A-Z]+\\d*).*").unwrap();
if !re.is_match(enable_reg) {
panic!(
"unable to derive clock name from register name {}",
enable_reg
);
} else {
let caps = re.captures(enable_reg).unwrap();
caps.get(1).unwrap().as_str()
}
} else {
clock_prefix
};
peripheral_rcc_table.push(vec![ peripheral_rcc_table.push(vec![
name.clone(), name.clone(),
clock.to_ascii_lowercase(),
enable_reg.to_ascii_lowercase(), enable_reg.to_ascii_lowercase(),
reset_reg.to_ascii_lowercase(), reset_reg.to_ascii_lowercase(),
format!("set_{}", enable_field.to_ascii_lowercase()), format!("set_{}", enable_field.to_ascii_lowercase()),