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.
This commit is contained in:
parent
37fbc5fcc4
commit
0a9022d59f
@ -16,7 +16,10 @@ pub fn generate(embassy_prefix: &ModulePrefix, config: syn::Expr) -> TokenStream
|
|||||||
interrupt::take!(TIM2),
|
interrupt::take!(TIM2),
|
||||||
);
|
);
|
||||||
let clock = unsafe { make_static(&mut c) };
|
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();
|
let mut alarm = clock.alarm1();
|
||||||
unsafe { #embassy_path::time::set_clock(clock) };
|
unsafe { #embassy_path::time::set_clock(clock) };
|
||||||
|
@ -11,6 +11,7 @@ use embassy::time::{Clock as EmbassyClock, TICKS_PER_SECOND};
|
|||||||
use crate::interrupt::{CriticalSection, Interrupt, Mutex};
|
use crate::interrupt::{CriticalSection, Interrupt, Mutex};
|
||||||
use crate::pac::timer::TimGp16;
|
use crate::pac::timer::TimGp16;
|
||||||
use crate::peripherals;
|
use crate::peripherals;
|
||||||
|
use crate::rcc::RccPeripheral;
|
||||||
use crate::time::Hertz;
|
use crate::time::Hertz;
|
||||||
|
|
||||||
// Clock timekeeping works with something we call "periods", which are time intervals
|
// Clock timekeeping works with something we call "periods", which are time intervals
|
||||||
@ -76,27 +77,12 @@ impl<T: Instance> Clock<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
pub fn start(&'static self, timer_freq: Hertz) {
|
||||||
let inner = T::inner();
|
let inner = T::inner();
|
||||||
|
|
||||||
|
T::enable();
|
||||||
|
T::reset();
|
||||||
|
|
||||||
// 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 {
|
||||||
@ -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 {
|
macro_rules! impl_timer {
|
||||||
($inst:ident) => {
|
($inst:ident) => {
|
||||||
|
@ -267,32 +267,42 @@ pub fn gen(options: Options) {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(clock) = &p.clock {
|
if let Some(rcc) = &rcc {
|
||||||
if let Some(rcc) = &rcc {
|
// Workaround for clock registers being split on some chip families. Assume fields are
|
||||||
// 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.
|
||||||
// named after peripheral and look for first field matching and use that register.
|
//
|
||||||
let en = find_reg_for_field(&rcc, clock, &format!("{}EN", name));
|
// Not all peripherals have the clock hint due to insufficient information from
|
||||||
let rst = find_reg_for_field(&rcc, clock, &format!("{}RST", name));
|
// 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) {
|
match (en, rst) {
|
||||||
(Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => {
|
(Some((enable_reg, enable_field)), Some((reset_reg, reset_field))) => {
|
||||||
peripheral_rcc_table.push(vec![
|
peripheral_rcc_table.push(vec![
|
||||||
name.clone(),
|
name.clone(),
|
||||||
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()),
|
||||||
format!("set_{}", reset_field.to_ascii_lowercase()),
|
format!("set_{}", reset_field.to_ascii_lowercase()),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
(None, Some(_)) => {
|
(None, Some(_)) => {
|
||||||
println!("Unable to find enable register for {}", name)
|
println!("Unable to find enable register for {}", name)
|
||||||
}
|
}
|
||||||
(Some(_), None) => {
|
(Some(_), None) => {
|
||||||
println!("Unable to find reset register for {}", name)
|
println!("Unable to find reset register for {}", name)
|
||||||
}
|
}
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
println!("Unable to find enable and reset register for {}", name)
|
println!("Unable to find enable and reset register for {}", name)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user