From 077e59a192ca4cb096a9ef939d06ebefebbac42d Mon Sep 17 00:00:00 2001 From: xoviat Date: Wed, 3 Dec 2025 09:36:58 -0600 Subject: timer: restore waveform method --- embassy-stm32/src/timer/complementary_pwm.rs | 24 ++++++++++++++++++++++-- embassy-stm32/src/timer/low_level.rs | 25 +++++++++++++++++++++---- embassy-stm32/src/timer/simple_pwm.rs | 22 ++++++++++++++++++++++ 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 6ca13820a..4f2ac4079 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -2,14 +2,13 @@ use core::marker::PhantomData; -pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr}; - use super::low_level::{CountingMode, OutputPolarity, Timer}; use super::simple_pwm::PwmPin; use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; use crate::Peri; use crate::dma::word::Word; use crate::gpio::{AnyPin, OutputType}; +pub use crate::pac::timer::vals::{Ccds, Ckd, Mms2, Ossi, Ossr}; use crate::time::Hertz; use crate::timer::TimerChannel; use crate::timer::low_level::OutputCompareMode; @@ -217,6 +216,27 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { self.inner.set_dead_time_value(value); } + /// Generate a sequence of PWM waveform + /// + /// Note: + /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. + /// Also be aware that embassy timers use one of timers internally. It is possible to + /// switch this timer by using `time-driver-timX` feature. + pub async fn waveform>( + &mut self, + dma: Peri<'_, impl super::Dma>, + channel: Channel, + duty: &[W], + ) { + self.inner.enable_channel(channel, true); + self.inner.enable_channel(C::CHANNEL, true); + self.inner.clamp_compare_value::(channel); + self.inner.set_cc_dma_selection(Ccds::ON_UPDATE); + self.inner.set_cc_dma_enable_state(C::CHANNEL, true); + self.inner.setup_channel_update_dma(dma, channel, duty).await; + self.inner.set_cc_dma_enable_state(C::CHANNEL, false); + } + /// Generate a sequence of PWM waveform /// /// Note: diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 6a70d2a40..da1bfac5f 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -13,7 +13,7 @@ use embassy_hal_internal::Peri; pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource}; use super::*; -use crate::dma::{Transfer, WritableRingBuffer}; +use crate::dma::{self, Transfer, WritableRingBuffer}; use crate::pac::timer::vals; use crate::rcc; use crate::time::Hertz; @@ -682,9 +682,26 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { channel: Channel, duty: &'a [W], ) -> Transfer<'a> { - #[allow(clippy::let_unit_value)] // eg. stm32f334 - let req = dma.request(); + self.setup_update_dma_inner(dma.request(), dma, channel, duty) + } + /// Generate a sequence of PWM waveform + pub fn setup_channel_update_dma<'a, C: TimerChannel, W: Word + Into>( + &mut self, + dma: Peri<'a, impl super::Dma>, + channel: Channel, + duty: &'a [W], + ) -> Transfer<'a> { + self.setup_update_dma_inner(dma.request(), dma, channel, duty) + } + + fn setup_update_dma_inner<'a, W: Word + Into>( + &mut self, + request: dma::Request, + dma: Peri<'a, impl dma::Channel>, + channel: Channel, + duty: &'a [W], + ) -> Transfer<'a> { unsafe { #[cfg(not(any(bdma, gpdma)))] use crate::dma::{Burst, FifoThreshold}; @@ -700,7 +717,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { Transfer::new_write( dma, - req, + request, duty, self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W, dma_transfer_option, diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index b79ed364b..3f050a366 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -11,6 +11,7 @@ use crate::dma::word::Word; #[cfg(gpio_v2)] use crate::gpio::Pull; use crate::gpio::{AfType, AnyPin, OutputType, Speed}; +use crate::pac::timer::vals::Ccds; use crate::time::Hertz; /// PWM pin wrapper. @@ -336,6 +337,27 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { self.inner.get_max_compare_value().into() + 1 } + /// Generate a sequence of PWM waveform + /// + /// Note: + /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. + /// Also be aware that embassy timers use one of timers internally. It is possible to + /// switch this timer by using `time-driver-timX` feature. + pub async fn waveform>( + &mut self, + dma: Peri<'_, impl super::Dma>, + channel: Channel, + duty: &[W], + ) { + self.inner.enable_channel(channel, true); + self.inner.enable_channel(C::CHANNEL, true); + self.inner.clamp_compare_value::(channel); + self.inner.set_cc_dma_selection(Ccds::ON_UPDATE); + self.inner.set_cc_dma_enable_state(C::CHANNEL, true); + self.inner.setup_channel_update_dma(dma, channel, duty).await; + self.inner.set_cc_dma_enable_state(C::CHANNEL, false); + } + /// Generate a sequence of PWM waveform /// /// Note: -- cgit