diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 7e3a8f14..ddf8cc2a 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -1,3 +1,5 @@ +mod traits; + use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; @@ -5,7 +7,7 @@ use embassy_hal_common::{into_ref, PeripheralRef}; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::AnyPin; -use crate::pwm::HighResolutionCaptureCompare16bitInstance; +use crate::hrtim::traits::HighResolutionCaptureCompare16bitInstance; use crate::time::Hertz; use crate::Peripheral; @@ -41,7 +43,7 @@ pub struct ChE { } mod sealed { - use crate::pwm::HighResolutionCaptureCompare16bitInstance; + use super::HighResolutionCaptureCompare16bitInstance; pub trait AdvancedChannel { fn raw() -> usize; diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs new file mode 100644 index 00000000..16193a45 --- /dev/null +++ b/embassy-stm32/src/hrtim/traits.rs @@ -0,0 +1,196 @@ +use crate::time::Hertz; + +#[derive(Clone, Copy)] +pub(crate) enum HighResolutionControlPrescaler { + Div1, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +impl From for u32 { + fn from(val: HighResolutionControlPrescaler) -> Self { + match val { + HighResolutionControlPrescaler::Div1 => 1, + HighResolutionControlPrescaler::Div2 => 2, + HighResolutionControlPrescaler::Div4 => 4, + HighResolutionControlPrescaler::Div8 => 8, + HighResolutionControlPrescaler::Div16 => 16, + HighResolutionControlPrescaler::Div32 => 32, + HighResolutionControlPrescaler::Div64 => 64, + HighResolutionControlPrescaler::Div128 => 128, + } + } +} + +impl From for u8 { + fn from(val: HighResolutionControlPrescaler) -> Self { + match val { + HighResolutionControlPrescaler::Div1 => 0b000, + HighResolutionControlPrescaler::Div2 => 0b001, + HighResolutionControlPrescaler::Div4 => 0b010, + HighResolutionControlPrescaler::Div8 => 0b011, + HighResolutionControlPrescaler::Div16 => 0b100, + HighResolutionControlPrescaler::Div32 => 0b101, + HighResolutionControlPrescaler::Div64 => 0b110, + HighResolutionControlPrescaler::Div128 => 0b111, + } + } +} + +impl From for HighResolutionControlPrescaler { + fn from(val: u8) -> Self { + match val { + 0b000 => HighResolutionControlPrescaler::Div1, + 0b001 => HighResolutionControlPrescaler::Div2, + 0b010 => HighResolutionControlPrescaler::Div4, + 0b011 => HighResolutionControlPrescaler::Div8, + 0b100 => HighResolutionControlPrescaler::Div16, + 0b101 => HighResolutionControlPrescaler::Div32, + 0b110 => HighResolutionControlPrescaler::Div64, + 0b111 => HighResolutionControlPrescaler::Div128, + _ => unreachable!(), + } + } +} + +impl HighResolutionControlPrescaler { + pub fn compute_min_high_res(val: u32) -> Self { + *[ + HighResolutionControlPrescaler::Div1, + HighResolutionControlPrescaler::Div2, + HighResolutionControlPrescaler::Div4, + HighResolutionControlPrescaler::Div8, + HighResolutionControlPrescaler::Div16, + HighResolutionControlPrescaler::Div32, + HighResolutionControlPrescaler::Div64, + HighResolutionControlPrescaler::Div128, + ] + .iter() + .skip_while(|psc| >::into(**psc) <= val) + .next() + .unwrap() + } + + pub fn compute_min_low_res(val: u32) -> Self { + *[ + HighResolutionControlPrescaler::Div32, + HighResolutionControlPrescaler::Div64, + HighResolutionControlPrescaler::Div128, + ] + .iter() + .skip_while(|psc| >::into(**psc) <= val) + .next() + .unwrap() + } +} + +pub(crate) mod sealed { + use super::*; + + pub trait HighResolutionCaptureCompare16bitInstance: crate::timer::sealed::HighResolutionControlInstance { + fn set_master_frequency(frequency: Hertz); + + fn set_channel_frequency(channnel: usize, frequency: Hertz); + + /// Set the dead time as a proportion of max_duty + fn set_channel_dead_time(channnel: usize, dead_time: u16); + + // fn enable_outputs(enable: bool); + // + // fn enable_channel(&mut self, channel: usize, enable: bool); + } +} + +pub trait HighResolutionCaptureCompare16bitInstance: + sealed::HighResolutionCaptureCompare16bitInstance + 'static +{ +} + +foreach_interrupt! { + ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { + impl sealed::HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { + fn set_master_frequency(frequency: Hertz) { + use crate::rcc::sealed::RccPeripheral; + use crate::timer::sealed::HighResolutionControlInstance; + + let f = frequency.0; + let timer_f = Self::frequency().0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = if Self::regs().isr().read().dllrdy() { + HighResolutionControlPrescaler::compute_min_high_res(psc_min) + } else { + HighResolutionControlPrescaler::compute_min_low_res(psc_min) + }; + + let psc_val: u32 = psc.into(); + let timer_f = 32 * (timer_f / psc_val); + let per: u16 = (timer_f / f) as u16; + + let regs = Self::regs(); + + regs.mcr().modify(|w| w.set_ckpsc(psc.into())); + regs.mper().modify(|w| w.set_mper(per)); + } + + fn set_channel_frequency(channel: usize, frequency: Hertz) { + use crate::rcc::sealed::RccPeripheral; + use crate::timer::sealed::HighResolutionControlInstance; + + let f = frequency.0; + let timer_f = Self::frequency().0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = if Self::regs().isr().read().dllrdy() { + HighResolutionControlPrescaler::compute_min_high_res(psc_min) + } else { + HighResolutionControlPrescaler::compute_min_low_res(psc_min) + }; + + let psc_val: u32 = psc.into(); + let timer_f = 32 * (timer_f / psc_val); + let per: u16 = (timer_f / f) as u16; + + let regs = Self::regs(); + + regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); + regs.tim(channel).per().modify(|w| w.set_per(per)); + } + + fn set_channel_dead_time(channel: usize, dead_time: u16) { + use crate::timer::sealed::HighResolutionControlInstance; + + let regs = Self::regs(); + + let channel_psc: HighResolutionControlPrescaler = regs.tim(channel).cr().read().ckpsc().into(); + let psc_val: u32 = channel_psc.into(); + + + // The dead-time base clock runs 4 times slower than the hrtim base clock + // u9::MAX = 511 + let psc_min = (psc_val * dead_time as u32) / (4 * 511); + let psc = if Self::regs().isr().read().dllrdy() { + HighResolutionControlPrescaler::compute_min_high_res(psc_min) + } else { + HighResolutionControlPrescaler::compute_min_low_res(psc_min) + }; + + let dt_psc_val: u32 = psc.into(); + let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val); + + regs.tim(channel).dt().modify(|w| { + w.set_dtprsc(psc.into()); + w.set_dtf(dt_val as u16); + w.set_dtr(dt_val as u16); + }); + } + } + + impl HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { + + } + }; +} diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index c4b38ebd..5aba2663 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -3,9 +3,6 @@ pub mod simple_pwm; use stm32_metapac::timer::vals::Ckd; -#[cfg(hrtim_v1)] -use crate::time::Hertz; - #[cfg(feature = "unstable-pac")] pub mod low_level { pub use super::sealed::*; @@ -57,117 +54,9 @@ impl From for stm32_metapac::timer::vals::Ocm { } } -#[cfg(hrtim_v1)] -#[derive(Clone, Copy)] -pub(crate) enum HighResolutionControlPrescaler { - Div1, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -#[cfg(hrtim_v1)] -impl From for u32 { - fn from(val: HighResolutionControlPrescaler) -> Self { - match val { - HighResolutionControlPrescaler::Div1 => 1, - HighResolutionControlPrescaler::Div2 => 2, - HighResolutionControlPrescaler::Div4 => 4, - HighResolutionControlPrescaler::Div8 => 8, - HighResolutionControlPrescaler::Div16 => 16, - HighResolutionControlPrescaler::Div32 => 32, - HighResolutionControlPrescaler::Div64 => 64, - HighResolutionControlPrescaler::Div128 => 128, - } - } -} - -#[cfg(hrtim_v1)] -impl From for u8 { - fn from(val: HighResolutionControlPrescaler) -> Self { - match val { - HighResolutionControlPrescaler::Div1 => 0b000, - HighResolutionControlPrescaler::Div2 => 0b001, - HighResolutionControlPrescaler::Div4 => 0b010, - HighResolutionControlPrescaler::Div8 => 0b011, - HighResolutionControlPrescaler::Div16 => 0b100, - HighResolutionControlPrescaler::Div32 => 0b101, - HighResolutionControlPrescaler::Div64 => 0b110, - HighResolutionControlPrescaler::Div128 => 0b111, - } - } -} - -#[cfg(hrtim_v1)] -impl From for HighResolutionControlPrescaler { - fn from(val: u8) -> Self { - match val { - 0b000 => HighResolutionControlPrescaler::Div1, - 0b001 => HighResolutionControlPrescaler::Div2, - 0b010 => HighResolutionControlPrescaler::Div4, - 0b011 => HighResolutionControlPrescaler::Div8, - 0b100 => HighResolutionControlPrescaler::Div16, - 0b101 => HighResolutionControlPrescaler::Div32, - 0b110 => HighResolutionControlPrescaler::Div64, - 0b111 => HighResolutionControlPrescaler::Div128, - _ => unreachable!(), - } - } -} - -#[cfg(hrtim_v1)] -impl HighResolutionControlPrescaler { - pub fn compute_min_high_res(val: u32) -> Self { - *[ - HighResolutionControlPrescaler::Div1, - HighResolutionControlPrescaler::Div2, - HighResolutionControlPrescaler::Div4, - HighResolutionControlPrescaler::Div8, - HighResolutionControlPrescaler::Div16, - HighResolutionControlPrescaler::Div32, - HighResolutionControlPrescaler::Div64, - HighResolutionControlPrescaler::Div128, - ] - .iter() - .skip_while(|psc| >::into(**psc) <= val) - .next() - .unwrap() - } - - pub fn compute_min_low_res(val: u32) -> Self { - *[ - HighResolutionControlPrescaler::Div32, - HighResolutionControlPrescaler::Div64, - HighResolutionControlPrescaler::Div128, - ] - .iter() - .skip_while(|psc| >::into(**psc) <= val) - .next() - .unwrap() - } -} - pub(crate) mod sealed { use super::*; - #[cfg(hrtim_v1)] - pub trait HighResolutionCaptureCompare16bitInstance: crate::timer::sealed::HighResolutionControlInstance { - fn set_master_frequency(frequency: Hertz); - - fn set_channel_frequency(channnel: usize, frequency: Hertz); - - /// Set the dead time as a proportion of max_duty - fn set_channel_dead_time(channnel: usize, dead_time: u16); - - // fn enable_outputs(enable: bool); - // - // fn enable_channel(&mut self, channel: usize, enable: bool); - } - pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance { /// Global output enable. Does not do anything on non-advanced timers. fn enable_outputs(&mut self, enable: bool); @@ -200,12 +89,6 @@ pub(crate) mod sealed { } } -#[cfg(hrtim_v1)] -pub trait HighResolutionCaptureCompare16bitInstance: - sealed::HighResolutionCaptureCompare16bitInstance + 'static -{ -} - pub trait CaptureCompare16bitInstance: sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static { @@ -367,88 +250,6 @@ foreach_interrupt! { } }; - - ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { - impl crate::pwm::sealed::HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { - fn set_master_frequency(frequency: Hertz) { - use crate::rcc::sealed::RccPeripheral; - use crate::timer::sealed::HighResolutionControlInstance; - - let f = frequency.0; - let timer_f = Self::frequency().0; - let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = if Self::regs().isr().read().dllrdy() { - HighResolutionControlPrescaler::compute_min_high_res(psc_min) - } else { - HighResolutionControlPrescaler::compute_min_low_res(psc_min) - }; - - let psc_val: u32 = psc.into(); - let timer_f = 32 * (timer_f / psc_val); - let per: u16 = (timer_f / f) as u16; - - let regs = Self::regs(); - - regs.mcr().modify(|w| w.set_ckpsc(psc.into())); - regs.mper().modify(|w| w.set_mper(per)); - } - - fn set_channel_frequency(channel: usize, frequency: Hertz) { - use crate::rcc::sealed::RccPeripheral; - use crate::timer::sealed::HighResolutionControlInstance; - - let f = frequency.0; - let timer_f = Self::frequency().0; - let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = if Self::regs().isr().read().dllrdy() { - HighResolutionControlPrescaler::compute_min_high_res(psc_min) - } else { - HighResolutionControlPrescaler::compute_min_low_res(psc_min) - }; - - let psc_val: u32 = psc.into(); - let timer_f = 32 * (timer_f / psc_val); - let per: u16 = (timer_f / f) as u16; - - let regs = Self::regs(); - - regs.tim(channel).cr().modify(|w| w.set_ckpsc(psc.into())); - regs.tim(channel).per().modify(|w| w.set_per(per)); - } - - fn set_channel_dead_time(channel: usize, dead_time: u16) { - use crate::timer::sealed::HighResolutionControlInstance; - - let regs = Self::regs(); - - let channel_psc: HighResolutionControlPrescaler = regs.tim(channel).cr().read().ckpsc().into(); - let psc_val: u32 = channel_psc.into(); - - - // The dead-time base clock runs 4 times slower than the hrtim base clock - // u9::MAX = 511 - let psc_min = (psc_val * dead_time as u32) / (4 * 511); - let psc = if Self::regs().isr().read().dllrdy() { - HighResolutionControlPrescaler::compute_min_high_res(psc_min) - } else { - HighResolutionControlPrescaler::compute_min_low_res(psc_min) - }; - - let dt_psc_val: u32 = psc.into(); - let dt_val = (dt_psc_val * dead_time as u32) / (4 * psc_val); - - regs.tim(channel).dt().modify(|w| { - w.set_dtprsc(psc.into()); - w.set_dtf(dt_val as u16); - w.set_dtr(dt_val as u16); - }); - } - } - - impl HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { - - } - }; } pin_trait!(Channel1Pin, CaptureCompare16bitInstance);