From 991b22b6a1e845dc15eca72bf9881e60f1803840 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 4 Apr 2023 19:35:25 -0500 Subject: [PATCH 1/4] stm32/pwm: add complementary pwm --- embassy-stm32/src/pwm/complementary_pwm.rs | 145 +++++++++++++++++++++ embassy-stm32/src/pwm/mod.rs | 22 ++++ 2 files changed, 167 insertions(+) create mode 100644 embassy-stm32/src/pwm/complementary_pwm.rs diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs new file mode 100644 index 000000000..b8761724a --- /dev/null +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -0,0 +1,145 @@ +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::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)>, +} + +pub struct ComplementaryPwmPin<'d, Perip, Channel> { + _pin: PeripheralRef<'d, AnyPin>, + phantom: PhantomData<(Perip, Channel)>, +} + +macro_rules! channel_impl { + ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_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(|_| unsafe { + 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: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { + pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { + into_ref!(pin); + critical_section::with(|_| unsafe { + 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, + } + } + } + }; +} + +channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); +channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); +channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); +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(); + + unsafe { + 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) { + unsafe { + self.inner.enable_channel(channel, true); + } + } + + pub fn disable(&mut self, channel: Channel) { + unsafe { + 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 { + unsafe { self.inner.get_max_compare_value() } + } + + pub fn set_duty(&mut self, channel: Channel, duty: u16) { + assert!(duty < self.get_max_duty()); + unsafe { self.inner.set_compare_value(channel, duty) } + } + + /* + set the value of the dead-time register + */ + pub fn set_dead_time_value(&mut self, value: u8) { + unsafe { self.inner.set_dead_time_value(value) } + } +} diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index d3713391c..6f3c12665 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -1,3 +1,4 @@ +pub mod complementary_pwm; pub mod simple_pwm; #[cfg(feature = "unstable-pac")] @@ -67,6 +68,10 @@ pub(crate) mod sealed { unsafe fn get_max_compare_value(&self) -> u16; } + pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { + unsafe fn set_dead_time_value(&mut self, value: u8); + } + pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); @@ -82,6 +87,12 @@ 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 { @@ -209,6 +220,17 @@ foreach_interrupt! { impl CaptureCompare16bitInstance for crate::peripherals::$inst { } + + impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { + unsafe fn set_dead_time_value(&mut self, value: u8) { + use crate::timer::sealed::AdvancedControlInstance; + Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); + } + } + + impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { + + } }; } From 76772683191be15d32604ec5dd46fb5eb3949de8 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 5 Apr 2023 17:50:23 -0500 Subject: [PATCH 2/4] stm32/pwm: cleanup and fix complementary pwm --- embassy-stm32/src/pwm/complementary_pwm.rs | 47 ++++++---------------- embassy-stm32/src/pwm/mod.rs | 18 +++++++++ 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs index b8761724a..e4de1fb7a 100644 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -1,7 +1,9 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; +use stm32_metapac::timer::vals::Ckd; +use super::simple_pwm::*; use super::*; #[allow(unused_imports)] use crate::gpio::sealed::{AFType, Pin}; @@ -9,39 +11,13 @@ 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)>, -} - pub struct ComplementaryPwmPin<'d, Perip, Channel> { _pin: PeripheralRef<'d, AnyPin>, phantom: PhantomData<(Perip, Channel)>, } -macro_rules! channel_impl { +macro_rules! complementary_channel_impl { ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_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(|_| unsafe { - 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: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { pub fn $new_chx(pin: impl Peripheral

> + 'd) -> Self { into_ref!(pin); @@ -60,10 +36,10 @@ macro_rules! channel_impl { }; } -channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); -channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); -channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); -channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); +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>, @@ -114,11 +90,13 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { pub fn enable(&mut self, channel: Channel) { unsafe { self.inner.enable_channel(channel, true); + self.inner.enable_complementary_channel(channel, true); } } pub fn disable(&mut self, channel: Channel) { unsafe { + self.inner.enable_complementary_channel(channel, false); self.inner.enable_channel(channel, false); } } @@ -136,9 +114,10 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { unsafe { self.inner.set_compare_value(channel, duty) } } - /* - set the value of the dead-time register - */ + pub fn set_dead_time_clock_division(&mut self, value: Ckd) { + unsafe { self.inner.set_dead_time_clock_division(value) } + } + pub fn set_dead_time_value(&mut self, value: u8) { unsafe { self.inner.set_dead_time_value(value) } } diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs index 6f3c12665..0bef07089 100644 --- a/embassy-stm32/src/pwm/mod.rs +++ b/embassy-stm32/src/pwm/mod.rs @@ -1,6 +1,8 @@ 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::*; @@ -69,7 +71,11 @@ pub(crate) mod sealed { } pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { + unsafe fn set_dead_time_clock_division(&mut self, value: Ckd); + unsafe fn set_dead_time_value(&mut self, value: u8); + + unsafe fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); } pub trait CaptureCompare32bitInstance: crate::timer::sealed::GeneralPurpose32bitInstance { @@ -222,10 +228,22 @@ foreach_interrupt! { } impl crate::pwm::sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { + unsafe 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)); + } + unsafe fn set_dead_time_value(&mut self, value: u8) { use crate::timer::sealed::AdvancedControlInstance; Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); } + + unsafe 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 { From 9f1dac3f5daf61a2d56679d00e018e5e3557c7e5 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 5 Apr 2023 18:07:07 -0500 Subject: [PATCH 3/4] stm32/pwm: add complementary pwm example --- embassy-stm32/src/pwm/complementary_pwm.rs | 2 +- examples/stm32f4/src/bin/pwm_complementary.rs | 77 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 examples/stm32f4/src/bin/pwm_complementary.rs diff --git a/embassy-stm32/src/pwm/complementary_pwm.rs b/embassy-stm32/src/pwm/complementary_pwm.rs index e4de1fb7a..13edfbaa3 100644 --- a/embassy-stm32/src/pwm/complementary_pwm.rs +++ b/embassy-stm32/src/pwm/complementary_pwm.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use embassy_hal_common::{into_ref, PeripheralRef}; -use stm32_metapac::timer::vals::Ckd; +pub use stm32_metapac::timer::vals::Ckd; use super::simple_pwm::*; use super::*; diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs new file mode 100644 index 000000000..795c38e48 --- /dev/null +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -0,0 +1,77 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::pwm::complementary_pwm::{Ckd, ComplementaryPwm, ComplementaryPwmPin}; +use embassy_stm32::pwm::simple_pwm::{PwmPin, SimplePwm}; +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_ch1(p.PE9); + let ch1n = ComplementaryPwmPin::new_ch1(p.PA7); + let mut pwm = ComplementaryPwm::new( + p.TIM1, + Some(ch1), + Some(ch1n), + None, + None, + None, + None, + None, + None, + khz(10), + ); + + /* + 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 + */ + pwm.set_dead_time_clock_division(Ckd::DIV1); + pwm.set_dead_time_value(0); + + let max = pwm.get_max_duty(); + 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 31ef783ac1add908c4c4506d3ce4e5f6ad9bea56 Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 5 Apr 2023 18:18:05 -0500 Subject: [PATCH 4/4] stm32/pwm: fix unused import --- examples/stm32f4/src/bin/pwm_complementary.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs index 795c38e48..6e17f3fd3 100644 --- a/examples/stm32f4/src/bin/pwm_complementary.rs +++ b/examples/stm32f4/src/bin/pwm_complementary.rs @@ -5,7 +5,7 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::pwm::complementary_pwm::{Ckd, ComplementaryPwm, ComplementaryPwmPin}; -use embassy_stm32::pwm::simple_pwm::{PwmPin, SimplePwm}; +use embassy_stm32::pwm::simple_pwm::PwmPin; use embassy_stm32::pwm::Channel; use embassy_stm32::time::khz; use embassy_time::{Duration, Timer};