aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-25 08:54:11 -0600
committerxoviat <[email protected]>2025-11-25 08:54:11 -0600
commit2612f07f549fa0b9d8565ef760814d5f7ebea785 (patch)
treee2227fbac5f2c404130c444cd1b31a4c53b3b31e /embassy-stm32/src
parent424d9d3aa961d4170be96ac23331aa5a3cba3e5b (diff)
cleanup low-level timer methods
Diffstat (limited to 'embassy-stm32/src')
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs11
-rw-r--r--embassy-stm32/src/timer/low_level.rs137
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs11
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> {
220 /// 220 ///
221 /// Note: 221 /// Note:
222 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 222 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
223 #[inline(always)]
224 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 223 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
225 self.inner.waveform_up(dma, channel, duty).await 224 self.inner.enable_channel(channel, true);
225 self.inner.enable_update_dma(true);
226 self.inner.setup_update_dma(dma, channel, duty).await;
227 self.inner.enable_update_dma(false);
226 } 228 }
227 229
228 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. 230 /// 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> {
254 /// Also be aware that embassy timers use one of timers internally. It is possible to 256 /// Also be aware that embassy timers use one of timers internally. It is possible to
255 /// switch this timer by using `time-driver-timX` feature. 257 /// switch this timer by using `time-driver-timX` feature.
256 /// 258 ///
257 #[inline(always)]
258 pub async fn waveform_up_multi_channel( 259 pub async fn waveform_up_multi_channel(
259 &mut self, 260 &mut self,
260 dma: Peri<'_, impl super::UpDma<T>>, 261 dma: Peri<'_, impl super::UpDma<T>>,
@@ -262,9 +263,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
262 ending_channel: Channel, 263 ending_channel: Channel,
263 duty: &[u16], 264 duty: &[u16],
264 ) { 265 ) {
266 self.inner.enable_update_dma(true);
265 self.inner 267 self.inner
266 .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) 268 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
267 .await; 269 .await;
270 self.inner.enable_update_dma(false);
268 } 271 }
269} 272}
270 273
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;
13pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource}; 13pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as SlaveMode, Ts as TriggerSource};
14 14
15use super::*; 15use super::*;
16use crate::dma::Transfer;
16use crate::pac::timer::vals; 17use crate::pac::timer::vals;
18use crate::rcc;
17use crate::time::Hertz; 19use crate::time::Hertz;
18use crate::{dma, rcc};
19 20
20/// Input capture mode. 21/// Input capture mode.
21#[derive(Clone, Copy)] 22#[derive(Clone, Copy)]
@@ -663,25 +664,51 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
663 /// 664 ///
664 /// Note: 665 /// Note:
665 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 666 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
666 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 667 pub fn setup_update_dma<'a>(
668 &mut self,
669 dma: Peri<'a, impl super::UpDma<T>>,
670 channel: Channel,
671 duty: &'a [u16],
672 ) -> Transfer<'a> {
667 #[allow(clippy::let_unit_value)] // eg. stm32f334 673 #[allow(clippy::let_unit_value)] // eg. stm32f334
668 let req = dma.request(); 674 let req = dma.request();
669 675
670 let original_update_dma_state = self.get_update_dma_state(); 676 unsafe {
677 #[cfg(not(any(bdma, gpdma)))]
678 use crate::dma::{Burst, FifoThreshold};
679 use crate::dma::{Transfer, TransferOptions};
671 680
672 if !original_update_dma_state { 681 let dma_transfer_option = TransferOptions {
673 self.enable_update_dma(true); 682 #[cfg(not(any(bdma, gpdma)))]
674 } 683 fifo_threshold: Some(FifoThreshold::Full),
684 #[cfg(not(any(bdma, gpdma)))]
685 mburst: Burst::Incr8,
686 ..Default::default()
687 };
675 688
676 self.waveform_helper(dma, req, channel, duty).await; 689 match self.bits() {
690 TimerBits::Bits16 => Transfer::new_write(
691 dma,
692 req,
693 duty,
694 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
695 dma_transfer_option,
696 ),
697 #[cfg(not(any(stm32l0)))]
698 TimerBits::Bits32 => {
699 #[cfg(not(any(bdma, gpdma)))]
700 panic!("unsupported timer bits");
677 701
678 // Since DMA is closed before timer update event trigger DMA is turn off, 702 #[cfg(any(bdma, gpdma))]
679 // this can almost always trigger a DMA FIFO error. 703 Transfer::new_write(
680 // 704 dma,
681 // optional TODO: 705 req,
682 // clean FEIF after disable UDE 706 duty,
683 if !original_update_dma_state { 707 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
684 self.enable_update_dma(false); 708 dma_transfer_option,
709 )
710 }
711 }
685 } 712 }
686 } 713 }
687 714
@@ -714,13 +741,13 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
714 /// Also be aware that embassy timers use one of timers internally. It is possible to 741 /// Also be aware that embassy timers use one of timers internally. It is possible to
715 /// switch this timer by using `time-driver-timX` feature. 742 /// switch this timer by using `time-driver-timX` feature.
716 /// 743 ///
717 pub async fn waveform_up_multi_channel( 744 pub fn setup_update_dma_burst<'a>(
718 &mut self, 745 &mut self,
719 dma: Peri<'_, impl super::UpDma<T>>, 746 dma: Peri<'a, impl super::UpDma<T>>,
720 starting_channel: Channel, 747 starting_channel: Channel,
721 ending_channel: Channel, 748 ending_channel: Channel,
722 duty: &[u16], 749 duty: &'a [u16],
723 ) { 750 ) -> Transfer<'a> {
724 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; 751 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
725 let start_ch_index = starting_channel.index(); 752 let start_ch_index = starting_channel.index();
726 let end_ch_index = ending_channel.index(); 753 let end_ch_index = ending_channel.index();
@@ -738,11 +765,6 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
738 #[allow(clippy::let_unit_value)] // eg. stm32f334 765 #[allow(clippy::let_unit_value)] // eg. stm32f334
739 let req = dma.request(); 766 let req = dma.request();
740 767
741 let original_update_dma_state = self.get_update_dma_state();
742 if !original_update_dma_state {
743 self.enable_update_dma(true);
744 }
745
746 unsafe { 768 unsafe {
747 #[cfg(not(any(bdma, gpdma)))] 769 #[cfg(not(any(bdma, gpdma)))]
748 use crate::dma::{Burst, FifoThreshold}; 770 use crate::dma::{Burst, FifoThreshold};
@@ -763,76 +785,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
763 self.regs_gp16().dmar().as_ptr() as *mut u16, 785 self.regs_gp16().dmar().as_ptr() as *mut u16,
764 dma_transfer_option, 786 dma_transfer_option,
765 ) 787 )
766 .await
767 };
768
769 if !original_update_dma_state {
770 self.enable_update_dma(false);
771 }
772 }
773
774 async fn waveform_helper(
775 &mut self,
776 dma: Peri<'_, impl dma::Channel>,
777 req: dma::Request,
778 channel: Channel,
779 duty: &[u16],
780 ) {
781 let original_duty_state = self.get_compare_value(channel);
782 let original_enable_state = self.get_channel_enable_state(channel);
783
784 if !original_enable_state {
785 self.enable_channel(channel, true);
786 }
787
788 unsafe {
789 #[cfg(not(any(bdma, gpdma)))]
790 use crate::dma::{Burst, FifoThreshold};
791 use crate::dma::{Transfer, TransferOptions};
792
793 let dma_transfer_option = TransferOptions {
794 #[cfg(not(any(bdma, gpdma)))]
795 fifo_threshold: Some(FifoThreshold::Full),
796 #[cfg(not(any(bdma, gpdma)))]
797 mburst: Burst::Incr8,
798 ..Default::default()
799 };
800
801 match self.bits() {
802 TimerBits::Bits16 => {
803 Transfer::new_write(
804 dma,
805 req,
806 duty,
807 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
808 dma_transfer_option,
809 )
810 .await
811 }
812 #[cfg(not(any(stm32l0)))]
813 TimerBits::Bits32 => {
814 #[cfg(not(any(bdma, gpdma)))]
815 panic!("unsupported timer bits");
816
817 #[cfg(any(bdma, gpdma))]
818 Transfer::new_write(
819 dma,
820 req,
821 duty,
822 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
823 dma_transfer_option,
824 )
825 .await
826 }
827 };
828 };
829
830 // restore output compare state
831 if !original_enable_state {
832 self.enable_channel(channel, false);
833 } 788 }
834
835 self.set_compare_value(channel, original_duty_state);
836 } 789 }
837 790
838 /// Get capture value for a channel. 791 /// 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> {
316 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. 316 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
317 /// Also be aware that embassy timers use one of timers internally. It is possible to 317 /// Also be aware that embassy timers use one of timers internally. It is possible to
318 /// switch this timer by using `time-driver-timX` feature. 318 /// switch this timer by using `time-driver-timX` feature.
319 #[inline(always)]
320 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 319 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
321 self.inner.waveform_up(dma, channel, duty).await; 320 self.inner.enable_channel(channel, true);
321 self.inner.enable_update_dma(true);
322 self.inner.setup_update_dma(dma, channel, duty).await;
323 self.inner.enable_update_dma(false);
322 } 324 }
323 325
324 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. 326 /// 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> {
350 /// Also be aware that embassy timers use one of timers internally. It is possible to 352 /// Also be aware that embassy timers use one of timers internally. It is possible to
351 /// switch this timer by using `time-driver-timX` feature. 353 /// switch this timer by using `time-driver-timX` feature.
352 /// 354 ///
353 #[inline(always)]
354 pub async fn waveform_up_multi_channel( 355 pub async fn waveform_up_multi_channel(
355 &mut self, 356 &mut self,
356 dma: Peri<'_, impl super::UpDma<T>>, 357 dma: Peri<'_, impl super::UpDma<T>>,
@@ -358,9 +359,11 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
358 ending_channel: Channel, 359 ending_channel: Channel,
359 duty: &[u16], 360 duty: &[u16],
360 ) { 361 ) {
362 self.inner.enable_update_dma(true);
361 self.inner 363 self.inner
362 .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty) 364 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
363 .await; 365 .await;
366 self.inner.enable_update_dma(false);
364 } 367 }
365} 368}
366 369