From cdb3fb059f32a5669856390cfe379da71092d545 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 25 Jun 2023 15:33:57 -0500 Subject: [PATCH 01/17] stm32/hrtim: first draft --- embassy-stm32/build.rs | 10 ++ embassy-stm32/src/pwm/advanced_pwm.rs | 147 ++++++++++++++++++++++++++ embassy-stm32/src/pwm/mod.rs | 60 +++++++++++ embassy-stm32/src/timer/mod.rs | 39 +++++++ 4 files changed, 256 insertions(+) create mode 100644 embassy-stm32/src/pwm/advanced_pwm.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 40103d32..4856047c 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -589,6 +589,16 @@ fn main() { (("timer", "BKIN2"), quote!(crate::pwm::BreakInput2Pin)), (("timer", "BKIN2_COMP1"), quote!(crate::pwm::BreakInput2Comparator1Pin)), (("timer", "BKIN2_COMP2"), quote!(crate::pwm::BreakInput2Comparator2Pin)), + (("hrtim", "CHA1"), quote!(crate::pwm::ChannelAPin)), + (("hrtim", "CHA2"), quote!(crate::pwm::ChannelAComplementaryPin)), + (("hrtim", "CHB1"), quote!(crate::pwm::ChannelBPin)), + (("hrtim", "CHB2"), quote!(crate::pwm::ChannelBComplementaryPin)), + (("hrtim", "CHC1"), quote!(crate::pwm::ChannelCPin)), + (("hrtim", "CHC2"), quote!(crate::pwm::ChannelCComplementaryPin)), + (("hrtim", "CHD1"), quote!(crate::pwm::ChannelDPin)), + (("hrtim", "CHD2"), quote!(crate::pwm::ChannelDComplementaryPin)), + (("hrtim", "CHE1"), quote!(crate::pwm::ChannelEPin)), + (("hrtim", "CHE2"), quote!(crate::pwm::ChannelEComplementaryPin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs new file mode 100644 index 00000000..39d60c50 --- /dev/null +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -0,0 +1,147 @@ +use core::marker::PhantomData; + +use embassy_hal_common::{into_ref, PeripheralRef}; + +use super::simple_pwm::*; +use super::*; +#[allow(unused_imports)] +use crate::gpio::sealed::{AFType, Pin}; +use crate::gpio::AnyPin; +use crate::time::Hertz; +use crate::Peripheral; + +// Re-implement the channels for hrtim +pub struct ChA; +pub struct ChB; +pub struct ChC; +pub struct ChD; +pub struct ChE; + +pub struct PwmPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, +} + +pub struct ComplementaryPwmPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, +} + +macro_rules! advanced_channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => { + impl<'d, Perip: AdvancedCaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af(pin.af_num(), AFType::OutputPushPull); + #[cfg(gpio_v2)] + pin.set_speed(crate::gpio::Speed::VeryHigh); + }); + PwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + + impl<'d, Perip: AdvancedCaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| { + pin.set_low(); + pin.set_as_af(pin.af_num(), AFType::OutputPushPull); + #[cfg(gpio_v2)] + pin.set_speed(crate::gpio::Speed::VeryHigh); + }); + ComplementaryPwmPin { + _pin: pin.map_into(), + phantom: PhantomData, + } + } + } + }; +} + +advanced_channel_impl!(new_cha, ChA, ChannelAPin, ChannelAComplementaryPin); +advanced_channel_impl!(new_chb, ChB, ChannelBPin, ChannelBComplementaryPin); +advanced_channel_impl!(new_chc, ChC, ChannelCPin, ChannelCComplementaryPin); +advanced_channel_impl!(new_chd, ChD, ChannelDPin, ChannelDComplementaryPin); +advanced_channel_impl!(new_che, ChE, ChannelEPin, ChannelEComplementaryPin); + +pub struct AdvancedPwm<'d, T> { + inner: PeripheralRef<'d, T>, +} + +impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1: Option>, + _ch1n: Option>, + _ch2: Option>, + _ch2n: Option>, + _ch3: Option>, + _ch3n: Option>, + _ch4: Option>, + _ch4n: Option>, + freq: Hertz, + ) -> Self { + Self::new_inner(tim, freq) + } + + fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + into_ref!(tim); + + T::enable(); + ::reset(); + + let mut this = Self { inner: tim }; + // + // this.inner.set_frequency(freq); + // this.inner.start(); + // + // this.inner.enable_outputs(true); + // + // this.inner + // .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); + // this.inner + // .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); + // this.inner + // .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); + // this.inner + // .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); + this + } + + pub fn enable(&mut self, channel: AdvancedChannel) { + // self.inner.enable_channel(channel, true); + // self.inner.enable_complementary_channel(channel, true); + } + + pub fn disable(&mut self, channel: AdvancedChannel) { + // self.inner.enable_complementary_channel(channel, false); + // self.inner.enable_channel(channel, false); + } + + pub fn set_freq(&mut self, freq: Hertz) { + // self.inner.set_frequency(freq); + } + + pub fn get_max_duty(&self) -> u16 { + todo!() + // self.inner.get_max_compare_value() + } + + pub fn set_duty(&mut self, channel: AdvancedChannel, duty: u16) { + // assert!(duty < self.get_max_duty()); + // self.inner.set_compare_value(channel, duty) + } + + /// Set the dead time as a proportion of max_duty + pub fn set_dead_time(&mut self, value: u16) { + // let (ckd, value) = compute_dead_time_value(value); + // + // self.inner.set_dead_time_clock_division(ckd); + // self.inner.set_dead_time_value(value); + } +} diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 5aba2663..4c203134 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -1,3 +1,5 @@ +#[cfg(hrtim_v1)] +pub mod advanced_pwm; pub mod complementary_pwm; pub mod simple_pwm; @@ -27,6 +29,29 @@ impl Channel { } } +#[cfg(hrtim_v1)] +#[derive(Clone, Copy)] +pub enum AdvancedChannel { + ChA, + ChB, + ChC, + ChD, + ChE, +} + +#[cfg(hrtim_v1)] +impl AdvancedChannel { + pub fn raw(&self) -> usize { + match self { + AdvancedChannel::ChA => 0, + AdvancedChannel::ChB => 1, + AdvancedChannel::ChC => 2, + AdvancedChannel::ChD => 3, + AdvancedChannel::ChE => 4, + } + } +} + #[derive(Clone, Copy)] pub enum OutputCompareMode { Frozen, @@ -57,6 +82,14 @@ impl From for stm32_metapac::timer::vals::Ocm { pub(crate) mod sealed { use super::*; + pub trait AdvancedCaptureCompare16bitInstance: crate::timer::sealed::HighResolutionControlInstance { + fn enable_outputs(&mut self, enable: bool); + + fn set_output_compare_mode(&mut self, channel: AdvancedChannel, mode: OutputCompareMode); + + fn enable_channel(&mut self, channel: AdvancedChannel, 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); @@ -89,6 +122,8 @@ pub(crate) mod sealed { } } +pub trait AdvancedCaptureCompare16bitInstance: sealed::AdvancedCaptureCompare16bitInstance + 'static {} + pub trait CaptureCompare16bitInstance: sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static { @@ -250,6 +285,20 @@ foreach_interrupt! { } }; + + ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { + impl crate::pwm::sealed::AdvancedCaptureCompare16bitInstance for crate::peripherals::$inst { + fn enable_outputs(&mut self, enable: bool) { todo!() } + + fn set_output_compare_mode(&mut self, channel: AdvancedChannel, mode: OutputCompareMode) { todo!() } + + fn enable_channel(&mut self, channel: AdvancedChannel, enable: bool) { todo!() } + } + + impl AdvancedCaptureCompare16bitInstance for crate::peripherals::$inst { + + } + }; } pin_trait!(Channel1Pin, CaptureCompare16bitInstance); @@ -267,3 +316,14 @@ pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); + +pin_trait!(ChannelAPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelAComplementaryPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelBPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelBComplementaryPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelCPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelCComplementaryPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelDPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelDComplementaryPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelEPin, AdvancedCaptureCompare16bitInstance); +pin_trait!(ChannelEComplementaryPin, AdvancedCaptureCompare16bitInstance); diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 09b7a377..34ad5db1 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -43,6 +43,21 @@ pub(crate) mod sealed { pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { fn regs_advanced() -> crate::pac::timer::TimAdv; } + + #[cfg(hrtim_v1)] + pub trait HighResolutionControlInstance: RccPeripheral { + type Interrupt: interrupt::typelevel::Interrupt; + + fn regs_highres() -> crate::pac::hrtim::Hrtim; + + fn start(&mut self); + + fn stop(&mut self); + + fn reset(&mut self); + + fn set_frequency(&mut self, frequency: Hertz); + } } pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} @@ -51,6 +66,9 @@ pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'st pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} +#[cfg(hrtim_v1)] +pub trait HighResolutionControlInstance: sealed::HighResolutionControlInstance + 'static {} + pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} #[allow(unused)] @@ -208,4 +226,25 @@ foreach_interrupt! { impl AdvancedControlInstance for crate::peripherals::$inst { } }; + + ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { + impl sealed::HighResolutionControlInstance for crate::peripherals::$inst { + type Interrupt = crate::interrupt::typelevel::$irq; + + fn regs_highres() -> crate::pac::hrtim::Hrtim { + crate::pac::$inst + } + + fn start(&mut self) { todo!() } + + fn stop(&mut self) { todo!() } + + fn reset(&mut self) { todo!() } + + fn set_frequency(&mut self, frequency: Hertz) { todo!() } + } + + impl HighResolutionControlInstance for crate::peripherals::$inst { + } + }; } From 71513ccb3905965aef2ae29a841dfdf4dfffe69a Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 26 Jun 2023 19:59:10 -0500 Subject: [PATCH 02/17] stm32/hrtim: impl. draft frequency computation --- embassy-stm32/src/pwm/mod.rs | 32 +++++--- embassy-stm32/src/timer/mod.rs | 138 ++++++++++++++++++++++++++++++++- 2 files changed, 155 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 4c203134..1838bfdf 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -29,7 +29,6 @@ impl Channel { } } -#[cfg(hrtim_v1)] #[derive(Clone, Copy)] pub enum AdvancedChannel { ChA, @@ -39,7 +38,6 @@ pub enum AdvancedChannel { ChE, } -#[cfg(hrtim_v1)] impl AdvancedChannel { pub fn raw(&self) -> usize { match self { @@ -82,6 +80,7 @@ impl From for stm32_metapac::timer::vals::Ocm { pub(crate) mod sealed { use super::*; + #[cfg(hrtim_v1)] pub trait AdvancedCaptureCompare16bitInstance: crate::timer::sealed::HighResolutionControlInstance { fn enable_outputs(&mut self, enable: bool); @@ -122,6 +121,7 @@ pub(crate) mod sealed { } } +#[cfg(hrtim_v1)] pub trait AdvancedCaptureCompare16bitInstance: sealed::AdvancedCaptureCompare16bitInstance + 'static {} pub trait CaptureCompare16bitInstance: @@ -317,13 +317,21 @@ pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); -pin_trait!(ChannelAPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelAComplementaryPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelBPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelBComplementaryPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelCPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelCComplementaryPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelDPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelDComplementaryPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelEPin, AdvancedCaptureCompare16bitInstance); -pin_trait!(ChannelEComplementaryPin, AdvancedCaptureCompare16bitInstance); +#[cfg(hrtim_v1)] +mod hrtim_pins { + use super::*; + + pin_trait!(ChannelAPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelAComplementaryPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelBPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelBComplementaryPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelCPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelCComplementaryPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelDPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelDComplementaryPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelEPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelEComplementaryPin, AdvancedCaptureCompare16bitInstance); +} + +#[cfg(hrtim_v1)] +pub use hrtim_pins::*; diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 34ad5db1..03b9b3cf 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,3 +1,6 @@ +#[cfg(hrtim_v1)] +use core::ops; + use stm32_metapac::timer::vals; use crate::interrupt; @@ -50,13 +53,64 @@ pub(crate) mod sealed { fn regs_highres() -> crate::pac::hrtim::Hrtim; + fn set_master_frequency(&mut self, frequency: Hertz); + + fn set_channel_frequency(&mut self, channel: usize, frequency: Hertz); + fn start(&mut self); fn stop(&mut self); fn reset(&mut self); + } +} - fn set_frequency(&mut self, frequency: Hertz); +#[cfg(hrtim_v1)] +#[derive(Clone, Copy)] +pub(crate) enum HighResolutionControlPrescaler { + Div1, + Div2, + Div4, + Div8, + Div16, + Div32, + Div64, + Div128, +} + +#[cfg(hrtim_v1)] +impl ops::Div for Hertz { + type Output = Hertz; + + fn div(self, rhs: HighResolutionControlPrescaler) -> Self::Output { + let divisor = match rhs { + HighResolutionControlPrescaler::Div1 => 1, + HighResolutionControlPrescaler::Div2 => 2, + HighResolutionControlPrescaler::Div4 => 4, + HighResolutionControlPrescaler::Div8 => 8, + HighResolutionControlPrescaler::Div16 => 16, + HighResolutionControlPrescaler::Div32 => 32, + HighResolutionControlPrescaler::Div64 => 64, + HighResolutionControlPrescaler::Div128 => 128, + }; + + Hertz(self.0 / divisor) + } +} + +#[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, + } } } @@ -235,13 +289,91 @@ foreach_interrupt! { crate::pac::$inst } + fn set_master_frequency(&mut self, frequency: Hertz) { + use crate::rcc::sealed::RccPeripheral; + + // TODO: fix frequency source + let f = frequency.0; + let timer_f = Self::frequency().0; + // Ratio taken from RM0364 Table 81 + let base_f = Hertz(timer_f * (70_300 / 144_000_000)); + + /* + Find the smallest prescaler that allows us to acheive our frequency + */ + let psc = [ + HighResolutionControlPrescaler::Div1, + HighResolutionControlPrescaler::Div2, + HighResolutionControlPrescaler::Div4, + HighResolutionControlPrescaler::Div8, + HighResolutionControlPrescaler::Div16, + HighResolutionControlPrescaler::Div32, + HighResolutionControlPrescaler::Div64, + HighResolutionControlPrescaler::Div128, + ] + .iter() + .skip_while(|psc| frequency < base_f / **psc) + .next() + .unwrap(); + + let psc_timer_f = Hertz(timer_f) / *psc; + let per: u16 = (psc_timer_f / f).0 as u16; + + let regs = Self::regs_highres(); + + regs.mcr().modify(|w| w.set_ckpsc(((*psc).into()))); + regs.mper().modify(|w| w.set_mper(per)); + + // regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + // regs.egr().write(|r| r.set_ug(true)); + // regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + } + + fn set_channel_frequency(&mut self, channel: usize, frequency: Hertz) { + use crate::rcc::sealed::RccPeripheral; + + // TODO: fix frequency source + let f = frequency.0; + let timer_f = Self::frequency().0; + // Ratio taken from RM0364 Table 81 + let base_f = Hertz(timer_f * (70_300 / 144_000_000)); + + /* + Find the smallest prescaler that allows us to acheive our frequency + */ + let psc = [ + HighResolutionControlPrescaler::Div1, + HighResolutionControlPrescaler::Div2, + HighResolutionControlPrescaler::Div4, + HighResolutionControlPrescaler::Div8, + HighResolutionControlPrescaler::Div16, + HighResolutionControlPrescaler::Div32, + HighResolutionControlPrescaler::Div64, + HighResolutionControlPrescaler::Div128, + ] + .iter() + .skip_while(|psc| frequency < base_f / **psc) + .next() + .unwrap(); + + let psc_timer_f = Hertz(timer_f) / *psc; + let per: u16 = (psc_timer_f / f).0 as u16; + + let regs = Self::regs_highres(); + + regs.tim(channel).cr().modify(|w| w.set_ckpsc(((*psc).into()))); + regs.tim(channel).per().modify(|w| w.set_per(per)); + + // regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); + // regs.egr().write(|r| r.set_ug(true)); + // regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); + } + fn start(&mut self) { todo!() } fn stop(&mut self) { todo!() } fn reset(&mut self) { todo!() } - - fn set_frequency(&mut self, frequency: Hertz) { todo!() } } impl HighResolutionControlInstance for crate::peripherals::$inst { From b9eb3dfad7b601a7819377c2c94369ca74efc824 Mon Sep 17 00:00:00 2001 From: xoviat Date: Mon, 26 Jun 2023 20:23:26 -0500 Subject: [PATCH 03/17] stm32/hrtim: add api concept --- embassy-stm32/src/pwm/advanced_pwm.rs | 131 +++++++++++++++++++------- 1 file changed, 98 insertions(+), 33 deletions(-) diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index 39d60c50..a0895224 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -11,11 +11,30 @@ use crate::time::Hertz; use crate::Peripheral; // Re-implement the channels for hrtim -pub struct ChA; -pub struct ChB; -pub struct ChC; -pub struct ChD; -pub struct ChE; +pub struct Master { + phantom: PhantomData, +} +pub struct ChA { + phantom: PhantomData, +} +pub struct ChB { + phantom: PhantomData, +} +pub struct ChC { + phantom: PhantomData, +} +pub struct ChD { + phantom: PhantomData, +} +pub struct ChE { + phantom: PhantomData, +} + +mod sealed { + pub trait AdvancedChannel {} +} + +pub trait AdvancedChannel: sealed::AdvancedChannel {} pub struct PwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, @@ -60,6 +79,9 @@ macro_rules! advanced_channel_impl { } } } + + impl sealed::AdvancedChannel for $channel {} + impl AdvancedChannel for $channel {} }; } @@ -69,8 +91,15 @@ advanced_channel_impl!(new_chc, ChC, ChannelCPin, ChannelCComplementaryPin); advanced_channel_impl!(new_chd, ChD, ChannelDPin, ChannelDComplementaryPin); advanced_channel_impl!(new_che, ChE, ChannelEPin, ChannelEComplementaryPin); +/// Struct used to divide a high resolution timer into multiple channels pub struct AdvancedPwm<'d, T> { inner: PeripheralRef<'d, T>, + pub master: Master, + pub ch_a: ChA, + pub ch_b: ChB, + pub ch_c: ChC, + pub ch_d: ChD, + pub ch_e: ChE, } impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { @@ -84,18 +113,25 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { _ch3n: Option>, _ch4: Option>, _ch4n: Option>, - freq: Hertz, ) -> Self { - Self::new_inner(tim, freq) + Self::new_inner(tim) } - fn new_inner(tim: impl Peripheral

+ 'd, freq: Hertz) -> Self { + fn new_inner(tim: impl Peripheral

+ 'd) -> Self { into_ref!(tim); T::enable(); ::reset(); - let mut this = Self { inner: tim }; + Self { + inner: tim, + master: Master { phantom: PhantomData }, + ch_a: ChA { phantom: PhantomData }, + ch_b: ChB { phantom: PhantomData }, + ch_c: ChC { phantom: PhantomData }, + ch_d: ChD { phantom: PhantomData }, + ch_e: ChE { phantom: PhantomData }, + } // // this.inner.set_frequency(freq); // this.inner.start(); @@ -110,32 +146,31 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { // .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); // this.inner // .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); - this } - pub fn enable(&mut self, channel: AdvancedChannel) { - // self.inner.enable_channel(channel, true); - // self.inner.enable_complementary_channel(channel, true); - } - - pub fn disable(&mut self, channel: AdvancedChannel) { - // self.inner.enable_complementary_channel(channel, false); - // self.inner.enable_channel(channel, false); - } - - pub fn set_freq(&mut self, freq: Hertz) { - // self.inner.set_frequency(freq); - } - - pub fn get_max_duty(&self) -> u16 { - todo!() - // self.inner.get_max_compare_value() - } - - pub fn set_duty(&mut self, channel: AdvancedChannel, duty: u16) { - // assert!(duty < self.get_max_duty()); - // self.inner.set_compare_value(channel, duty) - } + // pub fn enable(&mut self, channel: AdvancedChannel) { + // // self.inner.enable_channel(channel, true); + // // self.inner.enable_complementary_channel(channel, true); + // } + // + // pub fn disable(&mut self, channel: AdvancedChannel) { + // // self.inner.enable_complementary_channel(channel, false); + // // self.inner.enable_channel(channel, false); + // } + // + // pub fn set_freq(&mut self, freq: Hertz) { + // // self.inner.set_frequency(freq); + // } + // + // pub fn get_max_duty(&self) -> u16 { + // todo!() + // // self.inner.get_max_compare_value() + // } + // + // pub fn set_duty(&mut self, channel: AdvancedChannel, duty: u16) { + // // assert!(duty < self.get_max_duty()); + // // self.inner.set_compare_value(channel, duty) + // } /// Set the dead time as a proportion of max_duty pub fn set_dead_time(&mut self, value: u16) { @@ -145,3 +180,33 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { // self.inner.set_dead_time_value(value); } } + +// Represents a fixed-frequency bridge converter +pub struct BridgeConverter { + pub ch: T, +} + +impl BridgeConverter { + pub fn new(channel: T, frequency: Hertz) -> Self { + Self { ch: channel } + } + + pub fn set_duty(&mut self, primary: u16, secondary: u16) { + todo!() + } +} + +// Represents a variable-frequency resonant converter +pub struct ResonantConverter { + pub ch: T, +} + +impl ResonantConverter { + pub fn new(channel: T, min_frequency: Hertz) -> Self { + Self { ch: channel } + } + + pub fn set_frequency(&mut self, frequency: Hertz) { + todo!() + } +} From 348019e37f0ff5716d80199e33244c0a1a59b360 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 27 Jun 2023 18:24:32 -0500 Subject: [PATCH 04/17] stm32/hrtim: impl channel alloc type system --- embassy-stm32/src/pwm/advanced_pwm.rs | 167 ++++++++++++-------------- embassy-stm32/src/pwm/mod.rs | 144 +++++++++++++++++----- embassy-stm32/src/timer/mod.rs | 149 +---------------------- 3 files changed, 194 insertions(+), 266 deletions(-) diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index a0895224..c7b5f748 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -2,7 +2,6 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; -use super::simple_pwm::*; use super::*; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; @@ -11,30 +10,34 @@ use crate::time::Hertz; use crate::Peripheral; // Re-implement the channels for hrtim -pub struct Master { - phantom: PhantomData, +pub struct Master { + phantom: PhantomData, } -pub struct ChA { - phantom: PhantomData, +pub struct ChA { + phantom: PhantomData, } -pub struct ChB { - phantom: PhantomData, +pub struct ChB { + phantom: PhantomData, } -pub struct ChC { - phantom: PhantomData, +pub struct ChC { + phantom: PhantomData, } -pub struct ChD { - phantom: PhantomData, +pub struct ChD { + phantom: PhantomData, } -pub struct ChE { - phantom: PhantomData, +pub struct ChE { + phantom: PhantomData, } mod sealed { - pub trait AdvancedChannel {} + use crate::pwm::AdvancedCaptureCompare16bitInstance; + + pub trait AdvancedChannel {} } -pub trait AdvancedChannel: sealed::AdvancedChannel {} +pub trait AdvancedChannel: sealed::AdvancedChannel { + fn raw() -> usize; +} pub struct PwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, @@ -47,8 +50,8 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> { } macro_rules! advanced_channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => { - impl<'d, Perip: AdvancedCaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { + ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { + impl<'d, Perip: AdvancedCaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -64,7 +67,7 @@ macro_rules! advanced_channel_impl { } } - impl<'d, Perip: AdvancedCaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { + impl<'d, Perip: AdvancedCaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -80,39 +83,45 @@ macro_rules! advanced_channel_impl { } } - impl sealed::AdvancedChannel for $channel {} - impl AdvancedChannel for $channel {} + impl sealed::AdvancedChannel for $channel {} + impl AdvancedChannel for $channel { + fn raw() -> usize { + $ch_num + } + } }; } -advanced_channel_impl!(new_cha, ChA, ChannelAPin, ChannelAComplementaryPin); -advanced_channel_impl!(new_chb, ChB, ChannelBPin, ChannelBComplementaryPin); -advanced_channel_impl!(new_chc, ChC, ChannelCPin, ChannelCComplementaryPin); -advanced_channel_impl!(new_chd, ChD, ChannelDPin, ChannelDComplementaryPin); -advanced_channel_impl!(new_che, ChE, ChannelEPin, ChannelEComplementaryPin); +advanced_channel_impl!(new_cha, ChA, 0, ChannelAPin, ChannelAComplementaryPin); +advanced_channel_impl!(new_chb, ChB, 1, ChannelBPin, ChannelBComplementaryPin); +advanced_channel_impl!(new_chc, ChC, 2, ChannelCPin, ChannelCComplementaryPin); +advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); +advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); /// Struct used to divide a high resolution timer into multiple channels -pub struct AdvancedPwm<'d, T> { - inner: PeripheralRef<'d, T>, - pub master: Master, - pub ch_a: ChA, - pub ch_b: ChB, - pub ch_c: ChC, - pub ch_d: ChD, - pub ch_e: ChE, +pub struct AdvancedPwm<'d, T: AdvancedCaptureCompare16bitInstance> { + _inner: PeripheralRef<'d, T>, + pub master: Master, + pub ch_a: ChA, + pub ch_b: ChB, + pub ch_c: ChC, + pub ch_d: ChD, + pub ch_e: ChE, } -impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { +impl<'d, T: AdvancedCaptureCompare16bitInstance> AdvancedPwm<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, - _ch1: Option>, - _ch1n: Option>, - _ch2: Option>, - _ch2n: Option>, - _ch3: Option>, - _ch3n: Option>, - _ch4: Option>, - _ch4n: Option>, + _cha: Option>>, + _chan: Option>>, + _chb: Option>>, + _chbn: Option>>, + _chc: Option>>, + _chcn: Option>>, + _chd: Option>>, + _chdn: Option>>, + _che: Option>>, + _chen: Option>>, ) -> Self { Self::new_inner(tim) } @@ -124,7 +133,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { ::reset(); Self { - inner: tim, + _inner: tim, master: Master { phantom: PhantomData }, ch_a: ChA { phantom: PhantomData }, ch_b: ChB { phantom: PhantomData }, @@ -132,48 +141,11 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { ch_d: ChD { phantom: PhantomData }, ch_e: ChE { phantom: PhantomData }, } - // - // this.inner.set_frequency(freq); - // this.inner.start(); - // - // this.inner.enable_outputs(true); - // - // this.inner - // .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); - // this.inner - // .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); - // this.inner - // .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); - // this.inner - // .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); } - // pub fn enable(&mut self, channel: AdvancedChannel) { - // // self.inner.enable_channel(channel, true); - // // self.inner.enable_complementary_channel(channel, true); - // } - // - // pub fn disable(&mut self, channel: AdvancedChannel) { - // // self.inner.enable_complementary_channel(channel, false); - // // self.inner.enable_channel(channel, false); - // } - // - // pub fn set_freq(&mut self, freq: Hertz) { - // // self.inner.set_frequency(freq); - // } - // - // pub fn get_max_duty(&self) -> u16 { - // todo!() - // // self.inner.get_max_compare_value() - // } - // - // pub fn set_duty(&mut self, channel: AdvancedChannel, duty: u16) { - // // assert!(duty < self.get_max_duty()); - // // self.inner.set_compare_value(channel, duty) - // } - /// Set the dead time as a proportion of max_duty - pub fn set_dead_time(&mut self, value: u16) { + pub fn set_dead_time(&mut self, _value: u16) { + todo!() // let (ckd, value) = compute_dead_time_value(value); // // self.inner.set_dead_time_clock_division(ckd); @@ -182,28 +154,39 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> AdvancedPwm<'d, T> { } // Represents a fixed-frequency bridge converter -pub struct BridgeConverter { - pub ch: T, +pub struct BridgeConverter> { + phantom: PhantomData, + pub ch: C, } -impl BridgeConverter { - pub fn new(channel: T, frequency: Hertz) -> Self { - Self { ch: channel } +impl> BridgeConverter { + pub fn new(channel: C, frequency: Hertz) -> Self { + Self { + phantom: PhantomData, + ch: channel, + } } pub fn set_duty(&mut self, primary: u16, secondary: u16) { + let _ = T::regs(); + let _ = C::raw(); + todo!() } } // Represents a variable-frequency resonant converter -pub struct ResonantConverter { - pub ch: T, +pub struct ResonantConverter> { + phantom: PhantomData, + pub ch: C, } -impl ResonantConverter { - pub fn new(channel: T, min_frequency: Hertz) -> Self { - Self { ch: channel } +impl> ResonantConverter { + pub fn new(channel: C, min_frequency: Hertz) -> Self { + Self { + phantom: PhantomData, + ch: channel, + } } pub fn set_frequency(&mut self, frequency: Hertz) { diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 1838bfdf..67009e78 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -3,8 +3,14 @@ pub mod advanced_pwm; pub mod complementary_pwm; pub mod simple_pwm; +#[cfg(hrtim_v1)] +use core::ops; + 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::*; @@ -29,27 +35,6 @@ impl Channel { } } -#[derive(Clone, Copy)] -pub enum AdvancedChannel { - ChA, - ChB, - ChC, - ChD, - ChE, -} - -impl AdvancedChannel { - pub fn raw(&self) -> usize { - match self { - AdvancedChannel::ChA => 0, - AdvancedChannel::ChB => 1, - AdvancedChannel::ChC => 2, - AdvancedChannel::ChD => 3, - AdvancedChannel::ChE => 4, - } - } -} - #[derive(Clone, Copy)] pub enum OutputCompareMode { Frozen, @@ -77,16 +62,87 @@ 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 ops::Div for Hertz { + type Output = Hertz; + + fn div(self, rhs: HighResolutionControlPrescaler) -> Self::Output { + let divisor = match rhs { + HighResolutionControlPrescaler::Div1 => 1, + HighResolutionControlPrescaler::Div2 => 2, + HighResolutionControlPrescaler::Div4 => 4, + HighResolutionControlPrescaler::Div8 => 8, + HighResolutionControlPrescaler::Div16 => 16, + HighResolutionControlPrescaler::Div32 => 32, + HighResolutionControlPrescaler::Div64 => 64, + HighResolutionControlPrescaler::Div128 => 128, + }; + + Hertz(self.0 / divisor) + } +} + +#[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 HighResolutionControlPrescaler { + pub fn compute_min(base_f: Hertz, frequency: Hertz) -> Self { + *[ + HighResolutionControlPrescaler::Div1, + HighResolutionControlPrescaler::Div2, + HighResolutionControlPrescaler::Div4, + HighResolutionControlPrescaler::Div8, + HighResolutionControlPrescaler::Div16, + HighResolutionControlPrescaler::Div32, + HighResolutionControlPrescaler::Div64, + HighResolutionControlPrescaler::Div128, + ] + .iter() + .skip_while(|psc| frequency <= base_f / **psc) + .next() + .unwrap() + } +} + pub(crate) mod sealed { use super::*; #[cfg(hrtim_v1)] pub trait AdvancedCaptureCompare16bitInstance: crate::timer::sealed::HighResolutionControlInstance { - fn enable_outputs(&mut self, enable: bool); + fn set_master_frequency(frequency: Hertz); - fn set_output_compare_mode(&mut self, channel: AdvancedChannel, mode: OutputCompareMode); + fn set_channel_frequency(channnel: usize, frequency: Hertz); - fn enable_channel(&mut self, channel: AdvancedChannel, enable: bool); + // fn enable_outputs(enable: bool); + // + // fn enable_channel(&mut self, channel: usize, enable: bool); } pub trait CaptureCompare16bitInstance: crate::timer::sealed::GeneralPurpose16bitInstance { @@ -288,11 +344,45 @@ foreach_interrupt! { ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { impl crate::pwm::sealed::AdvancedCaptureCompare16bitInstance for crate::peripherals::$inst { - fn enable_outputs(&mut self, enable: bool) { todo!() } + fn set_master_frequency(frequency: Hertz) { + use crate::rcc::sealed::RccPeripheral; + use crate::timer::sealed::HighResolutionControlInstance; - fn set_output_compare_mode(&mut self, channel: AdvancedChannel, mode: OutputCompareMode) { todo!() } + let f = frequency.0; + // TODO: fix frequency source + // let timer_f = Self::frequency().0; + let timer_f = Hertz(144_000_000).0; + let base_f = Hertz((32 * timer_f as u64 / u16::MAX as u64) as u32); + let psc = HighResolutionControlPrescaler::compute_min(base_f, frequency); - fn enable_channel(&mut self, channel: AdvancedChannel, enable: bool) { todo!() } + let psc_timer_f = Hertz(timer_f) / psc; + let per: u16 = (psc_timer_f / f).0 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; + // TODO: fix frequency source + // let timer_f = Self::frequency().0; + let timer_f = Hertz(144_000_000).0; + let base_f = Hertz((32 * timer_f as u64 / u16::MAX as u64) as u32); + let psc = HighResolutionControlPrescaler::compute_min(base_f, frequency); + + let psc_timer_f = Hertz(timer_f) / psc; + let per: u16 = (psc_timer_f / f).0 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)); + } } impl AdvancedCaptureCompare16bitInstance for crate::peripherals::$inst { diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 03b9b3cf..89cb1666 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -51,66 +51,7 @@ pub(crate) mod sealed { pub trait HighResolutionControlInstance: RccPeripheral { type Interrupt: interrupt::typelevel::Interrupt; - fn regs_highres() -> crate::pac::hrtim::Hrtim; - - fn set_master_frequency(&mut self, frequency: Hertz); - - fn set_channel_frequency(&mut self, channel: usize, frequency: Hertz); - - fn start(&mut self); - - fn stop(&mut self); - - fn reset(&mut self); - } -} - -#[cfg(hrtim_v1)] -#[derive(Clone, Copy)] -pub(crate) enum HighResolutionControlPrescaler { - Div1, - Div2, - Div4, - Div8, - Div16, - Div32, - Div64, - Div128, -} - -#[cfg(hrtim_v1)] -impl ops::Div for Hertz { - type Output = Hertz; - - fn div(self, rhs: HighResolutionControlPrescaler) -> Self::Output { - let divisor = match rhs { - HighResolutionControlPrescaler::Div1 => 1, - HighResolutionControlPrescaler::Div2 => 2, - HighResolutionControlPrescaler::Div4 => 4, - HighResolutionControlPrescaler::Div8 => 8, - HighResolutionControlPrescaler::Div16 => 16, - HighResolutionControlPrescaler::Div32 => 32, - HighResolutionControlPrescaler::Div64 => 64, - HighResolutionControlPrescaler::Div128 => 128, - }; - - Hertz(self.0 / divisor) - } -} - -#[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, - } + fn regs() -> crate::pac::hrtim::Hrtim; } } @@ -285,95 +226,9 @@ foreach_interrupt! { impl sealed::HighResolutionControlInstance for crate::peripherals::$inst { type Interrupt = crate::interrupt::typelevel::$irq; - fn regs_highres() -> crate::pac::hrtim::Hrtim { + fn regs() -> crate::pac::hrtim::Hrtim { crate::pac::$inst } - - fn set_master_frequency(&mut self, frequency: Hertz) { - use crate::rcc::sealed::RccPeripheral; - - // TODO: fix frequency source - let f = frequency.0; - let timer_f = Self::frequency().0; - // Ratio taken from RM0364 Table 81 - let base_f = Hertz(timer_f * (70_300 / 144_000_000)); - - /* - Find the smallest prescaler that allows us to acheive our frequency - */ - let psc = [ - HighResolutionControlPrescaler::Div1, - HighResolutionControlPrescaler::Div2, - HighResolutionControlPrescaler::Div4, - HighResolutionControlPrescaler::Div8, - HighResolutionControlPrescaler::Div16, - HighResolutionControlPrescaler::Div32, - HighResolutionControlPrescaler::Div64, - HighResolutionControlPrescaler::Div128, - ] - .iter() - .skip_while(|psc| frequency < base_f / **psc) - .next() - .unwrap(); - - let psc_timer_f = Hertz(timer_f) / *psc; - let per: u16 = (psc_timer_f / f).0 as u16; - - let regs = Self::regs_highres(); - - regs.mcr().modify(|w| w.set_ckpsc(((*psc).into()))); - regs.mper().modify(|w| w.set_mper(per)); - - // regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); - // regs.egr().write(|r| r.set_ug(true)); - // regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); - } - - fn set_channel_frequency(&mut self, channel: usize, frequency: Hertz) { - use crate::rcc::sealed::RccPeripheral; - - // TODO: fix frequency source - let f = frequency.0; - let timer_f = Self::frequency().0; - // Ratio taken from RM0364 Table 81 - let base_f = Hertz(timer_f * (70_300 / 144_000_000)); - - /* - Find the smallest prescaler that allows us to acheive our frequency - */ - let psc = [ - HighResolutionControlPrescaler::Div1, - HighResolutionControlPrescaler::Div2, - HighResolutionControlPrescaler::Div4, - HighResolutionControlPrescaler::Div8, - HighResolutionControlPrescaler::Div16, - HighResolutionControlPrescaler::Div32, - HighResolutionControlPrescaler::Div64, - HighResolutionControlPrescaler::Div128, - ] - .iter() - .skip_while(|psc| frequency < base_f / **psc) - .next() - .unwrap(); - - let psc_timer_f = Hertz(timer_f) / *psc; - let per: u16 = (psc_timer_f / f).0 as u16; - - let regs = Self::regs_highres(); - - regs.tim(channel).cr().modify(|w| w.set_ckpsc(((*psc).into()))); - regs.tim(channel).per().modify(|w| w.set_per(per)); - - // regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTERONLY)); - // regs.egr().write(|r| r.set_ug(true)); - // regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); - } - - fn start(&mut self) { todo!() } - - fn stop(&mut self) { todo!() } - - fn reset(&mut self) { todo!() } } impl HighResolutionControlInstance for crate::peripherals::$inst { From 3252eaa060d8efb79f99511ac40a26be9cf287f9 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 27 Jun 2023 20:30:58 -0500 Subject: [PATCH 05/17] stm32/hrtim: add example impl. --- .vscode/settings.json | 1 + ci.sh | 1 + embassy-stm32/src/pwm/advanced_pwm.rs | 2 +- examples/stm32f334/.cargo/config.toml | 9 ++++ examples/stm32f334/Cargo.toml | 26 +++++++++++ examples/stm32f334/build.rs | 5 +++ examples/stm32f334/src/bin/hello.rs | 23 ++++++++++ examples/stm32f334/src/bin/pwm.rs | 63 +++++++++++++++++++++++++++ 8 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 examples/stm32f334/.cargo/config.toml create mode 100644 examples/stm32f334/Cargo.toml create mode 100644 examples/stm32f334/build.rs create mode 100644 examples/stm32f334/src/bin/hello.rs create mode 100644 examples/stm32f334/src/bin/pwm.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 9ef7fe1c..fdfafafa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -25,6 +25,7 @@ // "examples/stm32f1/Cargo.toml", // "examples/stm32f2/Cargo.toml", // "examples/stm32f3/Cargo.toml", + // "examples/stm32f334/Cargo.toml", // "examples/stm32f4/Cargo.toml", // "examples/stm32f7/Cargo.toml", // "examples/stm32g0/Cargo.toml", diff --git a/ci.sh b/ci.sh index a03efb85..ec6304f1 100755 --- a/ci.sh +++ b/ci.sh @@ -119,6 +119,7 @@ cargo batch \ --- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \ --- build --release --manifest-path examples/stm32f2/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f2 \ --- build --release --manifest-path examples/stm32f3/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f3 \ + --- build --release --manifest-path examples/stm32f334/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f334 \ --- build --release --manifest-path examples/stm32f4/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/stm32f4 \ --- build --release --manifest-path examples/stm32f7/Cargo.toml --target thumbv7em-none-eabihf --out-dir out/examples/stm32f7 \ --- build --release --manifest-path examples/stm32c0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32c0 \ diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index c7b5f748..bb0e06ad 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -52,7 +52,7 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> { macro_rules! advanced_channel_impl { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { impl<'d, Perip: AdvancedCaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { - pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { pin.set_low(); diff --git a/examples/stm32f334/.cargo/config.toml b/examples/stm32f334/.cargo/config.toml new file mode 100644 index 00000000..7f3fda52 --- /dev/null +++ b/examples/stm32f334/.cargo/config.toml @@ -0,0 +1,9 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` +runner = "probe-rs-cli run --chip STM32F303ZETx" + +[build] +target = "thumbv7em-none-eabihf" + +[env] +DEFMT_LOG = "trace" diff --git a/examples/stm32f334/Cargo.toml b/examples/stm32f334/Cargo.toml new file mode 100644 index 00000000..6410891a --- /dev/null +++ b/examples/stm32f334/Cargo.toml @@ -0,0 +1,26 @@ +[package] +edition = "2021" +name = "embassy-stm32f3-examples" +version = "0.1.0" +license = "MIT OR Apache-2.0" + +[dependencies] +embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } +embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] } +embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["nightly", "defmt", "stm32f334r8", "unstable-pac", "memory-x", "time-driver-any", "exti"] } +embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } + +defmt = "0.3" +defmt-rtt = "0.4" + +cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.3", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +heapless = { version = "0.7.5", default-features = false } +nb = "1.0.0" +embedded-storage = "0.3.0" +static_cell = { version = "1.1", features = ["nightly"]} diff --git a/examples/stm32f334/build.rs b/examples/stm32f334/build.rs new file mode 100644 index 00000000..8cd32d7e --- /dev/null +++ b/examples/stm32f334/build.rs @@ -0,0 +1,5 @@ +fn main() { + println!("cargo:rustc-link-arg-bins=--nmagic"); + println!("cargo:rustc-link-arg-bins=-Tlink.x"); + println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); +} diff --git a/examples/stm32f334/src/bin/hello.rs b/examples/stm32f334/src/bin/hello.rs new file mode 100644 index 00000000..65773210 --- /dev/null +++ b/examples/stm32f334/src/bin/hello.rs @@ -0,0 +1,23 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_stm32::time::Hertz; +use embassy_stm32::Config; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) -> ! { + let mut config = Config::default(); + config.rcc.hse = Some(Hertz(8_000_000)); + config.rcc.sysclk = Some(Hertz(16_000_000)); + let _p = embassy_stm32::init(config); + + loop { + info!("Hello World!"); + Timer::after(Duration::from_secs(1)).await; + } +} diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs new file mode 100644 index 00000000..cc2ea861 --- /dev/null +++ b/examples/stm32f334/src/bin/pwm.rs @@ -0,0 +1,63 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::pwm::advanced_pwm::*; +use embassy_stm32::pwm::Channel; +use embassy_stm32::time::khz; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_stm32::init(Default::default()); + info!("Hello World!"); + + let ch1 = PwmPin::new_cha(p.PA8); + let ch1n = ComplementaryPwmPin::new_cha(p.PA9); + let mut pwm = AdvancedPwm::new( + p.HRTIM1, + Some(ch1), + Some(ch1n), + None, + None, + None, + None, + None, + None, + None, + None, + ); + + pwm.set_dead_time(0); + + let mut buck_converter = BridgeConverter::new(pwm.ch_a, khz(100)); + + buck_converter.set_duty(0, u16::MAX); + + // note: if the pins are not passed into the advanced pwm struct, they will not be output + let mut boost_converter = BridgeConverter::new(pwm.ch_b, khz(100)); + + boost_converter.set_duty(0, 0); + + // let max = pwm.get_max_duty(); + // pwm.set_dead_time(max / 1024); + // + // pwm.enable(Channel::Ch1); + // + // info!("PWM initialized"); + // info!("PWM max duty {}", max); + // + // loop { + // pwm.set_duty(Channel::Ch1, 0); + // Timer::after(Duration::from_millis(300)).await; + // pwm.set_duty(Channel::Ch1, max / 4); + // Timer::after(Duration::from_millis(300)).await; + // pwm.set_duty(Channel::Ch1, max / 2); + // Timer::after(Duration::from_millis(300)).await; + // pwm.set_duty(Channel::Ch1, max - 1); + // Timer::after(Duration::from_millis(300)).await; + // } +} From 8c4997c5fcd8c25d68865b9e7537e0add50eac24 Mon Sep 17 00:00:00 2001 From: xoviat Date: Thu, 29 Jun 2023 21:05:41 -0500 Subject: [PATCH 06/17] stm32/hrtim: impl. bridge, dead-time part. res. --- embassy-stm32/src/pwm/advanced_pwm.rs | 193 +++++++++++++++++++++----- embassy-stm32/src/pwm/mod.rs | 117 +++++++++++----- examples/stm32f334/src/bin/pwm.rs | 9 +- 3 files changed, 241 insertions(+), 78 deletions(-) diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index bb0e06ad..228899c0 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -9,33 +9,44 @@ use crate::gpio::AnyPin; use crate::time::Hertz; use crate::Peripheral; -// Re-implement the channels for hrtim -pub struct Master { +pub enum Source { + Master, + ChA, + ChB, + ChC, + ChD, + ChE, +} + +pub struct BurstController { phantom: PhantomData, } -pub struct ChA { +pub struct Master { phantom: PhantomData, } -pub struct ChB { +pub struct ChA { phantom: PhantomData, } -pub struct ChC { +pub struct ChB { phantom: PhantomData, } -pub struct ChD { +pub struct ChC { phantom: PhantomData, } -pub struct ChE { +pub struct ChD { + phantom: PhantomData, +} +pub struct ChE { phantom: PhantomData, } mod sealed { - use crate::pwm::AdvancedCaptureCompare16bitInstance; + use crate::pwm::HighResolutionCaptureCompare16bitInstance; - pub trait AdvancedChannel {} + pub trait AdvancedChannel {} } -pub trait AdvancedChannel: sealed::AdvancedChannel { +pub trait AdvancedChannel: sealed::AdvancedChannel { fn raw() -> usize; } @@ -51,7 +62,7 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> { macro_rules! advanced_channel_impl { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { - impl<'d, Perip: AdvancedCaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { + impl<'d, Perip: HighResolutionCaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -67,7 +78,7 @@ macro_rules! advanced_channel_impl { } } - impl<'d, Perip: AdvancedCaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { + impl<'d, Perip: HighResolutionCaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -83,8 +94,8 @@ macro_rules! advanced_channel_impl { } } - impl sealed::AdvancedChannel for $channel {} - impl AdvancedChannel for $channel { + impl sealed::AdvancedChannel for $channel {} + impl AdvancedChannel for $channel { fn raw() -> usize { $ch_num } @@ -99,9 +110,10 @@ advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); /// Struct used to divide a high resolution timer into multiple channels -pub struct AdvancedPwm<'d, T: AdvancedCaptureCompare16bitInstance> { +pub struct AdvancedPwm<'d, T: HighResolutionCaptureCompare16bitInstance> { _inner: PeripheralRef<'d, T>, pub master: Master, + pub burst_controller: BurstController, pub ch_a: ChA, pub ch_b: ChB, pub ch_c: ChC, @@ -109,7 +121,7 @@ pub struct AdvancedPwm<'d, T: AdvancedCaptureCompare16bitInstance> { pub ch_e: ChE, } -impl<'d, T: AdvancedCaptureCompare16bitInstance> AdvancedPwm<'d, T> { +impl<'d, T: HighResolutionCaptureCompare16bitInstance> AdvancedPwm<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, _cha: Option>>, @@ -135,6 +147,7 @@ impl<'d, T: AdvancedCaptureCompare16bitInstance> AdvancedPwm<'d, T> { Self { _inner: tim, master: Master { phantom: PhantomData }, + burst_controller: BurstController { phantom: PhantomData }, ch_a: ChA { phantom: PhantomData }, ch_b: ChB { phantom: PhantomData }, ch_c: ChC { phantom: PhantomData }, @@ -142,54 +155,162 @@ impl<'d, T: AdvancedCaptureCompare16bitInstance> AdvancedPwm<'d, T> { ch_e: ChE { phantom: PhantomData }, } } +} - /// Set the dead time as a proportion of max_duty - pub fn set_dead_time(&mut self, _value: u16) { - todo!() - // let (ckd, value) = compute_dead_time_value(value); - // - // self.inner.set_dead_time_clock_division(ckd); - // self.inner.set_dead_time_value(value); +impl BurstController { + pub fn set_source(&mut self, source: Source) { + let regs = T::regs(); } } -// Represents a fixed-frequency bridge converter -pub struct BridgeConverter> { +/// Represents a fixed-frequency bridge converter +/// +/// Our implementation of the bridge converter uses a single channel and two compare registers, +/// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous +/// conduction mode. +/// +/// It is important to remember that in synchronous topologies, energy can flow in reverse during +/// light loading conditions, and that the low-side switch must be active for a short time to drive +/// a bootstrapped high-side switch. +pub struct BridgeConverter> { phantom: PhantomData, pub ch: C, } -impl> BridgeConverter { +impl> BridgeConverter { pub fn new(channel: C, frequency: Hertz) -> Self { + use crate::pac::hrtim::vals::{Activeeffect, Cont, Inactiveeffect}; + + T::set_channel_frequency(C::raw(), frequency); + + // Always enable preload + T::regs().tim(C::raw()).cr().modify(|w| { + w.set_preen(true); + + // TODO: fix metapac + w.set_cont(Cont(1)); + }); + + // Set output 1 to active on a period event + T::regs() + .tim(C::raw()) + .setr(0) + .modify(|w| w.set_per(Activeeffect::SETACTIVE)); + + // Set output 1 to inactive on a compare 1 event + T::regs() + .tim(C::raw()) + .rstr(0) + .modify(|w| w.set_cmp(0, Inactiveeffect::SETINACTIVE)); + + // Set output 2 to active on a compare 1 event + T::regs() + .tim(C::raw()) + .setr(1) + .modify(|w| w.set_cmp(0, Activeeffect::SETACTIVE)); + + // Set output 2 to inactive on a compare 2 event + T::regs() + .tim(C::raw()) + .rstr(1) + .modify(|w| w.set_cmp(1, Inactiveeffect::SETINACTIVE)); + Self { phantom: PhantomData, ch: channel, } } - pub fn set_duty(&mut self, primary: u16, secondary: u16) { - let _ = T::regs(); - let _ = C::raw(); + pub fn start(&mut self) { + T::regs().mcr().modify(|w| w.set_tcen(C::raw(), true)); + } - todo!() + pub fn stop(&mut self) { + T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); + } + + /// Set the dead time as a proportion of the maximum compare value + pub fn set_dead_time(&mut self, value: u16) { + T::set_channel_dead_time(C::raw(), value); + } + + /// Get the maximum compare value of a duty cycle + pub fn get_max_compare_value(&mut self) -> u16 { + T::regs().tim(C::raw()).per().read().per() + } + + /// The primary duty is the period in which the primary switch is active + /// + /// In the case of a buck converter, this is the high-side switch + /// In the case of a boost converter, this is the low-side switch + pub fn set_primary_duty(&mut self, primary: u16) { + T::regs().tim(C::raw()).cmp(0).modify(|w| w.set_cmp(primary)); + } + + /// The primary duty is the period in any switch is active + /// + /// If less than or equal to the primary duty, the secondary switch will never be active + pub fn set_secondary_duty(&mut self, secondary: u16) { + T::regs().tim(C::raw()).cmp(1).modify(|w| w.set_cmp(secondary)); } } -// Represents a variable-frequency resonant converter -pub struct ResonantConverter> { +/// Represents a variable-frequency resonant converter +/// +/// This implementation of a resonsant converter is appropriate for a half or full bridge, +/// but does not include secondary rectification, which is appropriate for applications +/// with a low-voltage on the secondary side. +pub struct ResonantConverter> { phantom: PhantomData, + min_period: u16, + max_period: u16, pub ch: C, } -impl> ResonantConverter { - pub fn new(channel: C, min_frequency: Hertz) -> Self { +impl> ResonantConverter { + pub fn new(channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { + use crate::pac::hrtim::vals::Cont; + + T::set_channel_frequency(C::raw(), min_frequency); + + // Always enable preload + T::regs().tim(C::raw()).cr().modify(|w| { + w.set_preen(true); + + // TODO: fix metapac + w.set_cont(Cont(1)); + w.set_half(true); + }); + + // TODO: compute min period value + Self { + min_period: 0, + max_period: T::regs().tim(C::raw()).per().read().per(), phantom: PhantomData, ch: channel, } } - pub fn set_frequency(&mut self, frequency: Hertz) { - todo!() + /// Set the dead time as a proportion of the maximum compare value + pub fn set_dead_time(&mut self, value: u16) { + T::set_channel_dead_time(C::raw(), value); + } + + pub fn set_period(&mut self, period: u16) { + assert!(period < self.max_period); + assert!(period > self.min_period); + + T::regs().tim(C::raw()).per().modify(|w| w.set_per(period)); + } + + /// Get the minimum compare value of a duty cycle + pub fn get_min_period(&mut self) -> u16 { + self.min_period + } + + /// Get the maximum compare value of a duty cycle + pub fn get_max_period(&mut self) -> u16 { + self.max_period } } diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 67009e78..2586dc15 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -76,11 +76,9 @@ pub(crate) enum HighResolutionControlPrescaler { } #[cfg(hrtim_v1)] -impl ops::Div for Hertz { - type Output = Hertz; - - fn div(self, rhs: HighResolutionControlPrescaler) -> Self::Output { - let divisor = match rhs { +impl From for u32 { + fn from(val: HighResolutionControlPrescaler) -> Self { + match val { HighResolutionControlPrescaler::Div1 => 1, HighResolutionControlPrescaler::Div2 => 2, HighResolutionControlPrescaler::Div4 => 4, @@ -89,9 +87,7 @@ impl ops::Div for Hertz { HighResolutionControlPrescaler::Div32 => 32, HighResolutionControlPrescaler::Div64 => 64, HighResolutionControlPrescaler::Div128 => 128, - }; - - Hertz(self.0 / divisor) + } } } @@ -111,9 +107,26 @@ impl From for u8 { } } +#[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(base_f: Hertz, frequency: Hertz) -> Self { + pub fn compute_min(val: u32) -> Self { *[ HighResolutionControlPrescaler::Div1, HighResolutionControlPrescaler::Div2, @@ -125,7 +138,7 @@ impl HighResolutionControlPrescaler { HighResolutionControlPrescaler::Div128, ] .iter() - .skip_while(|psc| frequency <= base_f / **psc) + .skip_while(|psc| >::into(**psc) <= val) .next() .unwrap() } @@ -135,11 +148,14 @@ pub(crate) mod sealed { use super::*; #[cfg(hrtim_v1)] - pub trait AdvancedCaptureCompare16bitInstance: crate::timer::sealed::HighResolutionControlInstance { + 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); @@ -178,7 +194,10 @@ pub(crate) mod sealed { } #[cfg(hrtim_v1)] -pub trait AdvancedCaptureCompare16bitInstance: sealed::AdvancedCaptureCompare16bitInstance + 'static {} +pub trait HighResolutionCaptureCompare16bitInstance: + sealed::HighResolutionCaptureCompare16bitInstance + 'static +{ +} pub trait CaptureCompare16bitInstance: sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static @@ -343,20 +362,19 @@ foreach_interrupt! { }; ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { - impl crate::pwm::sealed::AdvancedCaptureCompare16bitInstance for crate::peripherals::$inst { + 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; - // TODO: fix frequency source - // let timer_f = Self::frequency().0; - let timer_f = Hertz(144_000_000).0; - let base_f = Hertz((32 * timer_f as u64 / u16::MAX as u64) as u32); - let psc = HighResolutionControlPrescaler::compute_min(base_f, frequency); + let timer_f = Self::frequency().0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = HighResolutionControlPrescaler::compute_min(psc_min); - let psc_timer_f = Hertz(timer_f) / psc; - let per: u16 = (psc_timer_f / f).0 as u16; + let psc_val: u32 = psc.into(); + let timer_f = timer_f / psc_val; + let per: u16 = (timer_f / f) as u16; let regs = Self::regs(); @@ -369,23 +387,46 @@ foreach_interrupt! { use crate::timer::sealed::HighResolutionControlInstance; let f = frequency.0; - // TODO: fix frequency source - // let timer_f = Self::frequency().0; - let timer_f = Hertz(144_000_000).0; - let base_f = Hertz((32 * timer_f as u64 / u16::MAX as u64) as u32); - let psc = HighResolutionControlPrescaler::compute_min(base_f, frequency); + let timer_f = Self::frequency().0; + let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); + let psc = HighResolutionControlPrescaler::compute_min(psc_min); - let psc_timer_f = Hertz(timer_f) / psc; - let per: u16 = (psc_timer_f / f).0 as u16; + let psc_val: u32 = psc.into(); + let timer_f = 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::rcc::sealed::RccPeripheral; + 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 = HighResolutionControlPrescaler::compute_min(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 AdvancedCaptureCompare16bitInstance for crate::peripherals::$inst { + impl HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { } }; @@ -411,16 +452,16 @@ pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); mod hrtim_pins { use super::*; - pin_trait!(ChannelAPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelAComplementaryPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelBPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelBComplementaryPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelCPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelCComplementaryPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelDPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelDComplementaryPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelEPin, AdvancedCaptureCompare16bitInstance); - pin_trait!(ChannelEComplementaryPin, AdvancedCaptureCompare16bitInstance); + pin_trait!(ChannelAPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelAComplementaryPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelBPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelBComplementaryPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelCPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelCComplementaryPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelDPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelDComplementaryPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelEPin, HighResolutionCaptureCompare16bitInstance); + pin_trait!(ChannelEComplementaryPin, HighResolutionCaptureCompare16bitInstance); } #[cfg(hrtim_v1)] diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index cc2ea861..20a62137 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -31,16 +31,17 @@ async fn main(_spawner: Spawner) { None, ); - pwm.set_dead_time(0); - let mut buck_converter = BridgeConverter::new(pwm.ch_a, khz(100)); - buck_converter.set_duty(0, u16::MAX); + buck_converter.set_primary_duty(0); + buck_converter.set_secondary_duty(0); + buck_converter.set_dead_time(0); // note: if the pins are not passed into the advanced pwm struct, they will not be output let mut boost_converter = BridgeConverter::new(pwm.ch_b, khz(100)); - boost_converter.set_duty(0, 0); + boost_converter.set_primary_duty(0); + boost_converter.set_secondary_duty(0); // let max = pwm.get_max_duty(); // pwm.set_dead_time(max / 1024); From c07854fed8f6ba38d418ef63853769a9af109bff Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 30 Jun 2023 18:20:33 -0500 Subject: [PATCH 07/17] stm32/hrtim: minor fixes --- embassy-stm32/src/pwm/advanced_pwm.rs | 49 +++++++++++++++++++++------ 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index 228899c0..7e595421 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -43,12 +43,12 @@ pub struct ChE { mod sealed { use crate::pwm::HighResolutionCaptureCompare16bitInstance; - pub trait AdvancedChannel {} + pub trait AdvancedChannel { + fn raw() -> usize; + } } -pub trait AdvancedChannel: sealed::AdvancedChannel { - fn raw() -> usize; -} +pub trait AdvancedChannel: sealed::AdvancedChannel {} pub struct PwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, @@ -94,12 +94,12 @@ macro_rules! advanced_channel_impl { } } - impl sealed::AdvancedChannel for $channel {} - impl AdvancedChannel for $channel { + impl sealed::AdvancedChannel for $channel { fn raw() -> usize { $ch_num } } + impl AdvancedChannel for $channel {} }; } @@ -158,8 +158,8 @@ impl<'d, T: HighResolutionCaptureCompare16bitInstance> AdvancedPwm<'d, T> { } impl BurstController { - pub fn set_source(&mut self, source: Source) { - let regs = T::regs(); + pub fn set_source(&mut self, _source: Source) { + todo!("burst mode control registers not implemented") } } @@ -229,6 +229,32 @@ impl> Bridge T::regs().mcr().modify(|w| w.set_tcen(C::raw(), false)); } + pub fn enable_burst_mode(&mut self) { + use crate::pac::hrtim::vals::{Idlem, Idles}; + + // TODO: fix metapac + T::regs().tim(C::raw()).outr().modify(|w| { + w.set_idlem(0, Idlem(1)); + w.set_idlem(1, Idlem(1)); + + w.set_idles(0, Idles(1)); + w.set_idles(1, Idles(1)); + }) + } + + pub fn disable_burst_mode(&mut self) { + use crate::pac::hrtim::vals::{Idlem, Idles}; + + // TODO: fix metapac + T::regs().tim(C::raw()).outr().modify(|w| { + w.set_idlem(0, Idlem(0)); + w.set_idlem(1, Idlem(0)); + + w.set_idles(0, Idles(0)); + w.set_idles(1, Idles(0)); + }) + } + /// Set the dead time as a proportion of the maximum compare value pub fn set_dead_time(&mut self, value: u16) { T::set_channel_dead_time(C::raw(), value); @@ -282,11 +308,12 @@ impl> Resona w.set_half(true); }); - // TODO: compute min period value + let max_period = T::regs().tim(C::raw()).per().read().per(); + let min_period = max_period * (min_frequency.0 / max_frequency.0) as u16; Self { - min_period: 0, - max_period: T::regs().tim(C::raw()).per().read().per(), + min_period: min_period, + max_period: max_period, phantom: PhantomData, ch: channel, } From 6e13f5b387d8f0f948b5874bc300925b015947d9 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 30 Jun 2023 18:33:22 -0500 Subject: [PATCH 08/17] rustfmt --- embassy-stm32/src/pwm/mod.rs | 4 ---- embassy-stm32/src/rcc/f3.rs | 1 + embassy-stm32/src/timer/mod.rs | 3 --- examples/stm32f334/src/bin/pwm.rs | 4 +--- 4 files changed, 2 insertions(+), 10 deletions(-) diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 2586dc15..d09e38d0 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -3,9 +3,6 @@ pub mod advanced_pwm; pub mod complementary_pwm; pub mod simple_pwm; -#[cfg(hrtim_v1)] -use core::ops; - use stm32_metapac::timer::vals::Ckd; #[cfg(hrtim_v1)] @@ -402,7 +399,6 @@ foreach_interrupt! { } fn set_channel_dead_time(channel: usize, dead_time: u16) { - use crate::rcc::sealed::RccPeripheral; use crate::timer::sealed::HighResolutionControlInstance; let regs = Self::regs(); diff --git a/embassy-stm32/src/rcc/f3.rs b/embassy-stm32/src/rcc/f3.rs index 2deee80d..321270a7 100644 --- a/embassy-stm32/src/rcc/f3.rs +++ b/embassy-stm32/src/rcc/f3.rs @@ -264,6 +264,7 @@ fn calc_pll(config: &Config, Hertz(sysclk): Hertz) -> (Hertz, PllConfig) { } #[inline] +#[allow(unused_variables)] fn get_usb_pre(config: &Config, sysclk: u32, pclk1: u32, pll_config: &Option) -> Usbpre { cfg_if::cfg_if! { // Some chips do not have USB diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 89cb1666..a92f854e 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,6 +1,3 @@ -#[cfg(hrtim_v1)] -use core::ops; - use stm32_metapac::timer::vals; use crate::interrupt; diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 20a62137..1b5d509e 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -5,9 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::pwm::advanced_pwm::*; -use embassy_stm32::pwm::Channel; use embassy_stm32::time::khz; -use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] @@ -17,7 +15,7 @@ async fn main(_spawner: Spawner) { let ch1 = PwmPin::new_cha(p.PA8); let ch1n = ComplementaryPwmPin::new_cha(p.PA9); - let mut pwm = AdvancedPwm::new( + let pwm = AdvancedPwm::new( p.HRTIM1, Some(ch1), Some(ch1n), From 21a86531955facbdba5583b5218e20f1ca6dc23e Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 1 Jul 2023 17:32:16 -0500 Subject: [PATCH 09/17] hrtim: minor cleanup --- embassy-stm32/Cargo.toml | 2 +- embassy-stm32/src/pwm/advanced_pwm.rs | 28 ++++++++++++++------------- examples/stm32f334/.cargo/config.toml | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 3d9ee826..551c0969 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -57,7 +57,7 @@ sdio-host = "0.5.0" embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } critical-section = "1.1" atomic-polyfill = "1.0.1" -stm32-metapac = "10" +stm32-metapac = "12" vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index 7e595421..65f4e7ca 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -187,8 +187,12 @@ impl> Bridge T::regs().tim(C::raw()).cr().modify(|w| { w.set_preen(true); - // TODO: fix metapac - w.set_cont(Cont(1)); + w.set_cont(Cont::CONTINUOUS); + }); + + T::regs().oenr().modify(|w| { + w.set_t1oen(C::raw(), true); + w.set_t2oen(C::raw(), true); }); // Set output 1 to active on a period event @@ -234,24 +238,23 @@ impl> Bridge // TODO: fix metapac T::regs().tim(C::raw()).outr().modify(|w| { - w.set_idlem(0, Idlem(1)); - w.set_idlem(1, Idlem(1)); + w.set_idlem(0, Idlem::SETIDLE); + w.set_idlem(1, Idlem::SETIDLE); - w.set_idles(0, Idles(1)); - w.set_idles(1, Idles(1)); + w.set_idles(0, Idles::INACTIVE); + w.set_idles(1, Idles::INACTIVE); }) } pub fn disable_burst_mode(&mut self) { use crate::pac::hrtim::vals::{Idlem, Idles}; - // TODO: fix metapac T::regs().tim(C::raw()).outr().modify(|w| { - w.set_idlem(0, Idlem(0)); - w.set_idlem(1, Idlem(0)); + w.set_idlem(0, Idlem::NOEFFECT); + w.set_idlem(1, Idlem::NOEFFECT); - w.set_idles(0, Idles(0)); - w.set_idles(1, Idles(0)); + w.set_idles(0, Idles::INACTIVE); + w.set_idles(1, Idles::INACTIVE); }) } @@ -303,8 +306,7 @@ impl> Resona T::regs().tim(C::raw()).cr().modify(|w| { w.set_preen(true); - // TODO: fix metapac - w.set_cont(Cont(1)); + w.set_cont(Cont::CONTINUOUS); w.set_half(true); }); diff --git a/examples/stm32f334/.cargo/config.toml b/examples/stm32f334/.cargo/config.toml index 7f3fda52..caf947be 100644 --- a/examples/stm32f334/.cargo/config.toml +++ b/examples/stm32f334/.cargo/config.toml @@ -1,6 +1,6 @@ [target.'cfg(all(target_arch = "arm", target_os = "none"))'] # replace STM32F429ZITx with your chip as listed in `probe-rs-cli chip list` -runner = "probe-rs-cli run --chip STM32F303ZETx" +runner = "probe-run --chip STM32F334R8" [build] target = "thumbv7em-none-eabihf" From aceba1c03fc45179d4e910fad254a31191cf0c44 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sat, 1 Jul 2023 21:47:44 -0500 Subject: [PATCH 10/17] hrtim: fix example and auto adjust psc. --- embassy-stm32/src/pwm/advanced_pwm.rs | 87 ++++++++++++++++++++------- embassy-stm32/src/pwm/mod.rs | 37 ++++++++++-- examples/stm32f334/src/bin/button.rs | 27 +++++++++ examples/stm32f334/src/bin/pwm.rs | 65 +++++++++++--------- 4 files changed, 160 insertions(+), 56 deletions(-) create mode 100644 examples/stm32f334/src/bin/button.rs diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index 65f4e7ca..fa34b2e1 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -144,6 +144,18 @@ impl<'d, T: HighResolutionCaptureCompare16bitInstance> AdvancedPwm<'d, T> { T::enable(); ::reset(); + // // Enable and and stabilize the DLL + // T::regs().dllcr().modify(|w| { + // // w.set_calen(true); + // // w.set_calrte(11); + // w.set_cal(true); + // }); + // + // debug!("wait for dll calibration"); + // while !T::regs().isr().read().dllrdy() {} + // + // debug!("dll calibration complete"); + Self { _inner: tim, master: Master { phantom: PhantomData }, @@ -173,12 +185,14 @@ impl BurstController { /// light loading conditions, and that the low-side switch must be active for a short time to drive /// a bootstrapped high-side switch. pub struct BridgeConverter> { - phantom: PhantomData, - pub ch: C, + timer: PhantomData, + channel: PhantomData, + dead_time: u16, + primary_duty: u16, } impl> BridgeConverter { - pub fn new(channel: C, frequency: Hertz) -> Self { + pub fn new(_channel: C, frequency: Hertz) -> Self { use crate::pac::hrtim::vals::{Activeeffect, Cont, Inactiveeffect}; T::set_channel_frequency(C::raw(), frequency); @@ -186,15 +200,21 @@ impl> Bridge // Always enable preload T::regs().tim(C::raw()).cr().modify(|w| { w.set_preen(true); + w.set_repu(true); w.set_cont(Cont::CONTINUOUS); }); + // Enable timer outputs T::regs().oenr().modify(|w| { w.set_t1oen(C::raw(), true); w.set_t2oen(C::raw(), true); }); + // The dead-time generation unit cannot be used because it forces the other output + // to be completely complementary to the first output, which restricts certain waveforms + // Therefore, software-implemented dead time must be used when setting the duty cycles + // Set output 1 to active on a period event T::regs() .tim(C::raw()) @@ -207,21 +227,23 @@ impl> Bridge .rstr(0) .modify(|w| w.set_cmp(0, Inactiveeffect::SETINACTIVE)); - // Set output 2 to active on a compare 1 event + // Set output 2 to active on a compare 2 event T::regs() .tim(C::raw()) .setr(1) - .modify(|w| w.set_cmp(0, Activeeffect::SETACTIVE)); + .modify(|w| w.set_cmp(1, Activeeffect::SETACTIVE)); - // Set output 2 to inactive on a compare 2 event + // Set output 2 to inactive on a compare 3 event T::regs() .tim(C::raw()) .rstr(1) - .modify(|w| w.set_cmp(1, Inactiveeffect::SETINACTIVE)); + .modify(|w| w.set_cmp(2, Inactiveeffect::SETINACTIVE)); Self { - phantom: PhantomData, - ch: channel, + timer: PhantomData, + channel: PhantomData, + dead_time: 0, + primary_duty: 0, } } @@ -236,7 +258,6 @@ impl> Bridge pub fn enable_burst_mode(&mut self) { use crate::pac::hrtim::vals::{Idlem, Idles}; - // TODO: fix metapac T::regs().tim(C::raw()).outr().modify(|w| { w.set_idlem(0, Idlem::SETIDLE); w.set_idlem(1, Idlem::SETIDLE); @@ -258,9 +279,18 @@ impl> Bridge }) } + fn update_primary_duty_or_dead_time(&mut self) { + T::regs().tim(C::raw()).cmp(0).modify(|w| w.set_cmp(self.primary_duty)); + T::regs() + .tim(C::raw()) + .cmp(1) + .modify(|w| w.set_cmp(self.primary_duty + self.dead_time)); + } + /// Set the dead time as a proportion of the maximum compare value - pub fn set_dead_time(&mut self, value: u16) { - T::set_channel_dead_time(C::raw(), value); + pub fn set_dead_time(&mut self, dead_time: u16) { + self.dead_time = dead_time; + self.update_primary_duty_or_dead_time(); } /// Get the maximum compare value of a duty cycle @@ -272,15 +302,17 @@ impl> Bridge /// /// In the case of a buck converter, this is the high-side switch /// In the case of a boost converter, this is the low-side switch - pub fn set_primary_duty(&mut self, primary: u16) { - T::regs().tim(C::raw()).cmp(0).modify(|w| w.set_cmp(primary)); + pub fn set_primary_duty(&mut self, primary_duty: u16) { + self.primary_duty = primary_duty; + self.update_primary_duty_or_dead_time(); } - /// The primary duty is the period in any switch is active + /// The secondary duty is the period in any switch is active /// /// If less than or equal to the primary duty, the secondary switch will never be active - pub fn set_secondary_duty(&mut self, secondary: u16) { - T::regs().tim(C::raw()).cmp(1).modify(|w| w.set_cmp(secondary)); + /// If a fully complementary output is desired, the secondary duty can be set to the max compare + pub fn set_secondary_duty(&mut self, secondary_duty: u16) { + T::regs().tim(C::raw()).cmp(2).modify(|w| w.set_cmp(secondary_duty)); } } @@ -290,14 +322,14 @@ impl> Bridge /// but does not include secondary rectification, which is appropriate for applications /// with a low-voltage on the secondary side. pub struct ResonantConverter> { - phantom: PhantomData, + timer: PhantomData, + channel: PhantomData, min_period: u16, max_period: u16, - pub ch: C, } impl> ResonantConverter { - pub fn new(channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { + pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { use crate::pac::hrtim::vals::Cont; T::set_channel_frequency(C::raw(), min_frequency); @@ -305,19 +337,30 @@ impl> Resona // Always enable preload T::regs().tim(C::raw()).cr().modify(|w| { w.set_preen(true); + w.set_repu(true); w.set_cont(Cont::CONTINUOUS); w.set_half(true); }); + // Enable timer outputs + T::regs().oenr().modify(|w| { + w.set_t1oen(C::raw(), true); + w.set_t2oen(C::raw(), true); + }); + + // Dead-time generator can be used in this case because the primary fets + // of a resonant converter are always complementary + T::regs().tim(C::raw()).outr().modify(|w| w.set_dten(true)); + let max_period = T::regs().tim(C::raw()).per().read().per(); let min_period = max_period * (min_frequency.0 / max_frequency.0) as u16; Self { + timer: PhantomData, + channel: PhantomData, min_period: min_period, max_period: max_period, - phantom: PhantomData, - ch: channel, } } diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index d09e38d0..429a290e 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -123,7 +123,7 @@ impl From for HighResolutionControlPrescaler { #[cfg(hrtim_v1)] impl HighResolutionControlPrescaler { - pub fn compute_min(val: u32) -> Self { + pub fn compute_min_high_res(val: u32) -> Self { *[ HighResolutionControlPrescaler::Div1, HighResolutionControlPrescaler::Div2, @@ -139,6 +139,18 @@ impl HighResolutionControlPrescaler { .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 { @@ -367,10 +379,14 @@ foreach_interrupt! { let f = frequency.0; let timer_f = Self::frequency().0; let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = HighResolutionControlPrescaler::compute_min(psc_min); + 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 = timer_f / psc_val; + let timer_f = 32 * (timer_f / psc_val); let per: u16 = (timer_f / f) as u16; let regs = Self::regs(); @@ -386,10 +402,14 @@ foreach_interrupt! { let f = frequency.0; let timer_f = Self::frequency().0; let psc_min = (timer_f / f) / (u16::MAX as u32 / 32); - let psc = HighResolutionControlPrescaler::compute_min(psc_min); + 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 = timer_f / psc_val; + let timer_f = 32 * (timer_f / psc_val); let per: u16 = (timer_f / f) as u16; let regs = Self::regs(); @@ -410,7 +430,12 @@ foreach_interrupt! { // 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 = HighResolutionControlPrescaler::compute_min(psc_min); + 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); diff --git a/examples/stm32f334/src/bin/button.rs b/examples/stm32f334/src/bin/button.rs new file mode 100644 index 00000000..599c0f27 --- /dev/null +++ b/examples/stm32f334/src/bin/button.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + info!("Hello World!"); + + let p = embassy_stm32::init(Default::default()); + + let mut out1 = Output::new(p.PA8, Level::Low, Speed::High); + + out1.set_high(); + Timer::after(Duration::from_millis(500)).await; + out1.set_low(); + + Timer::after(Duration::from_millis(500)).await; + info!("end program"); + + cortex_m::asm::bkpt(); +} diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 1b5d509e..36411974 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -5,12 +5,20 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::pwm::advanced_pwm::*; -use embassy_stm32::time::khz; +use embassy_stm32::time::{khz, mhz}; +use embassy_stm32::Config; +use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] async fn main(_spawner: Spawner) { - let p = embassy_stm32::init(Default::default()); + let mut config: Config = Default::default(); + config.rcc.sysclk = Some(mhz(64)); + config.rcc.hclk = Some(mhz(64)); + config.rcc.pclk1 = Some(mhz(32)); + config.rcc.pclk2 = Some(mhz(64)); + + let p = embassy_stm32::init(config); info!("Hello World!"); let ch1 = PwmPin::new_cha(p.PA8); @@ -29,34 +37,35 @@ async fn main(_spawner: Spawner) { None, ); - let mut buck_converter = BridgeConverter::new(pwm.ch_a, khz(100)); + info!("pwm constructed"); - buck_converter.set_primary_duty(0); - buck_converter.set_secondary_duty(0); - buck_converter.set_dead_time(0); + let mut buck_converter = BridgeConverter::new(pwm.ch_a, khz(5)); - // note: if the pins are not passed into the advanced pwm struct, they will not be output - let mut boost_converter = BridgeConverter::new(pwm.ch_b, khz(100)); - - boost_converter.set_primary_duty(0); - boost_converter.set_secondary_duty(0); - - // let max = pwm.get_max_duty(); - // pwm.set_dead_time(max / 1024); + // embassy_stm32::pac::HRTIM1 + // .tim(0) + // .setr(0) + // .modify(|w| w.set_sst(Activeeffect::SETACTIVE)); // - // pwm.enable(Channel::Ch1); + // Timer::after(Duration::from_millis(500)).await; // - // info!("PWM initialized"); - // info!("PWM max duty {}", max); - // - // loop { - // pwm.set_duty(Channel::Ch1, 0); - // Timer::after(Duration::from_millis(300)).await; - // pwm.set_duty(Channel::Ch1, max / 4); - // Timer::after(Duration::from_millis(300)).await; - // pwm.set_duty(Channel::Ch1, max / 2); - // Timer::after(Duration::from_millis(300)).await; - // pwm.set_duty(Channel::Ch1, max - 1); - // Timer::after(Duration::from_millis(300)).await; - // } + // embassy_stm32::pac::HRTIM1 + // .tim(0) + // .rstr(0) + // .modify(|w| w.set_srt(Inactiveeffect::SETINACTIVE)); + + let max_duty = buck_converter.get_max_compare_value(); + + info!("max compare value: {}", max_duty); + + buck_converter.set_dead_time(max_duty / 20); + buck_converter.set_primary_duty(max_duty / 2); + buck_converter.set_secondary_duty(3 * max_duty / 4); + + buck_converter.start(); + + Timer::after(Duration::from_millis(500)).await; + + info!("end program"); + + cortex_m::asm::bkpt(); } From 2e6b813225450828ebeb9908048675db0e843330 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 2 Jul 2023 09:17:12 -0500 Subject: [PATCH 11/17] hrtim: add guardrails on bridge sec. duty --- embassy-stm32/src/pwm/advanced_pwm.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index fa34b2e1..07d8708d 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -177,7 +177,7 @@ impl BurstController { /// Represents a fixed-frequency bridge converter /// -/// Our implementation of the bridge converter uses a single channel and two compare registers, +/// Our implementation of the bridge converter uses a single channel and three compare registers, /// allowing implementation of a synchronous buck or boost converter in continuous or discontinuous /// conduction mode. /// @@ -189,6 +189,8 @@ pub struct BridgeConverter, dead_time: u16, primary_duty: u16, + min_secondary_duty: u16, + max_secondary_duty: u16, } impl> BridgeConverter { @@ -244,6 +246,8 @@ impl> Bridge channel: PhantomData, dead_time: 0, primary_duty: 0, + min_secondary_duty: 0, + max_secondary_duty: 0, } } @@ -280,16 +284,19 @@ impl> Bridge } fn update_primary_duty_or_dead_time(&mut self) { + self.min_secondary_duty = self.primary_duty + self.dead_time; + T::regs().tim(C::raw()).cmp(0).modify(|w| w.set_cmp(self.primary_duty)); T::regs() .tim(C::raw()) .cmp(1) - .modify(|w| w.set_cmp(self.primary_duty + self.dead_time)); + .modify(|w| w.set_cmp(self.min_secondary_duty)); } /// Set the dead time as a proportion of the maximum compare value pub fn set_dead_time(&mut self, dead_time: u16) { self.dead_time = dead_time; + self.max_secondary_duty = self.get_max_compare_value() - dead_time; self.update_primary_duty_or_dead_time(); } @@ -309,9 +316,17 @@ impl> Bridge /// The secondary duty is the period in any switch is active /// - /// If less than or equal to the primary duty, the secondary switch will never be active + /// If less than or equal to the primary duty, the secondary switch will be active for one tick /// If a fully complementary output is desired, the secondary duty can be set to the max compare pub fn set_secondary_duty(&mut self, secondary_duty: u16) { + let secondary_duty = if secondary_duty > self.max_secondary_duty { + self.max_secondary_duty + } else if secondary_duty <= self.min_secondary_duty { + self.min_secondary_duty + 1 + } else { + secondary_duty + }; + T::regs().tim(C::raw()).cmp(2).modify(|w| w.set_cmp(secondary_duty)); } } From 0c49e6747c02e03fc6517969105cfdf20239fc64 Mon Sep 17 00:00:00 2001 From: xoviat Date: Sun, 2 Jul 2023 22:00:50 -0500 Subject: [PATCH 12/17] wip --- embassy-stm32/src/pwm/advanced_pwm.rs | 31 +++++++++++---------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/pwm/advanced_pwm.rs index 07d8708d..9e40c5bf 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/pwm/advanced_pwm.rs @@ -195,7 +195,7 @@ pub struct BridgeConverter> BridgeConverter { pub fn new(_channel: C, frequency: Hertz) -> Self { - use crate::pac::hrtim::vals::{Activeeffect, Cont, Inactiveeffect}; + use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; T::set_channel_frequency(C::raw(), frequency); @@ -203,8 +203,7 @@ impl> Bridge T::regs().tim(C::raw()).cr().modify(|w| { w.set_preen(true); w.set_repu(true); - - w.set_cont(Cont::CONTINUOUS); + w.set_cont(true); }); // Enable timer outputs @@ -260,26 +259,22 @@ impl> Bridge } pub fn enable_burst_mode(&mut self) { - use crate::pac::hrtim::vals::{Idlem, Idles}; - T::regs().tim(C::raw()).outr().modify(|w| { - w.set_idlem(0, Idlem::SETIDLE); - w.set_idlem(1, Idlem::SETIDLE); + // Enable Burst Mode + w.set_idlem(0, true); + w.set_idlem(1, true); - w.set_idles(0, Idles::INACTIVE); - w.set_idles(1, Idles::INACTIVE); + // Set output to active during the burst + w.set_idles(0, true); + w.set_idles(1, true); }) } pub fn disable_burst_mode(&mut self) { - use crate::pac::hrtim::vals::{Idlem, Idles}; - T::regs().tim(C::raw()).outr().modify(|w| { - w.set_idlem(0, Idlem::NOEFFECT); - w.set_idlem(1, Idlem::NOEFFECT); - - w.set_idles(0, Idles::INACTIVE); - w.set_idles(1, Idles::INACTIVE); + // Disable Burst Mode + w.set_idlem(0, false); + w.set_idlem(1, false); }) } @@ -345,8 +340,6 @@ pub struct ResonantConverter> ResonantConverter { pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { - use crate::pac::hrtim::vals::Cont; - T::set_channel_frequency(C::raw(), min_frequency); // Always enable preload @@ -354,7 +347,7 @@ impl> Resona w.set_preen(true); w.set_repu(true); - w.set_cont(Cont::CONTINUOUS); + w.set_cont(true); w.set_half(true); }); From 28136579e98ea4d9745867d7c1ffff0ad826b504 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 28 Jul 2023 17:07:08 -0500 Subject: [PATCH 13/17] stm32/hrtim: extract into mod --- embassy-stm32/build.rs | 20 +++++++++--------- .../src/{pwm/advanced_pwm.rs => hrtim/mod.rs} | 13 +++++++++++- embassy-stm32/src/lib.rs | 9 ++++---- embassy-stm32/src/pwm/mod.rs | 21 ------------------- examples/stm32f334/src/bin/pwm.rs | 2 +- 5 files changed, 28 insertions(+), 37 deletions(-) rename embassy-stm32/src/{pwm/advanced_pwm.rs => hrtim/mod.rs} (94%) diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index d2b1cfd0..c2b84797 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -587,16 +587,16 @@ fn main() { (("timer", "BKIN2"), quote!(crate::pwm::BreakInput2Pin)), (("timer", "BKIN2_COMP1"), quote!(crate::pwm::BreakInput2Comparator1Pin)), (("timer", "BKIN2_COMP2"), quote!(crate::pwm::BreakInput2Comparator2Pin)), - (("hrtim", "CHA1"), quote!(crate::pwm::ChannelAPin)), - (("hrtim", "CHA2"), quote!(crate::pwm::ChannelAComplementaryPin)), - (("hrtim", "CHB1"), quote!(crate::pwm::ChannelBPin)), - (("hrtim", "CHB2"), quote!(crate::pwm::ChannelBComplementaryPin)), - (("hrtim", "CHC1"), quote!(crate::pwm::ChannelCPin)), - (("hrtim", "CHC2"), quote!(crate::pwm::ChannelCComplementaryPin)), - (("hrtim", "CHD1"), quote!(crate::pwm::ChannelDPin)), - (("hrtim", "CHD2"), quote!(crate::pwm::ChannelDComplementaryPin)), - (("hrtim", "CHE1"), quote!(crate::pwm::ChannelEPin)), - (("hrtim", "CHE2"), quote!(crate::pwm::ChannelEComplementaryPin)), + (("hrtim", "CHA1"), quote!(crate::hrtim::ChannelAPin)), + (("hrtim", "CHA2"), quote!(crate::hrtim::ChannelAComplementaryPin)), + (("hrtim", "CHB1"), quote!(crate::hrtim::ChannelBPin)), + (("hrtim", "CHB2"), quote!(crate::hrtim::ChannelBComplementaryPin)), + (("hrtim", "CHC1"), quote!(crate::hrtim::ChannelCPin)), + (("hrtim", "CHC2"), quote!(crate::hrtim::ChannelCComplementaryPin)), + (("hrtim", "CHD1"), quote!(crate::hrtim::ChannelDPin)), + (("hrtim", "CHD2"), quote!(crate::hrtim::ChannelDComplementaryPin)), + (("hrtim", "CHE1"), quote!(crate::hrtim::ChannelEPin)), + (("hrtim", "CHE2"), quote!(crate::hrtim::ChannelEComplementaryPin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), diff --git a/embassy-stm32/src/pwm/advanced_pwm.rs b/embassy-stm32/src/hrtim/mod.rs similarity index 94% rename from embassy-stm32/src/pwm/advanced_pwm.rs rename to embassy-stm32/src/hrtim/mod.rs index 9e40c5bf..7e3a8f14 100644 --- a/embassy-stm32/src/pwm/advanced_pwm.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -2,10 +2,10 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; -use super::*; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::AnyPin; +use crate::pwm::HighResolutionCaptureCompare16bitInstance; use crate::time::Hertz; use crate::Peripheral; @@ -394,3 +394,14 @@ impl> Resona self.max_period } } + +pin_trait!(ChannelAPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelAComplementaryPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelBPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelBComplementaryPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelCPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelCComplementaryPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelDPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelDComplementaryPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelEPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelEComplementaryPin, HighResolutionCaptureCompare16bitInstance); diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 45a7b547..8c005bfe 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -23,6 +23,8 @@ pub mod timer; pub mod adc; #[cfg(can)] pub mod can; +#[cfg(crc)] +pub mod crc; #[cfg(dac)] pub mod dac; #[cfg(dcmi)] @@ -31,14 +33,13 @@ pub mod dcmi; pub mod eth; #[cfg(feature = "exti")] pub mod exti; +pub mod flash; #[cfg(fmc)] pub mod fmc; +#[cfg(hrtim_v1)] +pub mod hrtim; #[cfg(i2c)] pub mod i2c; - -#[cfg(crc)] -pub mod crc; -pub mod flash; #[cfg(all(spi_v1, rcc_f4))] pub mod i2s; #[cfg(stm32wb)] diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 429a290e..c4b38ebd 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -1,5 +1,3 @@ -#[cfg(hrtim_v1)] -pub mod advanced_pwm; pub mod complementary_pwm; pub mod simple_pwm; @@ -468,22 +466,3 @@ pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); - -#[cfg(hrtim_v1)] -mod hrtim_pins { - use super::*; - - pin_trait!(ChannelAPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelAComplementaryPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelBPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelBComplementaryPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelCPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelCComplementaryPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelDPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelDComplementaryPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelEPin, HighResolutionCaptureCompare16bitInstance); - pin_trait!(ChannelEComplementaryPin, HighResolutionCaptureCompare16bitInstance); -} - -#[cfg(hrtim_v1)] -pub use hrtim_pins::*; diff --git a/examples/stm32f334/src/bin/pwm.rs b/examples/stm32f334/src/bin/pwm.rs index 36411974..2660b10c 100644 --- a/examples/stm32f334/src/bin/pwm.rs +++ b/examples/stm32f334/src/bin/pwm.rs @@ -4,7 +4,7 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::pwm::advanced_pwm::*; +use embassy_stm32::hrtim::*; use embassy_stm32::time::{khz, mhz}; use embassy_stm32::Config; use embassy_time::{Duration, Timer}; From e495d606ec62ccfd72eaf9fc868455da217e2d5c Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 28 Jul 2023 17:16:46 -0500 Subject: [PATCH 14/17] stm32/hrtim: extract traits --- embassy-stm32/src/hrtim/mod.rs | 6 +- embassy-stm32/src/hrtim/traits.rs | 196 +++++++++++++++++++++++++++++ embassy-stm32/src/pwm/mod.rs | 199 ------------------------------ 3 files changed, 200 insertions(+), 201 deletions(-) create mode 100644 embassy-stm32/src/hrtim/traits.rs 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); From ec787d3518211a91cbecc4056fde88d7d9eb3a34 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 28 Jul 2023 17:27:15 -0500 Subject: [PATCH 15/17] stm32/hrtim: cleanup merge issues --- embassy-stm32/src/hrtim/mod.rs | 2 +- embassy-stm32/src/hrtim/traits.rs | 12 ++++++++---- embassy-stm32/src/timer/mod.rs | 13 ------------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index ddf8cc2a..3a05719b 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -2,7 +2,7 @@ mod traits; use core::marker::PhantomData; -use embassy_hal_common::{into_ref, PeripheralRef}; +use embassy_hal_internal::{into_ref, PeripheralRef}; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 16193a45..7f2cedda 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -1,3 +1,4 @@ +use crate::rcc::sealed::RccPeripheral; use crate::time::Hertz; #[derive(Clone, Copy)] @@ -92,7 +93,9 @@ impl HighResolutionControlPrescaler { pub(crate) mod sealed { use super::*; - pub trait HighResolutionCaptureCompare16bitInstance: crate::timer::sealed::HighResolutionControlInstance { + pub trait HighResolutionCaptureCompare16bitInstance: RccPeripheral { + fn regs() -> crate::pac::hrtim::Hrtim; + fn set_master_frequency(frequency: Hertz); fn set_channel_frequency(channnel: usize, frequency: Hertz); @@ -114,9 +117,12 @@ pub trait HighResolutionCaptureCompare16bitInstance: foreach_interrupt! { ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { impl sealed::HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { + fn regs() -> crate::pac::hrtim::Hrtim { + crate::pac::$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; @@ -139,7 +145,6 @@ foreach_interrupt! { 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; @@ -161,7 +166,6 @@ foreach_interrupt! { } fn set_channel_dead_time(channel: usize, dead_time: u16) { - use crate::timer::sealed::HighResolutionControlInstance; let regs = Self::regs(); diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 286ab556..6c2d6d82 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -429,17 +429,4 @@ foreach_interrupt! { }; - - ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { - impl sealed::HighResolutionControlInstance for crate::peripherals::$inst { - type Interrupt = crate::interrupt::typelevel::$irq; - - fn regs() -> crate::pac::hrtim::Hrtim { - crate::pac::$inst - } - } - - impl HighResolutionControlInstance for crate::peripherals::$inst { - } - }; } From a8d3bcbb759293f93b7a623910ead15f2cae0a95 Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 28 Jul 2023 17:37:14 -0500 Subject: [PATCH 16/17] stm32/hrtim: shorten names --- embassy-stm32/src/hrtim/mod.rs | 64 ++++++++-------- embassy-stm32/src/hrtim/traits.rs | 119 ++++++++++++++---------------- 2 files changed, 88 insertions(+), 95 deletions(-) diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 3a05719b..9ed03a21 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -7,7 +7,7 @@ use embassy_hal_internal::{into_ref, PeripheralRef}; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::AnyPin; -use crate::hrtim::traits::HighResolutionCaptureCompare16bitInstance; +use crate::hrtim::traits::Instance; use crate::time::Hertz; use crate::Peripheral; @@ -20,37 +20,37 @@ pub enum Source { ChE, } -pub struct BurstController { +pub struct BurstController { phantom: PhantomData, } -pub struct Master { +pub struct Master { phantom: PhantomData, } -pub struct ChA { +pub struct ChA { phantom: PhantomData, } -pub struct ChB { +pub struct ChB { phantom: PhantomData, } -pub struct ChC { +pub struct ChC { phantom: PhantomData, } -pub struct ChD { +pub struct ChD { phantom: PhantomData, } -pub struct ChE { +pub struct ChE { phantom: PhantomData, } mod sealed { - use super::HighResolutionCaptureCompare16bitInstance; + use super::Instance; - pub trait AdvancedChannel { + pub trait AdvancedChannel { fn raw() -> usize; } } -pub trait AdvancedChannel: sealed::AdvancedChannel {} +pub trait AdvancedChannel: sealed::AdvancedChannel {} pub struct PwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, @@ -64,7 +64,7 @@ pub struct ComplementaryPwmPin<'d, Perip, Channel> { macro_rules! advanced_channel_impl { ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { - impl<'d, Perip: HighResolutionCaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { + impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -80,7 +80,7 @@ macro_rules! advanced_channel_impl { } } - impl<'d, Perip: HighResolutionCaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { + impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); critical_section::with(|_| { @@ -96,12 +96,12 @@ macro_rules! advanced_channel_impl { } } - impl sealed::AdvancedChannel for $channel { + impl sealed::AdvancedChannel for $channel { fn raw() -> usize { $ch_num } } - impl AdvancedChannel for $channel {} + impl AdvancedChannel for $channel {} }; } @@ -112,7 +112,7 @@ advanced_channel_impl!(new_chd, ChD, 3, ChannelDPin, ChannelDComplementaryPin); advanced_channel_impl!(new_che, ChE, 4, ChannelEPin, ChannelEComplementaryPin); /// Struct used to divide a high resolution timer into multiple channels -pub struct AdvancedPwm<'d, T: HighResolutionCaptureCompare16bitInstance> { +pub struct AdvancedPwm<'d, T: Instance> { _inner: PeripheralRef<'d, T>, pub master: Master, pub burst_controller: BurstController, @@ -123,7 +123,7 @@ pub struct AdvancedPwm<'d, T: HighResolutionCaptureCompare16bitInstance> { pub ch_e: ChE, } -impl<'d, T: HighResolutionCaptureCompare16bitInstance> AdvancedPwm<'d, T> { +impl<'d, T: Instance> AdvancedPwm<'d, T> { pub fn new( tim: impl Peripheral

+ 'd, _cha: Option>>, @@ -171,7 +171,7 @@ impl<'d, T: HighResolutionCaptureCompare16bitInstance> AdvancedPwm<'d, T> { } } -impl BurstController { +impl BurstController { pub fn set_source(&mut self, _source: Source) { todo!("burst mode control registers not implemented") } @@ -186,7 +186,7 @@ impl BurstController { /// It is important to remember that in synchronous topologies, energy can flow in reverse during /// light loading conditions, and that the low-side switch must be active for a short time to drive /// a bootstrapped high-side switch. -pub struct BridgeConverter> { +pub struct BridgeConverter> { timer: PhantomData, channel: PhantomData, dead_time: u16, @@ -195,7 +195,7 @@ pub struct BridgeConverter> BridgeConverter { +impl> BridgeConverter { pub fn new(_channel: C, frequency: Hertz) -> Self { use crate::pac::hrtim::vals::{Activeeffect, Inactiveeffect}; @@ -333,14 +333,14 @@ impl> Bridge /// This implementation of a resonsant converter is appropriate for a half or full bridge, /// but does not include secondary rectification, which is appropriate for applications /// with a low-voltage on the secondary side. -pub struct ResonantConverter> { +pub struct ResonantConverter> { timer: PhantomData, channel: PhantomData, min_period: u16, max_period: u16, } -impl> ResonantConverter { +impl> ResonantConverter { pub fn new(_channel: C, min_frequency: Hertz, max_frequency: Hertz) -> Self { T::set_channel_frequency(C::raw(), min_frequency); @@ -397,13 +397,13 @@ impl> Resona } } -pin_trait!(ChannelAPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelAComplementaryPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelBPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelBComplementaryPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelCPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelCComplementaryPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelDPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelDComplementaryPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelEPin, HighResolutionCaptureCompare16bitInstance); -pin_trait!(ChannelEComplementaryPin, HighResolutionCaptureCompare16bitInstance); +pin_trait!(ChannelAPin, Instance); +pin_trait!(ChannelAComplementaryPin, Instance); +pin_trait!(ChannelBPin, Instance); +pin_trait!(ChannelBComplementaryPin, Instance); +pin_trait!(ChannelCPin, Instance); +pin_trait!(ChannelCComplementaryPin, Instance); +pin_trait!(ChannelDPin, Instance); +pin_trait!(ChannelDComplementaryPin, Instance); +pin_trait!(ChannelEPin, Instance); +pin_trait!(ChannelEComplementaryPin, Instance); diff --git a/embassy-stm32/src/hrtim/traits.rs b/embassy-stm32/src/hrtim/traits.rs index 7f2cedda..158a6886 100644 --- a/embassy-stm32/src/hrtim/traits.rs +++ b/embassy-stm32/src/hrtim/traits.rs @@ -2,7 +2,7 @@ use crate::rcc::sealed::RccPeripheral; use crate::time::Hertz; #[derive(Clone, Copy)] -pub(crate) enum HighResolutionControlPrescaler { +pub(crate) enum Prescaler { Div1, Div2, Div4, @@ -13,87 +13,83 @@ pub(crate) enum HighResolutionControlPrescaler { Div128, } -impl From for u32 { - fn from(val: HighResolutionControlPrescaler) -> Self { +impl From for u32 { + fn from(val: Prescaler) -> 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, + Prescaler::Div1 => 1, + Prescaler::Div2 => 2, + Prescaler::Div4 => 4, + Prescaler::Div8 => 8, + Prescaler::Div16 => 16, + Prescaler::Div32 => 32, + Prescaler::Div64 => 64, + Prescaler::Div128 => 128, } } } -impl From for u8 { - fn from(val: HighResolutionControlPrescaler) -> Self { +impl From for u8 { + fn from(val: Prescaler) -> 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, + Prescaler::Div1 => 0b000, + Prescaler::Div2 => 0b001, + Prescaler::Div4 => 0b010, + Prescaler::Div8 => 0b011, + Prescaler::Div16 => 0b100, + Prescaler::Div32 => 0b101, + Prescaler::Div64 => 0b110, + Prescaler::Div128 => 0b111, } } } -impl From for HighResolutionControlPrescaler { +impl From for Prescaler { 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, + 0b000 => Prescaler::Div1, + 0b001 => Prescaler::Div2, + 0b010 => Prescaler::Div4, + 0b011 => Prescaler::Div8, + 0b100 => Prescaler::Div16, + 0b101 => Prescaler::Div32, + 0b110 => Prescaler::Div64, + 0b111 => Prescaler::Div128, _ => unreachable!(), } } } -impl HighResolutionControlPrescaler { +impl Prescaler { 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, + Prescaler::Div1, + Prescaler::Div2, + Prescaler::Div4, + Prescaler::Div8, + Prescaler::Div16, + Prescaler::Div32, + Prescaler::Div64, + Prescaler::Div128, ] .iter() - .skip_while(|psc| >::into(**psc) <= val) + .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() + *[Prescaler::Div32, Prescaler::Div64, Prescaler::Div128] + .iter() + .skip_while(|psc| >::into(**psc) <= val) + .next() + .unwrap() } } pub(crate) mod sealed { use super::*; - pub trait HighResolutionCaptureCompare16bitInstance: RccPeripheral { + pub trait Instance: RccPeripheral { fn regs() -> crate::pac::hrtim::Hrtim; fn set_master_frequency(frequency: Hertz); @@ -109,14 +105,11 @@ pub(crate) mod sealed { } } -pub trait HighResolutionCaptureCompare16bitInstance: - sealed::HighResolutionCaptureCompare16bitInstance + 'static -{ -} +pub trait Instance: sealed::Instance + 'static {} foreach_interrupt! { ($inst:ident, hrtim, HRTIM, MASTER, $irq:ident) => { - impl sealed::HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { + impl sealed::Instance for crate::peripherals::$inst { fn regs() -> crate::pac::hrtim::Hrtim { crate::pac::$inst } @@ -128,9 +121,9 @@ foreach_interrupt! { 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) + Prescaler::compute_min_high_res(psc_min) } else { - HighResolutionControlPrescaler::compute_min_low_res(psc_min) + Prescaler::compute_min_low_res(psc_min) }; let psc_val: u32 = psc.into(); @@ -150,9 +143,9 @@ foreach_interrupt! { 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) + Prescaler::compute_min_high_res(psc_min) } else { - HighResolutionControlPrescaler::compute_min_low_res(psc_min) + Prescaler::compute_min_low_res(psc_min) }; let psc_val: u32 = psc.into(); @@ -169,7 +162,7 @@ foreach_interrupt! { let regs = Self::regs(); - let channel_psc: HighResolutionControlPrescaler = regs.tim(channel).cr().read().ckpsc().into(); + let channel_psc: Prescaler = regs.tim(channel).cr().read().ckpsc().into(); let psc_val: u32 = channel_psc.into(); @@ -177,9 +170,9 @@ foreach_interrupt! { // 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) + Prescaler::compute_min_high_res(psc_min) } else { - HighResolutionControlPrescaler::compute_min_low_res(psc_min) + Prescaler::compute_min_low_res(psc_min) }; let dt_psc_val: u32 = psc.into(); @@ -193,7 +186,7 @@ foreach_interrupt! { } } - impl HighResolutionCaptureCompare16bitInstance for crate::peripherals::$inst { + impl Instance for crate::peripherals::$inst { } }; From 5bb5654d847b8d7a15f242d4b4078369a1b7285f Mon Sep 17 00:00:00 2001 From: xoviat Date: Fri, 28 Jul 2023 17:39:01 -0500 Subject: [PATCH 17/17] stm32/hrtim: pub instance --- embassy-stm32/src/hrtim/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs index 9ed03a21..a930ff73 100644 --- a/embassy-stm32/src/hrtim/mod.rs +++ b/embassy-stm32/src/hrtim/mod.rs @@ -3,11 +3,11 @@ mod traits; use core::marker::PhantomData; use embassy_hal_internal::{into_ref, PeripheralRef}; +pub use traits::Instance; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; use crate::gpio::AnyPin; -use crate::hrtim::traits::Instance; use crate::time::Hertz; use crate::Peripheral;