From 348019e37f0ff5716d80199e33244c0a1a59b360 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 27 Jun 2023 18:24:32 -0500 Subject: [PATCH] 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 a08952248..c7b5f7482 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 1838bfdfe..67009e788 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 03b9b3cf8..89cb16668 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 {