From 2612f07f549fa0b9d8565ef760814d5f7ebea785 Mon Sep 17 00:00:00 2001 From: xoviat Date: Tue, 25 Nov 2025 08:54:11 -0600 Subject: cleanup low-level timer methods --- embassy-stm32/src/timer/complementary_pwm.rs | 11 ++- embassy-stm32/src/timer/low_level.rs | 137 +++++++++------------------ embassy-stm32/src/timer/simple_pwm.rs | 11 ++- 3 files changed, 59 insertions(+), 100 deletions(-) diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 9f34f3ec7..77f19a37b 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs @@ -220,9 +220,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { /// /// Note: /// you will need to provide corresponding TIMx_UP DMA channel to use this method. - #[inline(always)] pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma>, channel: Channel, duty: &[u16]) { - self.inner.waveform_up(dma, channel, duty).await + self.inner.enable_channel(channel, true); + self.inner.enable_update_dma(true); + self.inner.setup_update_dma(dma, channel, duty).await; + self.inner.enable_update_dma(false); } /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. @@ -254,7 +256,6 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { /// Also be aware that embassy timers use one of timers internally. It is possible to /// switch this timer by using `time-driver-timX` feature. /// - #[inline(always)] pub async fn waveform_up_multi_channel( &mut self, dma: Peri<'_, impl super::UpDma>, @@ -262,9 +263,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { ending_channel: Channel, duty: &[u16], ) { + self.inner.enable_update_dma(true); self.inner - .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) + .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) .await; + self.inner.enable_update_dma(false); } } diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs index 8fbedafdf..f986c8dab 100644 --- a/embassy-stm32/src/timer/low_level.rs +++ b/embassy-stm32/src/timer/low_level.rs @@ -13,9 +13,10 @@ 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; use crate::pac::timer::vals; +use crate::rcc; use crate::time::Hertz; -use crate::{dma, rcc}; /// Input capture mode. #[derive(Clone, Copy)] @@ -663,25 +664,51 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { /// /// Note: /// you will need to provide corresponding TIMx_UP DMA channel to use this method. - pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma>, channel: Channel, duty: &[u16]) { + pub fn setup_update_dma<'a>( + &mut self, + dma: Peri<'a, impl super::UpDma>, + channel: Channel, + duty: &'a [u16], + ) -> Transfer<'a> { #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); - let original_update_dma_state = self.get_update_dma_state(); + unsafe { + #[cfg(not(any(bdma, gpdma)))] + use crate::dma::{Burst, FifoThreshold}; + use crate::dma::{Transfer, TransferOptions}; - if !original_update_dma_state { - self.enable_update_dma(true); - } + let dma_transfer_option = TransferOptions { + #[cfg(not(any(bdma, gpdma)))] + fifo_threshold: Some(FifoThreshold::Full), + #[cfg(not(any(bdma, gpdma)))] + mburst: Burst::Incr8, + ..Default::default() + }; - self.waveform_helper(dma, req, channel, duty).await; + match self.bits() { + TimerBits::Bits16 => Transfer::new_write( + dma, + req, + duty, + self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, + dma_transfer_option, + ), + #[cfg(not(any(stm32l0)))] + TimerBits::Bits32 => { + #[cfg(not(any(bdma, gpdma)))] + panic!("unsupported timer bits"); - // Since DMA is closed before timer update event trigger DMA is turn off, - // this can almost always trigger a DMA FIFO error. - // - // optional TODO: - // clean FEIF after disable UDE - if !original_update_dma_state { - self.enable_update_dma(false); + #[cfg(any(bdma, gpdma))] + Transfer::new_write( + dma, + req, + duty, + self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, + dma_transfer_option, + ) + } + } } } @@ -714,13 +741,13 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { /// 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_up_multi_channel( + pub fn setup_update_dma_burst<'a>( &mut self, - dma: Peri<'_, impl super::UpDma>, + dma: Peri<'a, impl super::UpDma>, starting_channel: Channel, ending_channel: Channel, - duty: &[u16], - ) { + duty: &'a [u16], + ) -> Transfer<'a> { let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; let start_ch_index = starting_channel.index(); let end_ch_index = ending_channel.index(); @@ -738,11 +765,6 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { #[allow(clippy::let_unit_value)] // eg. stm32f334 let req = dma.request(); - let original_update_dma_state = self.get_update_dma_state(); - if !original_update_dma_state { - self.enable_update_dma(true); - } - unsafe { #[cfg(not(any(bdma, gpdma)))] use crate::dma::{Burst, FifoThreshold}; @@ -763,76 +785,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> { self.regs_gp16().dmar().as_ptr() as *mut u16, dma_transfer_option, ) - .await - }; - - if !original_update_dma_state { - self.enable_update_dma(false); - } - } - - async fn waveform_helper( - &mut self, - dma: Peri<'_, impl dma::Channel>, - req: dma::Request, - channel: Channel, - duty: &[u16], - ) { - let original_duty_state = self.get_compare_value(channel); - let original_enable_state = self.get_channel_enable_state(channel); - - if !original_enable_state { - self.enable_channel(channel, true); - } - - unsafe { - #[cfg(not(any(bdma, gpdma)))] - use crate::dma::{Burst, FifoThreshold}; - use crate::dma::{Transfer, TransferOptions}; - - let dma_transfer_option = TransferOptions { - #[cfg(not(any(bdma, gpdma)))] - fifo_threshold: Some(FifoThreshold::Full), - #[cfg(not(any(bdma, gpdma)))] - mburst: Burst::Incr8, - ..Default::default() - }; - - match self.bits() { - TimerBits::Bits16 => { - Transfer::new_write( - dma, - req, - duty, - self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, - dma_transfer_option, - ) - .await - } - #[cfg(not(any(stm32l0)))] - TimerBits::Bits32 => { - #[cfg(not(any(bdma, gpdma)))] - panic!("unsupported timer bits"); - - #[cfg(any(bdma, gpdma))] - Transfer::new_write( - dma, - req, - duty, - self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32, - dma_transfer_option, - ) - .await - } - }; - }; - - // restore output compare state - if !original_enable_state { - self.enable_channel(channel, false); } - - self.set_compare_value(channel, original_duty_state); } /// Get capture value for a channel. diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 15399b108..eb1b66358 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs @@ -316,9 +316,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// 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. - #[inline(always)] pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma>, channel: Channel, duty: &[u16]) { - self.inner.waveform_up(dma, channel, duty).await; + self.inner.enable_channel(channel, true); + self.inner.enable_update_dma(true); + self.inner.setup_update_dma(dma, channel, duty).await; + self.inner.enable_update_dma(false); } /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. @@ -350,7 +352,6 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { /// Also be aware that embassy timers use one of timers internally. It is possible to /// switch this timer by using `time-driver-timX` feature. /// - #[inline(always)] pub async fn waveform_up_multi_channel( &mut self, dma: Peri<'_, impl super::UpDma>, @@ -358,9 +359,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { ending_channel: Channel, duty: &[u16], ) { + self.inner.enable_update_dma(true); self.inner - .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) + .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) .await; + self.inner.enable_update_dma(false); } } -- cgit