From 7dad187ff740a0a1940d2d503fbc373218f4bd01 Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 6 Aug 2025 10:46:21 +0200 Subject: [PATCH 1/6] Add methods for setting ossi, ossr, osi and oisn along with software trigger for break input --- embassy-stm32/src/timer/complementary_pwm.rs | 45 +++++++++++++++++++- embassy-stm32/src/timer/low_level.rs | 25 +++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index b00cc18ad..1178e7d83 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -2,7 +2,7 @@ use core::marker::PhantomData; -use stm32_metapac::timer::vals::Ckd; +pub use stm32_metapac::timer::vals::{Ckd, Ossi, Ossr}; use super::low_level::{CountingMode, OutputPolarity, Timer}; use super::simple_pwm::PwmPin; @@ -82,6 +82,49 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { this } + /// Set output idle state for all channels + /// - `output_high_when_idle` - true if the output for the normal channels should + /// be high when idle, which means that the complementary channels are low. Opposite + /// for `false`. + pub fn set_output_idle_state(&self, output_high_when_idle: bool) { + [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] + .iter() + .for_each(|&channel| { + self.inner.set_ois(channel, output_high_when_idle); + self.inner.set_oisn(channel, !output_high_when_idle); + }); + } + + /// Set state of OSSI-bit in BDTR register + pub fn set_off_state_selection_idle(&self, val: Ossi) { + self.inner.set_ossi(val); + } + + /// Set state of OSSR-bit in BDTR register + pub fn set_off_state_selection_run(&self, val: Ossr) { + self.inner.set_ossr(val); + } + + /// Trigger break input from software + pub fn trigger_software_break(&self, n: usize) { + self.inner.trigger_software_break(n); + } + + /// Set Master Output Enable + pub fn set_master_output_enable(&mut self, enable: bool) { + self.inner.set_moe(enable); + } + + /// Set Master Slave Mode 2 + pub fn set_mms2(&mut self, mms2: Mms2) { + self.inner.set_mms2_selection(mms2); + } + + /// Set Repetition Counter + pub fn set_repetition_counter(&mut self, val: u16) { + self.inner.set_repetition_counter(val); + } + /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { self.inner.enable_channel(channel, true); diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index dc8ceb725..01bf60869 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -686,6 +686,16 @@ impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> { self.regs_1ch_cmp().bdtr().modify(|w| w.set_dtg(value)); } + /// Set state of OSSI-bit in BDTR register + pub fn set_ossi(&self, val: vals::Ossi) { + self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossi(val)); + } + + /// Set state of OSSR-bit in BDTR register + pub fn set_ossr(&self, val: vals::Ossr) { + self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossr(val)); + } + /// Set state of MOE-bit in BDTR register to en-/disable output pub fn set_moe(&self, enable: bool) { self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); @@ -725,4 +735,19 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> { .ccer() .modify(|w| w.set_ccne(channel.index(), enable)); } + + /// Set Output Idle State + pub fn set_ois(&self, channel: Channel, val: bool) { + self.regs_advanced().cr2().modify(|w| w.set_ois(channel.index(), val)); + } + /// Set Output Idle State Complementary Channel + pub fn set_oisn(&self, channel: Channel, val: bool) { + self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val)); + } + + /// Trigger software break 1 or 2 + /// Setting this bit generates a break event. This bit is automatically cleared by the hardware. + pub fn trigger_software_break(&self, n: usize) { + self.regs_advanced().egr().write(|r| r.set_bg(n, true)); + } } From 0941a76be60a3c95aed9a3e1835ec1de6f03ac12 Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 6 Aug 2025 15:04:48 +0200 Subject: [PATCH 2/6] Add get methods for meo, ossi and ossr --- embassy-stm32/src/timer/complementary_pwm.rs | 15 +++++++++++++++ embassy-stm32/src/timer/low_level.rs | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 1178e7d83..bf76155dd 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -100,11 +100,21 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { self.inner.set_ossi(val); } + /// Get state of OSSR-bit in BDTR register + pub fn get_off_state_selection_idle(&self) -> Ossi { + self.inner.get_ossi() + } + /// Set state of OSSR-bit in BDTR register pub fn set_off_state_selection_run(&self, val: Ossr) { self.inner.set_ossr(val); } + /// Get state of OSSR-bit in BDTR register + pub fn get_off_state_selection_run(&self) -> Ossr { + self.inner.get_ossr() + } + /// Trigger break input from software pub fn trigger_software_break(&self, n: usize) { self.inner.trigger_software_break(n); @@ -115,6 +125,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { self.inner.set_moe(enable); } + /// Get Master Output Enable + pub fn get_master_output_enable(&mut self) -> bool { + self.inner.get_moe() + } + /// Set Master Slave Mode 2 pub fn set_mms2(&mut self, mms2: Mms2) { self.inner.set_mms2_selection(mms2); diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 01bf60869..ac039bb0d 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -691,15 +691,30 @@ impl<'d, T: AdvancedInstance1Channel> Timer<'d, T> { self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossi(val)); } + /// Get state of OSSI-bit in BDTR register + pub fn get_ossi(&self) -> vals::Ossi { + self.regs_1ch_cmp().bdtr().read().ossi() + } + /// Set state of OSSR-bit in BDTR register pub fn set_ossr(&self, val: vals::Ossr) { self.regs_1ch_cmp().bdtr().modify(|w| w.set_ossr(val)); } + /// Get state of OSSR-bit in BDTR register + pub fn get_ossr(&self) -> vals::Ossr { + self.regs_1ch_cmp().bdtr().read().ossr() + } + /// Set state of MOE-bit in BDTR register to en-/disable output pub fn set_moe(&self, enable: bool) { self.regs_1ch_cmp().bdtr().modify(|w| w.set_moe(enable)); } + + /// Get state of MOE-bit in BDTR register + pub fn get_moe(&self) -> bool { + self.regs_1ch_cmp().bdtr().read().moe() + } } #[cfg(not(stm32l0))] From c46cae734f3566a1e77d59b37d8bd714e542fd21 Mon Sep 17 00:00:00 2001 From: Jakob Date: Wed, 6 Aug 2025 15:25:01 +0200 Subject: [PATCH 3/6] Change method arugments to be non-mutable --- embassy-stm32/src/timer/complementary_pwm.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index bf76155dd..dcfe8f5dd 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -100,7 +100,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { self.inner.set_ossi(val); } - /// Get state of OSSR-bit in BDTR register + /// Get state of OSSI-bit in BDTR register pub fn get_off_state_selection_idle(&self) -> Ossi { self.inner.get_ossi() } @@ -121,12 +121,12 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { } /// Set Master Output Enable - pub fn set_master_output_enable(&mut self, enable: bool) { + pub fn set_master_output_enable(&self, enable: bool) { self.inner.set_moe(enable); } /// Get Master Output Enable - pub fn get_master_output_enable(&mut self) -> bool { + pub fn get_master_output_enable(&self) -> bool { self.inner.get_moe() } @@ -136,18 +136,18 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { } /// Set Repetition Counter - pub fn set_repetition_counter(&mut self, val: u16) { + pub fn set_repetition_counter(&self, val: u16) { self.inner.set_repetition_counter(val); } /// Enable the given channel. - pub fn enable(&mut self, channel: Channel) { + pub fn enable(&self, channel: Channel) { self.inner.enable_channel(channel, true); self.inner.enable_complementary_channel(channel, true); } /// Disable the given channel. - pub fn disable(&mut self, channel: Channel) { + pub fn disable(&self, channel: Channel) { self.inner.enable_complementary_channel(channel, false); self.inner.enable_channel(channel, false); } From b6ee237fb1c59eaa0c0aa1bf876d1caf7888e940 Mon Sep 17 00:00:00 2001 From: Jakob Date: Fri, 8 Aug 2025 11:43:51 +0200 Subject: [PATCH 4/6] Add enum for IdlePolarity to make interface clearer for set_output_idle_state method --- embassy-stm32/src/timer/complementary_pwm.rs | 24 ++++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index dcfe8f5dd..4d83875f5 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -43,6 +43,15 @@ pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { inner: Timer<'d, T>, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +/// Determines which outputs are active when PWM is in idle mode +pub enum IdlePolarity { + /// Normal channels are forced active and complementary channels are forced inactive + OisActive, + /// Normal channels are forced inactive and complementary channels are forced active + OisnActive, +} + impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { /// Create a new complementary PWM driver. #[allow(clippy::too_many_arguments)] @@ -82,16 +91,17 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { this } - /// Set output idle state for all channels - /// - `output_high_when_idle` - true if the output for the normal channels should - /// be high when idle, which means that the complementary channels are low. Opposite - /// for `false`. - pub fn set_output_idle_state(&self, output_high_when_idle: bool) { + /// Sets the idle output state for all channels. + pub fn set_output_idle_state(&self, polarity: IdlePolarity) { + let ois_active = match polarity { + IdlePolarity::OisActive => true, + IdlePolarity::OisnActive => false, + }; [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] .iter() .for_each(|&channel| { - self.inner.set_ois(channel, output_high_when_idle); - self.inner.set_oisn(channel, !output_high_when_idle); + self.inner.set_ois(channel, ois_active); + self.inner.set_oisn(channel, !ois_active); }); } From b0cef8c0adad0f90779a29f5b6c4e60fd5e38c1a Mon Sep 17 00:00:00 2001 From: Jakob Date: Sat, 9 Aug 2025 10:10:41 +0200 Subject: [PATCH 5/6] Adjust which methods should have mut reference to self. Change set_output_idle_state to accept channel iterator as input --- embassy-stm32/src/timer/complementary_pwm.rs | 37 ++++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 4d83875f5..1f049cb32 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -91,22 +91,21 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { this } - /// Sets the idle output state for all channels. - pub fn set_output_idle_state(&self, polarity: IdlePolarity) { - let ois_active = match polarity { - IdlePolarity::OisActive => true, - IdlePolarity::OisnActive => false, - }; - [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4] - .iter() - .for_each(|&channel| { - self.inner.set_ois(channel, ois_active); - self.inner.set_oisn(channel, !ois_active); - }); + /// Sets the idle output state for the given channels. + pub fn set_output_idle_state( + &mut self, + channels: &[Channel], + polarity: IdlePolarity, + ) { + let ois_active = matches!(polarity, IdlePolarity::OisActive); + for &channel in channels { + self.inner.set_ois(channel, ois_active); + self.inner.set_oisn(channel, !ois_active); + } } /// Set state of OSSI-bit in BDTR register - pub fn set_off_state_selection_idle(&self, val: Ossi) { + pub fn set_off_state_selection_idle(&mut self, val: Ossi) { self.inner.set_ossi(val); } @@ -116,7 +115,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { } /// Set state of OSSR-bit in BDTR register - pub fn set_off_state_selection_run(&self, val: Ossr) { + pub fn set_off_state_selection_run(&mut self, val: Ossr) { self.inner.set_ossr(val); } @@ -126,12 +125,12 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { } /// Trigger break input from software - pub fn trigger_software_break(&self, n: usize) { + pub fn trigger_software_break(&mut self, n: usize) { self.inner.trigger_software_break(n); } /// Set Master Output Enable - pub fn set_master_output_enable(&self, enable: bool) { + pub fn set_master_output_enable(&mut self, enable: bool) { self.inner.set_moe(enable); } @@ -146,18 +145,18 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { } /// Set Repetition Counter - pub fn set_repetition_counter(&self, val: u16) { + pub fn set_repetition_counter(&mut self, val: u16) { self.inner.set_repetition_counter(val); } /// Enable the given channel. - pub fn enable(&self, channel: Channel) { + pub fn enable(&mut self, channel: Channel) { self.inner.enable_channel(channel, true); self.inner.enable_complementary_channel(channel, true); } /// Disable the given channel. - pub fn disable(&self, channel: Channel) { + pub fn disable(&mut self, channel: Channel) { self.inner.enable_complementary_channel(channel, false); self.inner.enable_channel(channel, false); } From c228ffe666c4354c909ea454cebc14387930c9c0 Mon Sep 17 00:00:00 2001 From: Jakob Date: Sun, 10 Aug 2025 09:22:49 +0200 Subject: [PATCH 6/6] Remove unrelated cahnges --- embassy-stm32/src/timer/complementary_pwm.rs | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 1f049cb32..b291fc155 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -92,11 +92,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { } /// Sets the idle output state for the given channels. - pub fn set_output_idle_state( - &mut self, - channels: &[Channel], - polarity: IdlePolarity, - ) { + pub fn set_output_idle_state(&mut self, channels: &[Channel], polarity: IdlePolarity) { let ois_active = matches!(polarity, IdlePolarity::OisActive); for &channel in channels { self.inner.set_ois(channel, ois_active); @@ -139,16 +135,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { self.inner.get_moe() } - /// Set Master Slave Mode 2 - pub fn set_mms2(&mut self, mms2: Mms2) { - self.inner.set_mms2_selection(mms2); - } - - /// Set Repetition Counter - pub fn set_repetition_counter(&mut self, val: u16) { - self.inner.set_repetition_counter(val); - } - /// Enable the given channel. pub fn enable(&mut self, channel: Channel) { self.inner.enable_channel(channel, true);