aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-15 19:26:05 +0000
committerGitHub <[email protected]>2025-11-15 19:26:05 +0000
commitcf5ac499a2f7897488f19db9fbb9d4c3aa44235d (patch)
tree692aee4fdddb34ab9c27bc6c5fc7d456fb2dc123
parent933e27d99aaa4869aa601d6ac0f68b6e79788d3e (diff)
parentcf7a0ea280b823ea080c4dbf05adfa8c3be451c1 (diff)
Merge pull request #4892 from Dectron-AB/cleanup-timer
stm32: Cleanup timers
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs99
-rw-r--r--embassy-stm32/src/timer/low_level.rs215
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs218
4 files changed, 271 insertions, 262 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 72fe1c7a8..2c3dfb3d3 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9 9
10- feat: Add waveform methods to ComplementaryPwm
10- chore: cleanup low-power add time 11- chore: cleanup low-power add time
11- fix: Allow setting SAI peripheral `frame_length` to `256` 12- fix: Allow setting SAI peripheral `frame_length` to `256`
12- fix: flash erase on dual-bank STM32Gxxx 13- fix: flash erase on dual-bank STM32Gxxx
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 9a56a41fb..76cbbe91d 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -218,60 +218,57 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
218 /// 218 ///
219 /// Note: 219 /// Note:
220 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 220 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
221 #[inline(always)]
221 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 222 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
222 #[allow(clippy::let_unit_value)] // eg. stm32f334 223 self.inner.waveform_up(dma, channel, duty).await
223 let req = dma.request(); 224 }
224
225 let original_duty_state = self.inner.get_compare_value(channel);
226 let original_enable_state = self.inner.get_channel_enable_state(channel);
227 let original_update_dma_state = self.inner.get_update_dma_state();
228
229 if !original_update_dma_state {
230 self.inner.enable_update_dma(true);
231 }
232
233 if !original_enable_state {
234 self.inner.enable_channel(channel, true);
235 }
236
237 unsafe {
238 #[cfg(not(any(bdma, gpdma)))]
239 use crate::dma::{Burst, FifoThreshold};
240 use crate::dma::{Transfer, TransferOptions};
241
242 let dma_transfer_option = TransferOptions {
243 #[cfg(not(any(bdma, gpdma)))]
244 fifo_threshold: Some(FifoThreshold::Full),
245 #[cfg(not(any(bdma, gpdma)))]
246 mburst: Burst::Incr8,
247 ..Default::default()
248 };
249
250 Transfer::new_write(
251 dma,
252 req,
253 duty,
254 self.inner.regs_gp16().ccr(channel.index()).as_ptr() as *mut u16,
255 dma_transfer_option,
256 )
257 .await
258 };
259
260 // restore output compare state
261 if !original_enable_state {
262 self.inner.enable_channel(channel, false);
263 }
264 225
265 self.inner.set_compare_value(channel, original_duty_state); 226 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
227 ///
228 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
229 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
230 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
231 ///
232 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
233 /// represents a single update event and each column corresponds to a specific timer channel (starting
234 /// from `starting_channel` up to and including `ending_channel`).
235 ///
236 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
237 ///
238 /// ```rust,ignore
239 /// let dma_buf: [u16; 16] = [
240 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
241 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
242 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
243 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
244 /// ];
245 /// ```
246 ///
247 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
248 /// updating the duty cycles of all selected channels simultaneously.
249 ///
250 /// Note:
251 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
252 /// Also be aware that embassy timers use one of timers internally. It is possible to
253 /// switch this timer by using `time-driver-timX` feature.
254 ///
255 #[inline(always)]
256 pub async fn waveform_up_multi_channel(
257 &mut self,
258 dma: Peri<'_, impl super::UpDma<T>>,
259 starting_channel: Channel,
260 ending_channel: Channel,
261 duty: &[u16],
262 ) {
263 self.inner
264 .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty)
265 .await;
266 }
266 267
267 // Since DMA is closed before timer update event trigger DMA is turn off, 268 /// Generate a sequence of PWM waveform
268 // this can almost always trigger a DMA FIFO error. 269 #[inline(always)]
269 // 270 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
270 // optional TODO: 271 self.inner.waveform(dma, duty).await;
271 // clean FEIF after disable UDE
272 if !original_update_dma_state {
273 self.inner.enable_update_dma(false);
274 }
275 } 272 }
276} 273}
277 274
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index 0122fe4f7..c574277e7 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -14,8 +14,8 @@ pub use stm32_metapac::timer::vals::{FilterValue, Mms as MasterMode, Sms as Slav
14 14
15use super::*; 15use super::*;
16use crate::pac::timer::vals; 16use crate::pac::timer::vals;
17use crate::rcc;
18use crate::time::Hertz; 17use crate::time::Hertz;
18use crate::{dma, rcc};
19 19
20/// Input capture mode. 20/// Input capture mode.
21#[derive(Clone, Copy)] 21#[derive(Clone, Copy)]
@@ -656,6 +656,219 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
656 } 656 }
657 } 657 }
658 658
659 /// Generate a sequence of PWM waveform
660 ///
661 /// Note:
662 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
663 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
664 #[allow(clippy::let_unit_value)] // eg. stm32f334
665 let req = dma.request();
666
667 let original_update_dma_state = self.get_update_dma_state();
668
669 if !original_update_dma_state {
670 self.enable_update_dma(true);
671 }
672
673 self.waveform_helper(dma, req, channel, duty).await;
674
675 // Since DMA is closed before timer update event trigger DMA is turn off,
676 // this can almost always trigger a DMA FIFO error.
677 //
678 // optional TODO:
679 // clean FEIF after disable UDE
680 if !original_update_dma_state {
681 self.enable_update_dma(false);
682 }
683 }
684
685 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
686 ///
687 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
688 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
689 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
690 ///
691 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
692 /// represents a single update event and each column corresponds to a specific timer channel (starting
693 /// from `starting_channel` up to and including `ending_channel`).
694 ///
695 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
696 ///
697 /// ```rust,ignore
698 /// let dma_buf: [u16; 16] = [
699 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
700 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
701 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
702 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
703 /// ];
704 /// ```
705 ///
706 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
707 /// updating the duty cycles of all selected channels simultaneously.
708 ///
709 /// Note:
710 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
711 /// Also be aware that embassy timers use one of timers internally. It is possible to
712 /// switch this timer by using `time-driver-timX` feature.
713 ///
714 pub async fn waveform_up_multi_channel(
715 &mut self,
716 dma: Peri<'_, impl super::UpDma<T>>,
717 starting_channel: Channel,
718 ending_channel: Channel,
719 duty: &[u16],
720 ) {
721 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
722 let start_ch_index = starting_channel.index();
723 let end_ch_index = ending_channel.index();
724
725 assert!(start_ch_index <= end_ch_index);
726
727 let ccrx_addr = self.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
728 self.regs_gp16()
729 .dcr()
730 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
731 self.regs_gp16()
732 .dcr()
733 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
734
735 #[allow(clippy::let_unit_value)] // eg. stm32f334
736 let req = dma.request();
737
738 let original_update_dma_state = self.get_update_dma_state();
739 if !original_update_dma_state {
740 self.enable_update_dma(true);
741 }
742
743 unsafe {
744 #[cfg(not(any(bdma, gpdma)))]
745 use crate::dma::{Burst, FifoThreshold};
746 use crate::dma::{Transfer, TransferOptions};
747
748 let dma_transfer_option = TransferOptions {
749 #[cfg(not(any(bdma, gpdma)))]
750 fifo_threshold: Some(FifoThreshold::Full),
751 #[cfg(not(any(bdma, gpdma)))]
752 mburst: Burst::Incr4,
753 ..Default::default()
754 };
755
756 Transfer::new_write(
757 dma,
758 req,
759 duty,
760 self.regs_gp16().dmar().as_ptr() as *mut u16,
761 dma_transfer_option,
762 )
763 .await
764 };
765
766 if !original_update_dma_state {
767 self.enable_update_dma(false);
768 }
769 }
770
771 /// Generate a sequence of PWM waveform
772 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
773 use crate::pac::timer::vals::Ccds;
774
775 #[allow(clippy::let_unit_value)] // eg. stm32f334
776 let req = dma.request();
777
778 let cc_channel = C::CHANNEL;
779
780 let original_cc_dma_on_update = self.get_cc_dma_selection() == Ccds::ON_UPDATE;
781 let original_cc_dma_enabled = self.get_cc_dma_enable_state(cc_channel);
782
783 // redirect CC DMA request onto Update Event
784 if !original_cc_dma_on_update {
785 self.set_cc_dma_selection(Ccds::ON_UPDATE)
786 }
787
788 if !original_cc_dma_enabled {
789 self.set_cc_dma_enable_state(cc_channel, true);
790 }
791
792 self.waveform_helper(dma, req, cc_channel, duty).await;
793
794 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
795 // this can almost always trigger a DMA FIFO error.
796 //
797 // optional TODO:
798 // clean FEIF after disable UDE
799 if !original_cc_dma_enabled {
800 self.set_cc_dma_enable_state(cc_channel, false);
801 }
802
803 if !original_cc_dma_on_update {
804 self.set_cc_dma_selection(Ccds::ON_COMPARE)
805 }
806 }
807
808 async fn waveform_helper(
809 &mut self,
810 dma: Peri<'_, impl dma::Channel>,
811 req: dma::Request,
812 channel: Channel,
813 duty: &[u16],
814 ) {
815 let original_duty_state = self.get_compare_value(channel);
816 let original_enable_state = self.get_channel_enable_state(channel);
817
818 if !original_enable_state {
819 self.enable_channel(channel, true);
820 }
821
822 unsafe {
823 #[cfg(not(any(bdma, gpdma)))]
824 use crate::dma::{Burst, FifoThreshold};
825 use crate::dma::{Transfer, TransferOptions};
826
827 let dma_transfer_option = TransferOptions {
828 #[cfg(not(any(bdma, gpdma)))]
829 fifo_threshold: Some(FifoThreshold::Full),
830 #[cfg(not(any(bdma, gpdma)))]
831 mburst: Burst::Incr8,
832 ..Default::default()
833 };
834
835 match self.bits() {
836 TimerBits::Bits16 => {
837 Transfer::new_write(
838 dma,
839 req,
840 duty,
841 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
842 dma_transfer_option,
843 )
844 .await
845 }
846 #[cfg(not(any(stm32l0)))]
847 TimerBits::Bits32 => {
848 #[cfg(not(any(bdma, gpdma)))]
849 panic!("unsupported timer bits");
850
851 #[cfg(any(bdma, gpdma))]
852 Transfer::new_write(
853 dma,
854 req,
855 duty,
856 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
857 dma_transfer_option,
858 )
859 .await
860 }
861 };
862 };
863
864 // restore output compare state
865 if !original_enable_state {
866 self.enable_channel(channel, false);
867 }
868
869 self.set_compare_value(channel, original_duty_state);
870 }
871
659 /// Get capture value for a channel. 872 /// Get capture value for a channel.
660 pub fn get_capture_value(&self, channel: Channel) -> u32 { 873 pub fn get_capture_value(&self, channel: Channel) -> u32 {
661 self.get_compare_value(channel) 874 self.get_compare_value(channel)
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index c338b0fd4..19a0b38d1 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -4,7 +4,7 @@ use core::marker::PhantomData;
4use core::mem::ManuallyDrop; 4use core::mem::ManuallyDrop;
5 5
6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; 6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin}; 7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin};
8use crate::Peri; 8use crate::Peri;
9#[cfg(gpio_v2)] 9#[cfg(gpio_v2)]
10use crate::gpio::Pull; 10use crate::gpio::Pull;
@@ -312,79 +312,9 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
312 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. 312 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
313 /// Also be aware that embassy timers use one of timers internally. It is possible to 313 /// Also be aware that embassy timers use one of timers internally. It is possible to
314 /// switch this timer by using `time-driver-timX` feature. 314 /// switch this timer by using `time-driver-timX` feature.
315 #[inline(always)]
315 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 316 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) {
316 #[allow(clippy::let_unit_value)] // eg. stm32f334 317 self.inner.waveform_up(dma, channel, duty).await;
317 let req = dma.request();
318
319 let original_duty_state = self.channel(channel).current_duty_cycle();
320 let original_enable_state = self.channel(channel).is_enabled();
321 let original_update_dma_state = self.inner.get_update_dma_state();
322
323 if !original_update_dma_state {
324 self.inner.enable_update_dma(true);
325 }
326
327 if !original_enable_state {
328 self.channel(channel).enable();
329 }
330
331 unsafe {
332 #[cfg(not(any(bdma, gpdma)))]
333 use crate::dma::{Burst, FifoThreshold};
334 use crate::dma::{Transfer, TransferOptions};
335
336 let dma_transfer_option = TransferOptions {
337 #[cfg(not(any(bdma, gpdma)))]
338 fifo_threshold: Some(FifoThreshold::Full),
339 #[cfg(not(any(bdma, gpdma)))]
340 mburst: Burst::Incr8,
341 ..Default::default()
342 };
343
344 match self.inner.bits() {
345 TimerBits::Bits16 => {
346 Transfer::new_write(
347 dma,
348 req,
349 duty,
350 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16,
351 dma_transfer_option,
352 )
353 .await
354 }
355 #[cfg(not(any(stm32l0)))]
356 TimerBits::Bits32 => {
357 #[cfg(not(any(bdma, gpdma)))]
358 panic!("unsupported timer bits");
359
360 #[cfg(any(bdma, gpdma))]
361 Transfer::new_write(
362 dma,
363 req,
364 duty,
365 self.inner.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
366 dma_transfer_option,
367 )
368 .await
369 }
370 };
371 };
372
373 // restore output compare state
374 if !original_enable_state {
375 self.channel(channel).disable();
376 }
377
378 self.channel(channel).set_duty_cycle(original_duty_state);
379
380 // Since DMA is closed before timer update event trigger DMA is turn off,
381 // this can almost always trigger a DMA FIFO error.
382 //
383 // optional TODO:
384 // clean FEIF after disable UDE
385 if !original_update_dma_state {
386 self.inner.enable_update_dma(false);
387 }
388 } 318 }
389 319
390 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events. 320 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
@@ -416,6 +346,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
416 /// Also be aware that embassy timers use one of timers internally. It is possible to 346 /// Also be aware that embassy timers use one of timers internally. It is possible to
417 /// switch this timer by using `time-driver-timX` feature. 347 /// switch this timer by using `time-driver-timX` feature.
418 /// 348 ///
349 #[inline(always)]
419 pub async fn waveform_up_multi_channel( 350 pub async fn waveform_up_multi_channel(
420 &mut self, 351 &mut self,
421 dma: Peri<'_, impl super::UpDma<T>>, 352 dma: Peri<'_, impl super::UpDma<T>>,
@@ -423,148 +354,15 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
423 ending_channel: Channel, 354 ending_channel: Channel,
424 duty: &[u16], 355 duty: &[u16],
425 ) { 356 ) {
426 let cr1_addr = self.inner.regs_gp16().cr1().as_ptr() as u32;
427 let start_ch_index = starting_channel.index();
428 let end_ch_index = ending_channel.index();
429
430 assert!(start_ch_index <= end_ch_index);
431
432 let ccrx_addr = self.inner.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
433 self.inner 357 self.inner
434 .regs_gp16() 358 .waveform_up_multi_channel(dma, starting_channel, ending_channel, duty)
435 .dcr() 359 .await;
436 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
437 self.inner
438 .regs_gp16()
439 .dcr()
440 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
441
442 #[allow(clippy::let_unit_value)] // eg. stm32f334
443 let req = dma.request();
444
445 let original_update_dma_state = self.inner.get_update_dma_state();
446 if !original_update_dma_state {
447 self.inner.enable_update_dma(true);
448 }
449
450 unsafe {
451 #[cfg(not(any(bdma, gpdma)))]
452 use crate::dma::{Burst, FifoThreshold};
453 use crate::dma::{Transfer, TransferOptions};
454
455 let dma_transfer_option = TransferOptions {
456 #[cfg(not(any(bdma, gpdma)))]
457 fifo_threshold: Some(FifoThreshold::Full),
458 #[cfg(not(any(bdma, gpdma)))]
459 mburst: Burst::Incr4,
460 ..Default::default()
461 };
462
463 Transfer::new_write(
464 dma,
465 req,
466 duty,
467 self.inner.regs_gp16().dmar().as_ptr() as *mut u16,
468 dma_transfer_option,
469 )
470 .await
471 };
472
473 if !original_update_dma_state {
474 self.inner.enable_update_dma(false);
475 }
476 } 360 }
477}
478 361
479impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
480 /// Generate a sequence of PWM waveform 362 /// Generate a sequence of PWM waveform
363 #[inline(always)]
481 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) { 364 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
482 use crate::pac::timer::vals::Ccds; 365 self.inner.waveform(dma, duty).await;
483
484 #[allow(clippy::let_unit_value)] // eg. stm32f334
485 let req = dma.request();
486
487 let cc_channel = C::CHANNEL;
488
489 let original_duty_state = self.channel(cc_channel).current_duty_cycle();
490 let original_enable_state = self.channel(cc_channel).is_enabled();
491 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
492 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
493
494 // redirect CC DMA request onto Update Event
495 if !original_cc_dma_on_update {
496 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
497 }
498
499 if !original_cc_dma_enabled {
500 self.inner.set_cc_dma_enable_state(cc_channel, true);
501 }
502
503 if !original_enable_state {
504 self.channel(cc_channel).enable();
505 }
506
507 unsafe {
508 #[cfg(not(any(bdma, gpdma)))]
509 use crate::dma::{Burst, FifoThreshold};
510 use crate::dma::{Transfer, TransferOptions};
511
512 let dma_transfer_option = TransferOptions {
513 #[cfg(not(any(bdma, gpdma)))]
514 fifo_threshold: Some(FifoThreshold::Full),
515 #[cfg(not(any(bdma, gpdma)))]
516 mburst: Burst::Incr8,
517 ..Default::default()
518 };
519
520 match self.inner.bits() {
521 TimerBits::Bits16 => {
522 Transfer::new_write(
523 dma,
524 req,
525 duty,
526 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
527 dma_transfer_option,
528 )
529 .await
530 }
531 #[cfg(not(any(stm32l0)))]
532 TimerBits::Bits32 => {
533 #[cfg(not(any(bdma, gpdma)))]
534 panic!("unsupported timer bits");
535
536 #[cfg(any(bdma, gpdma))]
537 Transfer::new_write(
538 dma,
539 req,
540 duty,
541 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
542 dma_transfer_option,
543 )
544 .await
545 }
546 };
547 };
548
549 // restore output compare state
550 if !original_enable_state {
551 self.channel(cc_channel).disable();
552 }
553
554 self.channel(cc_channel).set_duty_cycle(original_duty_state);
555
556 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
557 // this can almost always trigger a DMA FIFO error.
558 //
559 // optional TODO:
560 // clean FEIF after disable UDE
561 if !original_cc_dma_enabled {
562 self.inner.set_cc_dma_enable_state(cc_channel, false);
563 }
564
565 if !original_cc_dma_on_update {
566 self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
567 }
568 } 366 }
569} 367}
570 368