From 0a9022d59f412f8ecade98da273126d834006841 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 10 Jun 2021 09:31:41 +0200 Subject: [PATCH 1/3] Enable timer clock in RCC on timer start * Moves the tim2-specific code into macro which always uses TIM2 * For peripherals without clock specified, attempt to locate enable and reset registers in the RCC block matching the peripheral name. This could be useful for peripherals where deducing the clock name might not be feasible, but it remains to be tested with more chip families to see if it is sufficiently accurate. --- embassy-macros/src/chip/stm32.rs | 5 ++- embassy-stm32/src/clock.rs | 24 +++---------- stm32-metapac/gen/src/lib.rs | 60 +++++++++++++++++++------------- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/embassy-macros/src/chip/stm32.rs b/embassy-macros/src/chip/stm32.rs index 274560a0..0a3a5abb 100644 --- a/embassy-macros/src/chip/stm32.rs +++ b/embassy-macros/src/chip/stm32.rs @@ -16,7 +16,10 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream interrupt::take!(TIM2), ); let clock = unsafe { make_static(&mut c) }; - clock.start_tim2(); + + // TODO: Is TIM2 always APB1? + let timer_freq = unsafe { #embassy_stm32_path::rcc::get_freqs().apb1_clk }; + clock.start(timer_freq); let mut alarm = clock.alarm1(); unsafe { #embassy_path::time::set_clock(clock) }; diff --git a/embassy-stm32/src/clock.rs b/embassy-stm32/src/clock.rs index 7f478e79..39a96402 100644 --- a/embassy-stm32/src/clock.rs +++ b/embassy-stm32/src/clock.rs @@ -11,6 +11,7 @@ use embassy::time::{Clock as EmbassyClock, TICKS_PER_SECOND}; use crate::interrupt::{CriticalSection, Interrupt, Mutex}; use crate::pac::timer::TimGp16; use crate::peripherals; +use crate::rcc::RccPeripheral; use crate::time::Hertz; // Clock timekeeping works with something we call "periods", which are time intervals @@ -76,27 +77,12 @@ impl Clock { } } - // TODO: Temporary until clock code generation is in place - pub fn start_tim2(&'static self) { - cfg_if::cfg_if! { - if #[cfg(rcc_l0)] { - unsafe { - let rcc = crate::pac::RCC; - rcc.apb1enr() - .modify(|w| w.set_tim2en(true)); - rcc.apb1rstr().modify(|w| w.set_tim2rst(true)); - rcc.apb1rstr().modify(|w| w.set_tim2rst(false)); - } - - let timer_freq = unsafe { crate::rcc::get_freqs().apb1_clk }; - self.start(timer_freq); - } - } - } - pub fn start(&'static self, timer_freq: Hertz) { let inner = T::inner(); + T::enable(); + T::reset(); + // NOTE(unsafe) Critical section to use the unsafe methods critical_section::with(|_| { unsafe { @@ -359,7 +345,7 @@ pub(crate) mod sealed { } } -pub trait Instance: sealed::Instance + Sized + 'static {} +pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {} macro_rules! impl_timer { ($inst:ident) => { diff --git a/stm32-metapac/gen/src/lib.rs b/stm32-metapac/gen/src/lib.rs index c4090cca..6db950be 100644 --- a/stm32-metapac/gen/src/lib.rs +++ b/stm32-metapac/gen/src/lib.rs @@ -267,32 +267,42 @@ pub fn gen(options: Options) { _ => {} } - if let Some(clock) = &p.clock { - if let Some(rcc) = &rcc { - // Workaround for clock registers being split on some chip families. Assume fields are - // named after peripheral and look for first field matching and use that register. - let en = find_reg_for_field(&rcc, clock, &format!("{}EN", name)); - let rst = find_reg_for_field(&rcc, clock, &format!("{}RST", name)); + if let Some(rcc) = &rcc { + // Workaround for clock registers being split on some chip families. Assume fields are + // named after peripheral and look for first field matching and use that register. + // + // Not all peripherals have the clock hint due to insufficient information from + // chip definition. If clock is not specified, the first matching register with the + // expected field will be used. + let en = find_reg_for_field( + &rcc, + p.clock.as_ref().unwrap_or(&String::new()), + &format!("{}EN", name), + ); + let rst = find_reg_for_field( + &rcc, + p.clock.as_ref().unwrap_or(&String::new()), + &format!("{}RST", name), + ); - match (en, rst) { - (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { - peripheral_rcc_table.push(vec![ - name.clone(), - enable_reg.to_ascii_lowercase(), - reset_reg.to_ascii_lowercase(), - format!("set_{}", enable_field.to_ascii_lowercase()), - format!("set_{}", reset_field.to_ascii_lowercase()), - ]); - } - (None, Some(_)) => { - println!("Unable to find enable register for {}", name) - } - (Some(_), None) => { - println!("Unable to find reset register for {}", name) - } - (None, None) => { - println!("Unable to find enable and reset register for {}", name) - } + match (en, rst) { + (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { + peripheral_rcc_table.push(vec![ + name.clone(), + enable_reg.to_ascii_lowercase(), + reset_reg.to_ascii_lowercase(), + format!("set_{}", enable_field.to_ascii_lowercase()), + format!("set_{}", reset_field.to_ascii_lowercase()), + ]); + } + (None, Some(_)) => { + println!("Unable to find enable register for {}", name) + } + (Some(_), None) => { + println!("Unable to find reset register for {}", name) + } + (None, None) => { + println!("Unable to find enable and reset register for {}", name) } } } From 8dd3ddd228076b49948189f6b95b64dcf131631e Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Thu, 10 Jun 2021 09:52:57 +0200 Subject: [PATCH 2/3] Special handling for timers instead --- stm32-metapac/gen/src/lib.rs | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/stm32-metapac/gen/src/lib.rs b/stm32-metapac/gen/src/lib.rs index 6db950be..ea06e308 100644 --- a/stm32-metapac/gen/src/lib.rs +++ b/stm32-metapac/gen/src/lib.rs @@ -268,42 +268,42 @@ pub fn gen(options: Options) { } if let Some(rcc) = &rcc { - // Workaround for clock registers being split on some chip families. Assume fields are - // named after peripheral and look for first field matching and use that register. - // - // Not all peripherals have the clock hint due to insufficient information from - // chip definition. If clock is not specified, the first matching register with the - // expected field will be used. - let en = find_reg_for_field( - &rcc, - p.clock.as_ref().unwrap_or(&String::new()), - &format!("{}EN", name), - ); - let rst = find_reg_for_field( - &rcc, - p.clock.as_ref().unwrap_or(&String::new()), - &format!("{}RST", name), - ); + let mut generate_rcc_peripheral = |clock_prefix| { + // Workaround for clock registers being split on some chip families. Assume fields are + // named after peripheral and look for first field matching and use that register. - match (en, rst) { - (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { - peripheral_rcc_table.push(vec![ - name.clone(), - enable_reg.to_ascii_lowercase(), - reset_reg.to_ascii_lowercase(), - format!("set_{}", enable_field.to_ascii_lowercase()), - format!("set_{}", reset_field.to_ascii_lowercase()), - ]); - } - (None, Some(_)) => { - println!("Unable to find enable register for {}", name) - } - (Some(_), None) => { - println!("Unable to find reset register for {}", name) - } - (None, None) => { - println!("Unable to find enable and reset register for {}", name) + let en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); + let rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); + + match (en, rst) { + (Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => { + peripheral_rcc_table.push(vec![ + name.clone(), + enable_reg.to_ascii_lowercase(), + reset_reg.to_ascii_lowercase(), + format!("set_{}", enable_field.to_ascii_lowercase()), + format!("set_{}", reset_field.to_ascii_lowercase()), + ]); + } + (None, Some(_)) => { + println!("Unable to find enable register for {}", name) + } + (Some(_), None) => { + println!("Unable to find reset register for {}", name) + } + (None, None) => { + println!("Unable to find enable and reset register for {}", name) + } } + }; + + if let Some(clock) = &p.clock { + generate_rcc_peripheral(clock); + } else if name.starts_with("TIM") { + // Not all peripherals like timers the clock hint due to insufficient information from + // chip definition. If clock is not specified, the first matching register with the + // expected field will be used. + generate_rcc_peripheral(""); } } } From 6c7fd3e3c4f54cc8b882086d3973180dd84c95c2 Mon Sep 17 00:00:00 2001 From: Ulf Lilleengen Date: Fri, 11 Jun 2021 16:21:51 +0200 Subject: [PATCH 3/3] Refactor --- stm32-metapac/gen/src/lib.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/stm32-metapac/gen/src/lib.rs b/stm32-metapac/gen/src/lib.rs index ea06e308..399840c5 100644 --- a/stm32-metapac/gen/src/lib.rs +++ b/stm32-metapac/gen/src/lib.rs @@ -268,10 +268,20 @@ pub fn gen(options: Options) { } if let Some(rcc) = &rcc { - let mut generate_rcc_peripheral = |clock_prefix| { + let clock_prefix: Option<&str> = if let Some(clock) = &p.clock { + Some(clock) + } else if name.starts_with("TIM") { + // Not all peripherals like timers the clock hint due to insufficient information from + // chip definition. If clock is not specified, the first matching register with the + // expected field will be used. + Some("") + } else { + None + }; + + if let Some(clock_prefix) = clock_prefix { // Workaround for clock registers being split on some chip families. Assume fields are // named after peripheral and look for first field matching and use that register. - let en = find_reg_for_field(&rcc, clock_prefix, &format!("{}EN", name)); let rst = find_reg_for_field(&rcc, clock_prefix, &format!("{}RST", name)); @@ -295,15 +305,6 @@ pub fn gen(options: Options) { println!("Unable to find enable and reset register for {}", name) } } - }; - - if let Some(clock) = &p.clock { - generate_rcc_peripheral(clock); - } else if name.starts_with("TIM") { - // Not all peripherals like timers the clock hint due to insufficient information from - // chip definition. If clock is not specified, the first matching register with the - // expected field will be used. - generate_rcc_peripheral(""); } } }