Merge pull request #4522 from WattStep/complementary_pwm_idle_state

Add methods for idle-state control in STM32 Complementary PWM
This commit is contained in:
Ulf Lilleengen 2025-08-12 19:27:28 +02:00 committed by GitHub
commit e2921be35c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 94 additions and 1 deletions

View File

@ -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;
@ -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,6 +91,50 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
this
}
/// 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(&mut self, val: Ossi) {
self.inner.set_ossi(val);
}
/// Get state of OSSI-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(&mut 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(&mut 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);
}
/// Get Master Output Enable
pub fn get_master_output_enable(&self) -> bool {
self.inner.get_moe()
}
/// Enable the given channel.
pub fn enable(&mut self, channel: Channel) {
self.inner.enable_channel(channel, true);

View File

@ -686,10 +686,35 @@ 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));
}
/// 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))]
@ -725,4 +750,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));
}
}