From 3690af9bea5968653780d296146a91c63994d89d Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 28 Jul 2023 15:29:27 +0200 Subject: stm32/timer: merge pwm module into timer. (#1703) The traits there are applicable to timer use cases other than PWM. It doesn't make sense to keep them separated. --- embassy-stm32/build.rs | 30 +-- embassy-stm32/src/lib.rs | 1 - embassy-stm32/src/pwm/complementary_pwm.rs | 250 ---------------------- embassy-stm32/src/pwm/mod.rs | 269 ----------------------- embassy-stm32/src/pwm/simple_pwm.rs | 107 ---------- embassy-stm32/src/timer/complementary_pwm.rs | 250 ++++++++++++++++++++++ embassy-stm32/src/timer/mod.rs | 271 +++++++++++++++++++++--- embassy-stm32/src/timer/simple_pwm.rs | 107 ++++++++++ examples/stm32f4/src/bin/pwm.rs | 4 +- examples/stm32f4/src/bin/pwm_complementary.rs | 6 +- examples/stm32g4/src/bin/pwm.rs | 4 +- examples/stm32h7/src/bin/low_level_timer_api.rs | 2 +- examples/stm32h7/src/bin/pwm.rs | 4 +- 13 files changed, 628 insertions(+), 677 deletions(-) delete mode 100644 embassy-stm32/src/pwm/complementary_pwm.rs delete mode 100644 embassy-stm32/src/pwm/mod.rs delete mode 100644 embassy-stm32/src/pwm/simple_pwm.rs create mode 100644 embassy-stm32/src/timer/complementary_pwm.rs create mode 100644 embassy-stm32/src/timer/simple_pwm.rs diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 0e9606ec3..409a943d2 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -572,21 +572,21 @@ fn main() { (("fmc", "Clk"), quote!(crate::fmc::ClkPin)), (("fmc", "BA0"), quote!(crate::fmc::BA0Pin)), (("fmc", "BA1"), quote!(crate::fmc::BA1Pin)), - (("timer", "CH1"), quote!(crate::pwm::Channel1Pin)), - (("timer", "CH1N"), quote!(crate::pwm::Channel1ComplementaryPin)), - (("timer", "CH2"), quote!(crate::pwm::Channel2Pin)), - (("timer", "CH2N"), quote!(crate::pwm::Channel2ComplementaryPin)), - (("timer", "CH3"), quote!(crate::pwm::Channel3Pin)), - (("timer", "CH3N"), quote!(crate::pwm::Channel3ComplementaryPin)), - (("timer", "CH4"), quote!(crate::pwm::Channel4Pin)), - (("timer", "CH4N"), quote!(crate::pwm::Channel4ComplementaryPin)), - (("timer", "ETR"), quote!(crate::pwm::ExternalTriggerPin)), - (("timer", "BKIN"), quote!(crate::pwm::BreakInputPin)), - (("timer", "BKIN_COMP1"), quote!(crate::pwm::BreakInputComparator1Pin)), - (("timer", "BKIN_COMP2"), quote!(crate::pwm::BreakInputComparator2Pin)), - (("timer", "BKIN2"), quote!(crate::pwm::BreakInput2Pin)), - (("timer", "BKIN2_COMP1"), quote!(crate::pwm::BreakInput2Comparator1Pin)), - (("timer", "BKIN2_COMP2"), quote!(crate::pwm::BreakInput2Comparator2Pin)), + (("timer", "CH1"), quote!(crate::timer::Channel1Pin)), + (("timer", "CH1N"), quote!(crate::timer::Channel1ComplementaryPin)), + (("timer", "CH2"), quote!(crate::timer::Channel2Pin)), + (("timer", "CH2N"), quote!(crate::timer::Channel2ComplementaryPin)), + (("timer", "CH3"), quote!(crate::timer::Channel3Pin)), + (("timer", "CH3N"), quote!(crate::timer::Channel3ComplementaryPin)), + (("timer", "CH4"), quote!(crate::timer::Channel4Pin)), + (("timer", "CH4N"), quote!(crate::timer::Channel4ComplementaryPin)), + (("timer", "ETR"), quote!(crate::timer::ExternalTriggerPin)), + (("timer", "BKIN"), quote!(crate::timer::BreakInputPin)), + (("timer", "BKIN_COMP1"), quote!(crate::timer::BreakInputComparator1Pin)), + (("timer", "BKIN_COMP2"), quote!(crate::timer::BreakInputComparator2Pin)), + (("timer", "BKIN2"), quote!(crate::timer::BreakInput2Pin)), + (("timer", "BKIN2_COMP1"), quote!(crate::timer::BreakInput2Comparator1Pin)), + (("timer", "BKIN2_COMP2"), quote!(crate::timer::BreakInput2Comparator2Pin)), (("sdmmc", "CK"), quote!(crate::sdmmc::CkPin)), (("sdmmc", "CMD"), quote!(crate::sdmmc::CmdPin)), (("sdmmc", "D0"), quote!(crate::sdmmc::D0Pin)), diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index ebd0e7cd5..bb2ef2fc0 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -43,7 +43,6 @@ pub mod flash; pub mod i2s; #[cfg(stm32wb)] pub mod ipcc; -pub mod pwm; #[cfg(quadspi)] pub mod qspi; #[cfg(rng)] diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs deleted file mode 100644 index 64bb32c39..000000000 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ /dev/null @@ -1,250 +0,0 @@ -use core::marker::PhantomData; - -use embassy_hal_internal::{into_ref, PeripheralRef}; -use stm32_metapac::timer::vals::Ckd; - -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; - -pub struct ComplementaryPwmPin<'d, Perip, Channel> { - _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, -} - -macro_rules! complementary_channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => { - impl<'d, Perip: CaptureCompare16bitInstance> 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, - } - } - } - }; -} - -complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); -complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); -complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); -complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); - -pub struct ComplementaryPwm<'d, T> { - inner: PeripheralRef<'d, T>, -} - -impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'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: Channel) { - self.inner.enable_channel(channel, true); - self.inner.enable_complementary_channel(channel, true); - } - - pub fn disable(&mut self, channel: Channel) { - 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 { - self.inner.get_max_compare_value() - } - - pub fn set_duty(&mut self, channel: Channel, 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); - } -} - -fn compute_dead_time_value(value: u16) -> (Ckd, u8) { - /* - Dead-time = T_clk * T_dts * T_dtg - - T_dts: - This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the - dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters - (ETR, TIx), - 00: tDTS=tCK_INT - 01: tDTS=2*tCK_INT - 10: tDTS=4*tCK_INT - - T_dtg: - This bit-field defines the duration of the dead-time inserted between the complementary - outputs. DT correspond to this duration. - DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS. - DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS. - DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS. - DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS. - Example if TDTS=125ns (8MHz), dead-time possible values are: - 0 to 15875 ns by 125 ns steps, - 16 us to 31750 ns by 250 ns steps, - 32 us to 63us by 1 us steps, - 64 us to 126 us by 2 us steps - */ - - let mut error = u16::MAX; - let mut ckd = Ckd::DIV1; - let mut bits = 0u8; - - for this_ckd in [Ckd::DIV1, Ckd::DIV2, Ckd::DIV4] { - let outdiv = match this_ckd { - Ckd::DIV1 => 1, - Ckd::DIV2 => 2, - Ckd::DIV4 => 4, - _ => unreachable!(), - }; - - // 127 - // 128 - // .. - // 254 - // 256 - // .. - // 504 - // 512 - // .. - // 1008 - - let target = value / outdiv; - let (these_bits, result) = if target < 128 { - (target as u8, target) - } else if target < 255 { - (64 + (target / 2) as u8, (target - target % 2)) - } else if target < 508 { - (32 + (target / 8) as u8, (target - target % 8)) - } else if target < 1008 { - (32 + (target / 16) as u8, (target - target % 16)) - } else { - (u8::MAX, 1008) - }; - - let this_error = value.abs_diff(result * outdiv); - if error > this_error { - ckd = this_ckd; - bits = these_bits; - error = this_error; - } - - match error { - 0 => break, - _ => {} - } - } - - (ckd, bits) -} - -#[cfg(test)] -mod tests { - use super::{compute_dead_time_value, Ckd}; - - #[test] - fn test_compute_dead_time_value() { - struct TestRun { - value: u16, - ckd: Ckd, - bits: u8, - } - - let fn_results = [ - TestRun { - value: 1, - ckd: Ckd::DIV1, - bits: 1, - }, - TestRun { - value: 125, - ckd: Ckd::DIV1, - bits: 125, - }, - TestRun { - value: 245, - ckd: Ckd::DIV1, - bits: 64 + 245 / 2, - }, - TestRun { - value: 255, - ckd: Ckd::DIV2, - bits: 127, - }, - TestRun { - value: 400, - ckd: Ckd::DIV1, - bits: 32 + (400u16 / 8) as u8, - }, - TestRun { - value: 600, - ckd: Ckd::DIV4, - bits: 64 + (600u16 / 8) as u8, - }, - ]; - - for test_run in fn_results { - let (ckd, bits) = compute_dead_time_value(test_run.value); - - assert_eq!(ckd.to_bits(), test_run.ckd.to_bits()); - assert_eq!(bits, test_run.bits); - } - } -} diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs deleted file mode 100644 index 5aba2663e..000000000 --- a/embassy-stm32/src/pwm/mod.rs +++ /dev/null @@ -1,269 +0,0 @@ -pub mod complementary_pwm; -pub mod simple_pwm; - -use stm32_metapac::timer::vals::Ckd; - -#[cfg(feature = "unstable-pac")] -pub mod low_level { - pub use super::sealed::*; -} - -#[derive(Clone, Copy)] -pub enum Channel { - Ch1, - Ch2, - Ch3, - Ch4, -} - -impl Channel { - pub fn raw(&self) -> usize { - match self { - Channel::Ch1 => 0, - Channel::Ch2 => 1, - Channel::Ch3 => 2, - Channel::Ch4 => 3, - } - } -} - -#[derive(Clone, Copy)] -pub enum OutputCompareMode { - Frozen, - ActiveOnMatch, - InactiveOnMatch, - Toggle, - ForceInactive, - ForceActive, - PwmMode1, - PwmMode2, -} - -impl From for stm32_metapac::timer::vals::Ocm { - fn from(mode: OutputCompareMode) -> Self { - match mode { - OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, - OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, - OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, - OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, - OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, - OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, - OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, - OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, - } - } -} - -pub(crate) mod sealed { - use super::*; - - 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); - - fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); - - fn enable_channel(&mut self, channel: Channel, enable: bool); - - fn set_compare_value(&mut self, channel: Channel, value: u16); - - fn get_max_compare_value(&self) -> u16; - } - - pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { - fn set_dead_time_clock_division(&mut self, value: Ckd); - - fn set_dead_time_value(&mut self, value: u8); - - fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); - } - - pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { - fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); - - fn enable_channel(&mut self, channel: Channel, enable: bool); - - fn set_compare_value(&mut self, channel: Channel, value: u32); - - fn get_max_compare_value(&self) -> u32; - } -} - -pub trait CaptureCompare16bitInstance: - sealed::CaptureCompare16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static -{ -} - -pub trait ComplementaryCaptureCompare16bitInstance: - sealed::ComplementaryCaptureCompare16bitInstance + crate::timer::AdvancedControlInstance + 'static -{ -} - -pub trait CaptureCompare32bitInstance: - sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + crate::timer::GeneralPurpose32bitInstance + 'static -{ -} - -#[allow(unused)] -macro_rules! impl_compare_capable_16bit { - ($inst:ident) => { - impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { - fn enable_outputs(&mut self, _enable: bool) {} - - fn set_output_compare_mode(&mut self, channel: crate::pwm::Channel, mode: OutputCompareMode) { - use crate::timer::sealed::GeneralPurpose16bitInstance; - let r = Self::regs_gp16(); - let raw_channel: usize = channel.raw(); - r.ccmr_output(raw_channel / 2) - .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - fn enable_channel(&mut self, channel: Channel, enable: bool) { - use crate::timer::sealed::GeneralPurpose16bitInstance; - Self::regs_gp16() - .ccer() - .modify(|w| w.set_cce(channel.raw(), enable)); - } - - fn set_compare_value(&mut self, channel: Channel, value: u16) { - use crate::timer::sealed::GeneralPurpose16bitInstance; - Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); - } - - fn get_max_compare_value(&self) -> u16 { - use crate::timer::sealed::GeneralPurpose16bitInstance; - Self::regs_gp16().arr().read().arr() - } - } - }; -} - -foreach_interrupt! { - ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { - impl_compare_capable_16bit!($inst); - - impl CaptureCompare16bitInstance for crate::peripherals::$inst { - - } - }; - - ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { - impl_compare_capable_16bit!($inst); - impl crate::pwm::sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { - fn set_output_compare_mode( - &mut self, - channel: crate::pwm::Channel, - mode: OutputCompareMode, - ) { - use crate::timer::sealed::GeneralPurpose32bitInstance; - let raw_channel = channel.raw(); - Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - fn enable_channel(&mut self, channel: Channel, enable: bool) { - use crate::timer::sealed::GeneralPurpose32bitInstance; - Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); - } - - fn set_compare_value(&mut self, channel: Channel, value: u32) { - use crate::timer::sealed::GeneralPurpose32bitInstance; - Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); - } - - fn get_max_compare_value(&self) -> u32 { - use crate::timer::sealed::GeneralPurpose32bitInstance; - Self::regs_gp32().arr().read().arr() as u32 - } - } - impl CaptureCompare16bitInstance for crate::peripherals::$inst { - - } - impl CaptureCompare32bitInstance for crate::peripherals::$inst { - - } - }; - - ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { - impl crate::pwm::sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { - fn enable_outputs(&mut self, enable: bool) { - use crate::timer::sealed::AdvancedControlInstance; - let r = Self::regs_advanced(); - r.bdtr().modify(|w| w.set_moe(enable)); - } - - fn set_output_compare_mode( - &mut self, - channel: crate::pwm::Channel, - mode: OutputCompareMode, - ) { - use crate::timer::sealed::AdvancedControlInstance; - let r = Self::regs_advanced(); - let raw_channel: usize = channel.raw(); - r.ccmr_output(raw_channel / 2) - .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); - } - - fn enable_channel(&mut self, channel: Channel, enable: bool) { - use crate::timer::sealed::AdvancedControlInstance; - Self::regs_advanced() - .ccer() - .modify(|w| w.set_cce(channel.raw(), enable)); - } - - fn set_compare_value(&mut self, channel: Channel, value: u16) { - use crate::timer::sealed::AdvancedControlInstance; - Self::regs_advanced() - .ccr(channel.raw()) - .modify(|w| w.set_ccr(value)); - } - - fn get_max_compare_value(&self) -> u16 { - use crate::timer::sealed::AdvancedControlInstance; - Self::regs_advanced().arr().read().arr() - } - } - - impl CaptureCompare16bitInstance for crate::peripherals::$inst { - - } - - impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { - fn set_dead_time_clock_division(&mut self, value: Ckd) { - use crate::timer::sealed::AdvancedControlInstance; - Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); - } - - fn set_dead_time_value(&mut self, value: u8) { - use crate::timer::sealed::AdvancedControlInstance; - Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); - } - - fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { - use crate::timer::sealed::AdvancedControlInstance; - Self::regs_advanced() - .ccer() - .modify(|w| w.set_ccne(channel.raw(), enable)); - } - } - - impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { - - } - }; -} - -pin_trait!(Channel1Pin, CaptureCompare16bitInstance); -pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(Channel2Pin, CaptureCompare16bitInstance); -pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(Channel3Pin, CaptureCompare16bitInstance); -pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(Channel4Pin, CaptureCompare16bitInstance); -pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance); -pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); -pin_trait!(BreakInputPin, CaptureCompare16bitInstance); -pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); -pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); diff --git a/embassy-stm32/src/pwm/simple_pwm.rs b/embassy-stm32/src/pwm/simple_pwm.rs deleted file mode 100644 index 514796930..000000000 --- a/embassy-stm32/src/pwm/simple_pwm.rs +++ /dev/null @@ -1,107 +0,0 @@ -use core::marker::PhantomData; - -use embassy_hal_internal::{into_ref, PeripheralRef}; - -use super::*; -#[allow(unused_imports)] -use crate::gpio::sealed::{AFType, Pin}; -use crate::gpio::AnyPin; -use crate::time::Hertz; -use crate::Peripheral; - -pub struct Ch1; -pub struct Ch2; -pub struct Ch3; -pub struct Ch4; - -pub struct PwmPin<'d, Perip, Channel> { - _pin: PeripheralRef<'d, AnyPin>, - phantom: PhantomData<(Perip, Channel)>, -} - -macro_rules! channel_impl { - ($new_chx:ident, $channel:ident, $pin_trait:ident) => { - impl<'d, Perip: CaptureCompare16bitInstance> 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, - } - } - } - }; -} - -channel_impl!(new_ch1, Ch1, Channel1Pin); -channel_impl!(new_ch2, Ch2, Channel2Pin); -channel_impl!(new_ch3, Ch3, Channel3Pin); -channel_impl!(new_ch4, Ch4, Channel4Pin); - -pub struct SimplePwm<'d, T> { - inner: PeripheralRef<'d, T>, -} - -impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { - pub fn new( - tim: impl Peripheral

+ 'd, - _ch1: Option>, - _ch2: Option>, - _ch3: Option>, - _ch4: 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: Channel) { - self.inner.enable_channel(channel, true); - } - - pub fn disable(&mut self, channel: Channel) { - 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 { - self.inner.get_max_compare_value() - } - - pub fn set_duty(&mut self, channel: Channel, duty: u16) { - assert!(duty < self.get_max_duty()); - self.inner.set_compare_value(channel, duty) - } -} diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs new file mode 100644 index 000000000..64bb32c39 --- /dev/null +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -0,0 +1,250 @@ +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; +use stm32_metapac::timer::vals::Ckd; + +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; + +pub struct ComplementaryPwmPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, +} + +macro_rules! complementary_channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => { + impl<'d, Perip: CaptureCompare16bitInstance> 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, + } + } + } + }; +} + +complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); +complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); +complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); +complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); + +pub struct ComplementaryPwm<'d, T> { + inner: PeripheralRef<'d, T>, +} + +impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'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: Channel) { + self.inner.enable_channel(channel, true); + self.inner.enable_complementary_channel(channel, true); + } + + pub fn disable(&mut self, channel: Channel) { + 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 { + self.inner.get_max_compare_value() + } + + pub fn set_duty(&mut self, channel: Channel, 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); + } +} + +fn compute_dead_time_value(value: u16) -> (Ckd, u8) { + /* + Dead-time = T_clk * T_dts * T_dtg + + T_dts: + This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the + dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters + (ETR, TIx), + 00: tDTS=tCK_INT + 01: tDTS=2*tCK_INT + 10: tDTS=4*tCK_INT + + T_dtg: + This bit-field defines the duration of the dead-time inserted between the complementary + outputs. DT correspond to this duration. + DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS. + DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS. + DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS. + DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS. + Example if TDTS=125ns (8MHz), dead-time possible values are: + 0 to 15875 ns by 125 ns steps, + 16 us to 31750 ns by 250 ns steps, + 32 us to 63us by 1 us steps, + 64 us to 126 us by 2 us steps + */ + + let mut error = u16::MAX; + let mut ckd = Ckd::DIV1; + let mut bits = 0u8; + + for this_ckd in [Ckd::DIV1, Ckd::DIV2, Ckd::DIV4] { + let outdiv = match this_ckd { + Ckd::DIV1 => 1, + Ckd::DIV2 => 2, + Ckd::DIV4 => 4, + _ => unreachable!(), + }; + + // 127 + // 128 + // .. + // 254 + // 256 + // .. + // 504 + // 512 + // .. + // 1008 + + let target = value / outdiv; + let (these_bits, result) = if target < 128 { + (target as u8, target) + } else if target < 255 { + (64 + (target / 2) as u8, (target - target % 2)) + } else if target < 508 { + (32 + (target / 8) as u8, (target - target % 8)) + } else if target < 1008 { + (32 + (target / 16) as u8, (target - target % 16)) + } else { + (u8::MAX, 1008) + }; + + let this_error = value.abs_diff(result * outdiv); + if error > this_error { + ckd = this_ckd; + bits = these_bits; + error = this_error; + } + + match error { + 0 => break, + _ => {} + } + } + + (ckd, bits) +} + +#[cfg(test)] +mod tests { + use super::{compute_dead_time_value, Ckd}; + + #[test] + fn test_compute_dead_time_value() { + struct TestRun { + value: u16, + ckd: Ckd, + bits: u8, + } + + let fn_results = [ + TestRun { + value: 1, + ckd: Ckd::DIV1, + bits: 1, + }, + TestRun { + value: 125, + ckd: Ckd::DIV1, + bits: 125, + }, + TestRun { + value: 245, + ckd: Ckd::DIV1, + bits: 64 + 245 / 2, + }, + TestRun { + value: 255, + ckd: Ckd::DIV2, + bits: 127, + }, + TestRun { + value: 400, + ckd: Ckd::DIV1, + bits: 32 + (400u16 / 8) as u8, + }, + TestRun { + value: 600, + ckd: Ckd::DIV4, + bits: 64 + (600u16 / 8) as u8, + }, + ]; + + for test_run in fn_results { + let (ckd, bits) = compute_dead_time_value(test_run.value); + + assert_eq!(ckd.to_bits(), test_run.ckd.to_bits()); + assert_eq!(bits, test_run.bits); + } + } +} diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 09b7a3776..6c2d6d827 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs @@ -1,3 +1,6 @@ +pub mod complementary_pwm; +pub mod simple_pwm; + use stm32_metapac::timer::vals; use crate::interrupt; @@ -43,15 +46,123 @@ pub(crate) mod sealed { pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { fn regs_advanced() -> crate::pac::timer::TimAdv; } + + pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { + /// Global output enable. Does not do anything on non-advanced timers. + fn enable_outputs(&mut self, enable: bool); + + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); + + fn enable_channel(&mut self, channel: Channel, enable: bool); + + fn set_compare_value(&mut self, channel: Channel, value: u16); + + fn get_max_compare_value(&self) -> u16; + } + + pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { + fn set_dead_time_clock_division(&mut self, value: vals::Ckd); + + fn set_dead_time_value(&mut self, value: u8); + + fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); + } + + pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); + + fn enable_channel(&mut self, channel: Channel, enable: bool); + + fn set_compare_value(&mut self, channel: Channel, value: u32); + + fn get_max_compare_value(&self) -> u32; + } +} + +#[derive(Clone, Copy)] +pub enum Channel { + Ch1, + Ch2, + Ch3, + Ch4, } +impl Channel { + pub fn raw(&self) -> usize { + match self { + Channel::Ch1 => 0, + Channel::Ch2 => 1, + Channel::Ch3 => 2, + Channel::Ch4 => 3, + } + } +} + +#[derive(Clone, Copy)] +pub enum OutputCompareMode { + Frozen, + ActiveOnMatch, + InactiveOnMatch, + Toggle, + ForceInactive, + ForceActive, + PwmMode1, + PwmMode2, +} + +impl From for stm32_metapac::timer::vals::Ocm { + fn from(mode: OutputCompareMode) -> Self { + match mode { + OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, + OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, + OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, + OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, + OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, + OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, + OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, + OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, + } + } +} + +pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} + pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} -pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} +pub trait CaptureCompare16bitInstance: + sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static +{ +} + +pub trait ComplementaryCaptureCompare16bitInstance: + sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static +{ +} + +pub trait CaptureCompare32bitInstance: + sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static +{ +} + +pin_trait!(Channel1Pin, CaptureCompare16bitInstance); +pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance); +pin_trait!(Channel2Pin, CaptureCompare16bitInstance); +pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance); +pin_trait!(Channel3Pin, CaptureCompare16bitInstance); +pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance); +pin_trait!(Channel4Pin, CaptureCompare16bitInstance); +pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance); +pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); +pin_trait!(BreakInputPin, CaptureCompare16bitInstance); +pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance); +pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); +pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); +pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); +pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); #[allow(unused)] macro_rules! impl_basic_16bit_timer { @@ -140,33 +251,94 @@ macro_rules! impl_32bit_timer { }; } +#[allow(unused)] +macro_rules! impl_compare_capable_16bit { + ($inst:ident) => { + impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn enable_outputs(&mut self, _enable: bool) {} + + fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { + use sealed::GeneralPurpose16bitInstance; + let r = Self::regs_gp16(); + let raw_channel: usize = channel.raw(); + r.ccmr_output(raw_channel / 2) + .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + fn enable_channel(&mut self, channel: Channel, enable: bool) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16() + .ccer() + .modify(|w| w.set_cce(channel.raw(), enable)); + } + + fn set_compare_value(&mut self, channel: Channel, value: u16) { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); + } + + fn get_max_compare_value(&self) -> u16 { + use sealed::GeneralPurpose16bitInstance; + Self::regs_gp16().arr().read().arr() + } + } + }; +} + foreach_interrupt! { ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { impl_basic_16bit_timer!($inst, $irq); - - impl Basic16bitInstance for crate::peripherals::$inst { - } + impl Basic16bitInstance for crate::peripherals::$inst {} }; ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { impl_basic_16bit_timer!($inst, $irq); - - impl Basic16bitInstance for crate::peripherals::$inst { - } + impl_compare_capable_16bit!($inst); + impl Basic16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { fn regs_gp16() -> crate::pac::timer::TimGp16 { crate::pac::$inst } } - - impl GeneralPurpose16bitInstance for crate::peripherals::$inst { - } }; ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { impl_basic_16bit_timer!($inst, $irq); + impl_32bit_timer!($inst); + impl_compare_capable_16bit!($inst); + impl Basic16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare32bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} + + impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { + fn set_output_compare_mode( + &mut self, + channel: Channel, + mode: OutputCompareMode, + ) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + let raw_channel = channel.raw(); + Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + fn enable_channel(&mut self, channel: Channel, enable: bool) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); + } - impl Basic16bitInstance for crate::peripherals::$inst { + fn set_compare_value(&mut self, channel: Channel, value: u32) { + use crate::timer::sealed::GeneralPurpose32bitInstance; + Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); + } + + fn get_max_compare_value(&self) -> u32 { + use crate::timer::sealed::GeneralPurpose32bitInstance; + Self::regs_gp32().arr().read().arr() as u32 + } } impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { @@ -174,21 +346,16 @@ foreach_interrupt! { unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } } } - - impl GeneralPurpose16bitInstance for crate::peripherals::$inst { - } - - impl_32bit_timer!($inst); - - impl GeneralPurpose32bitInstance for crate::peripherals::$inst { - } }; ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { impl_basic_16bit_timer!($inst, $irq); - impl Basic16bitInstance for crate::peripherals::$inst { - } + impl Basic16bitInstance for crate::peripherals::$inst {} + impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} + impl CaptureCompare16bitInstance for crate::peripherals::$inst {} + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} + impl AdvancedControlInstance for crate::peripherals::$inst {} impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { fn regs_gp16() -> crate::pac::timer::TimGp16 { @@ -196,16 +363,70 @@ foreach_interrupt! { } } - impl GeneralPurpose16bitInstance for crate::peripherals::$inst { - } - impl sealed::AdvancedControlInstance for crate::peripherals::$inst { fn regs_advanced() -> crate::pac::timer::TimAdv { crate::pac::$inst } } - impl AdvancedControlInstance for crate::peripherals::$inst { + impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { + fn enable_outputs(&mut self, enable: bool) { + use crate::timer::sealed::AdvancedControlInstance; + let r = Self::regs_advanced(); + r.bdtr().modify(|w| w.set_moe(enable)); + } + + fn set_output_compare_mode( + &mut self, + channel: Channel, + mode: OutputCompareMode, + ) { + use crate::timer::sealed::AdvancedControlInstance; + let r = Self::regs_advanced(); + let raw_channel: usize = channel.raw(); + r.ccmr_output(raw_channel / 2) + .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); + } + + fn enable_channel(&mut self, channel: Channel, enable: bool) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .ccer() + .modify(|w| w.set_cce(channel.raw(), enable)); + } + + fn set_compare_value(&mut self, channel: Channel, value: u16) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .ccr(channel.raw()) + .modify(|w| w.set_ccr(value)); + } + + fn get_max_compare_value(&self) -> u16 { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().arr().read().arr() + } + } + + impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { + fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); + } + + fn set_dead_time_value(&mut self, value: u8) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); + } + + fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced() + .ccer() + .modify(|w| w.set_ccne(channel.raw(), enable)); + } } + + }; } diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs new file mode 100644 index 000000000..514796930 --- /dev/null +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -0,0 +1,107 @@ +use core::marker::PhantomData; + +use embassy_hal_internal::{into_ref, PeripheralRef}; + +use super::*; +#[allow(unused_imports)] +use crate::gpio::sealed::{AFType, Pin}; +use crate::gpio::AnyPin; +use crate::time::Hertz; +use crate::Peripheral; + +pub struct Ch1; +pub struct Ch2; +pub struct Ch3; +pub struct Ch4; + +pub struct PwmPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident) => { + impl<'d, Perip: CaptureCompare16bitInstance> 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, + } + } + } + }; +} + +channel_impl!(new_ch1, Ch1, Channel1Pin); +channel_impl!(new_ch2, Ch2, Channel2Pin); +channel_impl!(new_ch3, Ch3, Channel3Pin); +channel_impl!(new_ch4, Ch4, Channel4Pin); + +pub struct SimplePwm<'d, T> { + inner: PeripheralRef<'d, T>, +} + +impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { + pub fn new( + tim: impl Peripheral

+ 'd, + _ch1: Option>, + _ch2: Option>, + _ch3: Option>, + _ch4: 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: Channel) { + self.inner.enable_channel(channel, true); + } + + pub fn disable(&mut self, channel: Channel) { + 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 { + self.inner.get_max_compare_value() + } + + pub fn set_duty(&mut self, channel: Channel, duty: u16) { + assert!(duty < self.get_max_duty()); + self.inner.set_compare_value(channel, duty) + } +} diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs index 7c5902052..4f130c26b 100644 --- a/examples/stm32f4/src/bin/pwm.rs +++ b/examples/stm32f4/src/bin/pwm.rs @@ -4,9 +4,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::pwm::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::pwm::Channel; use embassy_stm32::time::khz; +use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::timer::Channel; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index a8a68ed6e..8cc2a4117 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -4,10 +4,10 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::pwm::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; -use embassy_stm32::pwm::simple_pwm::PwmPin; -use embassy_stm32::pwm::Channel; use embassy_stm32::time::khz; +use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, ComplementaryPwmPin}; +use embassy_stm32::timer::simple_pwm::PwmPin; +use embassy_stm32::timer::Channel; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs index 8f7842ed7..b5a9b9952 100644 --- a/examples/stm32g4/src/bin/pwm.rs +++ b/examples/stm32g4/src/bin/pwm.rs @@ -4,9 +4,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::pwm::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::pwm::Channel; use embassy_stm32::time::khz; +use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::timer::Channel; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs index d360df085..45b0872b5 100644 --- a/examples/stm32h7/src/bin/low_level_timer_api.rs +++ b/examples/stm32h7/src/bin/low_level_timer_api.rs @@ -6,8 +6,8 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::low_level::AFType; use embassy_stm32::gpio::Speed; -use embassy_stm32::pwm::*; use embassy_stm32::time::{khz, mhz, Hertz}; +use embassy_stm32::timer::*; use embassy_stm32::{into_ref, Config, Peripheral, PeripheralRef}; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs index c5c0dd290..adf2ea9ce 100644 --- a/examples/stm32h7/src/bin/pwm.rs +++ b/examples/stm32h7/src/bin/pwm.rs @@ -4,9 +4,9 @@ use defmt::*; use embassy_executor::Spawner; -use embassy_stm32::pwm::simple_pwm::{PwmPin, SimplePwm}; -use embassy_stm32::pwm::Channel; use embassy_stm32::time::{khz, mhz}; +use embassy_stm32::timer::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::timer::Channel; use embassy_stm32::Config; use embassy_time::{Duration, Timer}; use {defmt_rtt as _, panic_probe as _}; -- cgit