aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer/low_level.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/timer/low_level.rs')
-rw-r--r--embassy-stm32/src/timer/low_level.rs430
1 files changed, 321 insertions, 109 deletions
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index ac039bb0d..82e936f3a 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -10,9 +10,10 @@ use core::mem::ManuallyDrop;
10 10
11use embassy_hal_internal::Peri; 11use embassy_hal_internal::Peri;
12// Re-export useful enums 12// Re-export useful enums
13pub use stm32_metapac::timer::vals::{FilterValue, 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::{self, Transfer, WritableRingBuffer};
16use crate::pac::timer::vals; 17use crate::pac::timer::vals;
17use crate::rcc; 18use crate::rcc;
18use crate::time::Hertz; 19use crate::time::Hertz;
@@ -143,20 +144,69 @@ pub enum OutputCompareMode {
143 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as 144 /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as
144 /// TIMx_CNT>TIMx_CCRx else inactive. 145 /// TIMx_CNT>TIMx_CCRx else inactive.
145 PwmMode2, 146 PwmMode2,
146 // TODO: there's more modes here depending on the chip family. 147
148 #[cfg(timer_v2)]
149 /// In up-counting mode, the channel is active until a trigger
150 /// event is detected (on tim_trgi signal). Then, a comparison is performed as in PWM
151 /// mode 1 and the channels becomes active again at the next update. In down-counting
152 /// mode, the channel is inactive until a trigger event is detected (on tim_trgi signal).
153 /// Then, a comparison is performed as in PWM mode 1 and the channels becomes
154 /// inactive again at the next update.
155 OnePulseMode1,
156
157 #[cfg(timer_v2)]
158 /// In up-counting mode, the channel is inactive until a
159 /// trigger event is detected (on tim_trgi signal). Then, a comparison is performed as in
160 /// PWM mode 2 and the channels becomes inactive again at the next update. In down
161 /// counting mode, the channel is active until a trigger event is detected (on tim_trgi
162 /// signal). Then, a comparison is performed as in PWM mode 1 and the channels
163 /// becomes active again at the next update.
164 OnePulseMode2,
165
166 #[cfg(timer_v2)]
167 /// Combined PWM mode 1 - tim_oc1ref has the same behavior as in PWM mode 1.
168 /// tim_oc1refc is the logical OR between tim_oc1ref and tim_oc2ref.
169 CombinedPwmMode1,
170
171 #[cfg(timer_v2)]
172 /// Combined PWM mode 2 - tim_oc1ref has the same behavior as in PWM mode 2.
173 /// tim_oc1refc is the logical AND between tim_oc1ref and tim_oc2ref.
174 CombinedPwmMode2,
175
176 #[cfg(timer_v2)]
177 /// tim_oc1ref has the same behavior as in PWM mode 1. tim_oc1refc outputs tim_oc1ref
178 /// when the counter is counting up, tim_oc2ref when it is counting down.
179 AsymmetricPwmMode1,
180
181 #[cfg(timer_v2)]
182 /// tim_oc1ref has the same behavior as in PWM mode 2. tim_oc1refc outputs tim_oc1ref
183 /// when the counter is counting up, tim_oc2ref when it is counting down.
184 AsymmetricPwmMode2,
147} 185}
148 186
149impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 187impl From<OutputCompareMode> for crate::pac::timer::vals::Ocm {
150 fn from(mode: OutputCompareMode) -> Self { 188 fn from(mode: OutputCompareMode) -> Self {
151 match mode { 189 match mode {
152 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, 190 OutputCompareMode::Frozen => crate::pac::timer::vals::Ocm::FROZEN,
153 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVE_ON_MATCH, 191 OutputCompareMode::ActiveOnMatch => crate::pac::timer::vals::Ocm::ACTIVE_ON_MATCH,
154 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVE_ON_MATCH, 192 OutputCompareMode::InactiveOnMatch => crate::pac::timer::vals::Ocm::INACTIVE_ON_MATCH,
155 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, 193 OutputCompareMode::Toggle => crate::pac::timer::vals::Ocm::TOGGLE,
156 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCE_INACTIVE, 194 OutputCompareMode::ForceInactive => crate::pac::timer::vals::Ocm::FORCE_INACTIVE,
157 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCE_ACTIVE, 195 OutputCompareMode::ForceActive => crate::pac::timer::vals::Ocm::FORCE_ACTIVE,
158 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWM_MODE1, 196 OutputCompareMode::PwmMode1 => crate::pac::timer::vals::Ocm::PWM_MODE1,
159 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWM_MODE2, 197 OutputCompareMode::PwmMode2 => crate::pac::timer::vals::Ocm::PWM_MODE2,
198 #[cfg(timer_v2)]
199 OutputCompareMode::OnePulseMode1 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_1,
200 #[cfg(timer_v2)]
201 OutputCompareMode::OnePulseMode2 => crate::pac::timer::vals::Ocm::RETRIGERRABLE_OPM_MODE_2,
202 #[cfg(timer_v2)]
203 OutputCompareMode::CombinedPwmMode1 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_1,
204 #[cfg(timer_v2)]
205 OutputCompareMode::CombinedPwmMode2 => crate::pac::timer::vals::Ocm::COMBINED_PWM_MODE_2,
206 #[cfg(timer_v2)]
207 OutputCompareMode::AsymmetricPwmMode1 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_1,
208 #[cfg(timer_v2)]
209 OutputCompareMode::AsymmetricPwmMode2 => crate::pac::timer::vals::Ocm::ASYMMETRIC_PWM_MODE_2,
160 } 210 }
161 } 211 }
162} 212}
@@ -218,11 +268,27 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
218 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } 268 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
219 } 269 }
220 270
271 #[cfg(stm32l0)]
272 fn regs_gp32_unchecked(&self) -> crate::pac::timer::TimGp16 {
273 unsafe { crate::pac::timer::TimGp16::from_ptr(T::regs()) }
274 }
275
221 /// Start the timer. 276 /// Start the timer.
222 pub fn start(&self) { 277 pub fn start(&self) {
223 self.regs_core().cr1().modify(|r| r.set_cen(true)); 278 self.regs_core().cr1().modify(|r| r.set_cen(true));
224 } 279 }
225 280
281 /// Generate timer update event from software.
282 ///
283 /// Set URS to avoid generating interrupt or DMA request. This update event is only
284 /// used to load value from pre-load registers. If called when the timer is running,
285 /// it may disrupt the output waveform.
286 pub fn generate_update_event(&self) {
287 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
288 self.regs_core().egr().write(|r| r.set_ug(true));
289 self.regs_core().cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
290 }
291
226 /// Stop the timer. 292 /// Stop the timer.
227 pub fn stop(&self) { 293 pub fn stop(&self) {
228 self.regs_core().cr1().modify(|r| r.set_cen(false)); 294 self.regs_core().cr1().modify(|r| r.set_cen(false));
@@ -235,7 +301,12 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
235 301
236 /// get the capability of the timer 302 /// get the capability of the timer
237 pub fn bits(&self) -> TimerBits { 303 pub fn bits(&self) -> TimerBits {
238 T::BITS 304 match T::Word::bits() {
305 16 => TimerBits::Bits16,
306 #[cfg(not(stm32l0))]
307 32 => TimerBits::Bits32,
308 _ => unreachable!(),
309 }
239 } 310 }
240 311
241 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0. 312 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
@@ -245,18 +316,10 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
245 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved 316 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
246 /// because it needs to count up and down. 317 /// because it needs to count up and down.
247 pub fn set_frequency(&self, frequency: Hertz) { 318 pub fn set_frequency(&self, frequency: Hertz) {
248 match T::BITS { 319 self.set_frequency_internal(frequency, T::Word::bits());
249 TimerBits::Bits16 => {
250 self.set_frequency_internal(frequency, 16);
251 }
252 #[cfg(not(stm32l0))]
253 TimerBits::Bits32 => {
254 self.set_frequency_internal(frequency, 32);
255 }
256 }
257 } 320 }
258 321
259 pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: u8) { 322 pub(crate) fn set_frequency_internal(&self, frequency: Hertz, max_divide_by_bits: usize) {
260 let f = frequency.0; 323 let f = frequency.0;
261 assert!(f > 0); 324 assert!(f > 0);
262 let timer_f = T::frequency().0; 325 let timer_f = T::frequency().0;
@@ -265,33 +328,15 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
265 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into()); 328 let psc: u16 = unwrap!(((pclk_ticks_per_timer_period - 1) / (1 << max_divide_by_bits)).try_into());
266 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1); 329 let divide_by = pclk_ticks_per_timer_period / (u64::from(psc) + 1);
267 330
268 match T::BITS { 331 // the timer counts `0..=arr`, we want it to count `0..divide_by`
269 TimerBits::Bits16 => { 332 let arr: T::Word = unwrap!(T::Word::try_from(divide_by - 1));
270 // the timer counts `0..=arr`, we want it to count `0..divide_by`
271 let arr = unwrap!(u16::try_from(divide_by - 1));
272
273 let regs = self.regs_core();
274 regs.psc().write_value(psc);
275 regs.arr().write(|r| r.set_arr(arr));
276
277 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
278 regs.egr().write(|r| r.set_ug(true));
279 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
280 }
281 #[cfg(not(stm32l0))]
282 TimerBits::Bits32 => {
283 // the timer counts `0..=arr`, we want it to count `0..divide_by`
284 let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
285
286 let regs = self.regs_gp32_unchecked();
287 regs.psc().write_value(psc);
288 regs.arr().write_value(arr);
289 333
290 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); 334 let regs = self.regs_gp32_unchecked();
291 regs.egr().write(|r| r.set_ug(true)); 335 regs.psc().write_value(psc);
292 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); 336 #[cfg(stm32l0)]
293 } 337 regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into())));
294 } 338 #[cfg(not(stm32l0))]
339 regs.arr().write_value(arr.into());
295 } 340 }
296 341
297 /// Set tick frequency. 342 /// Set tick frequency.
@@ -340,23 +385,14 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
340 pub fn get_frequency(&self) -> Hertz { 385 pub fn get_frequency(&self) -> Hertz {
341 let timer_f = T::frequency(); 386 let timer_f = T::frequency();
342 387
343 match T::BITS { 388 let regs = self.regs_gp32_unchecked();
344 TimerBits::Bits16 => { 389 #[cfg(not(stm32l0))]
345 let regs = self.regs_core(); 390 let arr = regs.arr().read();
346 let arr = regs.arr().read().arr(); 391 #[cfg(stm32l0)]
347 let psc = regs.psc().read(); 392 let arr = regs.arr().read().arr();
348 393 let psc = regs.psc().read();
349 timer_f / arr / (psc + 1)
350 }
351 #[cfg(not(stm32l0))]
352 TimerBits::Bits32 => {
353 let regs = self.regs_gp32_unchecked();
354 let arr = regs.arr().read();
355 let psc = regs.psc().read();
356 394
357 timer_f / arr / (psc + 1) 395 timer_f / arr / (psc + 1)
358 }
359 }
360 } 396 }
361 397
362 /// Get the clock frequency of the timer (before prescaler is applied). 398 /// Get the clock frequency of the timer (before prescaler is applied).
@@ -416,42 +452,29 @@ impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
416 } 452 }
417 453
418 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. 454 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
419 pub fn get_max_compare_value(&self) -> u32 { 455 pub fn get_max_compare_value(&self) -> T::Word {
420 match T::BITS { 456 #[cfg(not(stm32l0))]
421 TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32, 457 return unwrap!(self.regs_gp32_unchecked().arr().read().try_into());
422 #[cfg(not(stm32l0))] 458 #[cfg(stm32l0)]
423 TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), 459 return unwrap!(self.regs_gp32_unchecked().arr().read().arr().try_into());
424 }
425 } 460 }
426 461
427 /// Set the max compare value. 462 /// Set the max compare value.
428 /// 463 ///
429 /// An update event is generated to load the new value. The update event is 464 /// An update event is generated to load the new value. The update event is
430 /// generated such that it will not cause an interrupt or DMA request. 465 /// generated such that it will not cause an interrupt or DMA request.
431 pub fn set_max_compare_value(&self, ticks: u32) { 466 pub fn set_max_compare_value(&self, ticks: T::Word) {
432 match T::BITS { 467 let arr = ticks;
433 TimerBits::Bits16 => {
434 let arr = unwrap!(u16::try_from(ticks));
435
436 let regs = self.regs_1ch();
437 regs.arr().write(|r| r.set_arr(arr));
438
439 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
440 regs.egr().write(|r| r.set_ug(true));
441 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
442 }
443 #[cfg(not(stm32l0))]
444 TimerBits::Bits32 => {
445 let arr = ticks;
446 468
447 let regs = self.regs_gp32_unchecked(); 469 let regs = self.regs_gp32_unchecked();
448 regs.arr().write_value(arr); 470 #[cfg(not(stm32l0))]
471 regs.arr().write_value(arr.into());
472 #[cfg(stm32l0)]
473 regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into())));
449 474
450 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); 475 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
451 regs.egr().write(|r| r.set_ug(true)); 476 regs.egr().write(|r| r.set_ug(true));
452 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); 477 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
453 }
454 }
455 } 478 }
456} 479}
457 480
@@ -585,30 +608,204 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
585 } 608 }
586 609
587 /// Set compare value for a channel. 610 /// Set compare value for a channel.
588 pub fn set_compare_value(&self, channel: Channel, value: u32) { 611 pub fn set_compare_value(&self, channel: Channel, value: T::Word) {
589 match T::BITS { 612 #[cfg(not(stm32l0))]
590 TimerBits::Bits16 => { 613 self.regs_gp32_unchecked()
591 let value = unwrap!(u16::try_from(value)); 614 .ccr(channel.index())
592 self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); 615 .write_value(value.into());
593 } 616 #[cfg(stm32l0)]
594 #[cfg(not(stm32l0))] 617 self.regs_gp16()
595 TimerBits::Bits32 => { 618 .ccr(channel.index())
596 self.regs_gp32_unchecked().ccr(channel.index()).write_value(value); 619 .modify(|w| w.set_ccr(unwrap!(value.try_into())));
597 }
598 }
599 } 620 }
600 621
601 /// Get compare value for a channel. 622 /// Get compare value for a channel.
602 pub fn get_compare_value(&self, channel: Channel) -> u32 { 623 pub fn get_compare_value(&self, channel: Channel) -> T::Word {
603 match T::BITS { 624 #[cfg(not(stm32l0))]
604 TimerBits::Bits16 => self.regs_gp16().ccr(channel.index()).read().ccr() as u32, 625 return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().try_into());
605 #[cfg(not(stm32l0))] 626 #[cfg(stm32l0)]
606 TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(), 627 return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().ccr().try_into());
628 }
629
630 pub(crate) fn clamp_compare_value<W: Word>(&mut self, channel: Channel) {
631 self.set_compare_value(
632 channel,
633 unwrap!(
634 self.get_compare_value(channel)
635 .into()
636 .clamp(0, W::max() as u32)
637 .try_into()
638 ),
639 );
640 }
641
642 /// Setup a ring buffer for the channel
643 pub fn setup_ring_buffer<'a, W: Word + Into<T::Word>>(
644 &mut self,
645 dma: Peri<'a, impl super::UpDma<T>>,
646 channel: Channel,
647 dma_buf: &'a mut [W],
648 ) -> WritableRingBuffer<'a, W> {
649 #[allow(clippy::let_unit_value)] // eg. stm32f334
650 let req = dma.request();
651
652 unsafe {
653 use crate::dma::TransferOptions;
654 #[cfg(not(any(bdma, gpdma)))]
655 use crate::dma::{Burst, FifoThreshold};
656
657 let dma_transfer_option = TransferOptions {
658 #[cfg(not(any(bdma, gpdma)))]
659 fifo_threshold: Some(FifoThreshold::Full),
660 #[cfg(not(any(bdma, gpdma)))]
661 mburst: Burst::Incr8,
662 ..Default::default()
663 };
664
665 WritableRingBuffer::new(
666 dma,
667 req,
668 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut W,
669 dma_buf,
670 dma_transfer_option,
671 )
672 }
673 }
674
675 /// Generate a sequence of PWM waveform
676 ///
677 /// Note:
678 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
679 pub fn setup_update_dma<'a, W: Word + Into<T::Word>>(
680 &mut self,
681 dma: Peri<'a, impl super::UpDma<T>>,
682 channel: Channel,
683 duty: &'a [W],
684 ) -> Transfer<'a> {
685 self.setup_update_dma_inner(dma.request(), dma, channel, duty)
686 }
687
688 /// Generate a sequence of PWM waveform
689 ///
690 /// Note:
691 /// The DMA channel provided does not need to correspond to the requested channel.
692 pub fn setup_channel_update_dma<'a, C: TimerChannel, W: Word + Into<T::Word>>(
693 &mut self,
694 dma: Peri<'a, impl super::Dma<T, C>>,
695 channel: Channel,
696 duty: &'a [W],
697 ) -> Transfer<'a> {
698 self.setup_update_dma_inner(dma.request(), dma, channel, duty)
699 }
700
701 fn setup_update_dma_inner<'a, W: Word + Into<T::Word>>(
702 &mut self,
703 request: dma::Request,
704 dma: Peri<'a, impl dma::Channel>,
705 channel: Channel,
706 duty: &'a [W],
707 ) -> Transfer<'a> {
708 unsafe {
709 #[cfg(not(any(bdma, gpdma)))]
710 use crate::dma::{Burst, FifoThreshold};
711 use crate::dma::{Transfer, TransferOptions};
712
713 let dma_transfer_option = TransferOptions {
714 #[cfg(not(any(bdma, gpdma)))]
715 fifo_threshold: Some(FifoThreshold::Full),
716 #[cfg(not(any(bdma, gpdma)))]
717 mburst: Burst::Incr8,
718 ..Default::default()
719 };
720
721 Transfer::new_write(
722 dma,
723 request,
724 duty,
725 self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W,
726 dma_transfer_option,
727 )
728 }
729 }
730
731 /// Generate a multichannel sequence of PWM waveforms using DMA triggered by timer update events.
732 ///
733 /// This method utilizes the timer's DMA burst transfer capability to update multiple CCRx registers
734 /// in sequence on each update event (UEV). The data is written via the DMAR register using the
735 /// DMA base address (DBA) and burst length (DBL) configured in the DCR register.
736 ///
737 /// The `duty` buffer must be structured as a flattened 2D array in row-major order, where each row
738 /// represents a single update event and each column corresponds to a specific timer channel (starting
739 /// from `starting_channel` up to and including `ending_channel`).
740 ///
741 /// For example, if using channels 1 through 4, a buffer of 4 update steps might look like:
742 ///
743 /// ```rust,ignore
744 /// let dma_buf: [u16; 16] = [
745 /// ch1_duty_1, ch2_duty_1, ch3_duty_1, ch4_duty_1, // update 1
746 /// ch1_duty_2, ch2_duty_2, ch3_duty_2, ch4_duty_2, // update 2
747 /// ch1_duty_3, ch2_duty_3, ch3_duty_3, ch4_duty_3, // update 3
748 /// ch1_duty_4, ch2_duty_4, ch3_duty_4, ch4_duty_4, // update 4
749 /// ];
750 /// ```
751 ///
752 /// Each group of `N` values (where `N` is number of channels) is transferred on one update event,
753 /// updating the duty cycles of all selected channels simultaneously.
754 ///
755 /// Note:
756 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
757 /// Also be aware that embassy timers use one of timers internally. It is possible to
758 /// switch this timer by using `time-driver-timX` feature.
759 ///
760 pub fn setup_update_dma_burst<'a, W: Word + Into<T::Word>>(
761 &mut self,
762 dma: Peri<'a, impl super::UpDma<T>>,
763 starting_channel: Channel,
764 ending_channel: Channel,
765 duty: &'a [W],
766 ) -> Transfer<'a> {
767 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
768 let start_ch_index = starting_channel.index();
769 let end_ch_index = ending_channel.index();
770
771 assert!(start_ch_index <= end_ch_index);
772
773 let ccrx_addr = self.regs_gp16().ccr(start_ch_index).as_ptr() as u32;
774 self.regs_gp16()
775 .dcr()
776 .modify(|w| w.set_dba(((ccrx_addr - cr1_addr) / 4) as u8));
777 self.regs_gp16()
778 .dcr()
779 .modify(|w| w.set_dbl((end_ch_index - start_ch_index) as u8));
780
781 #[allow(clippy::let_unit_value)] // eg. stm32f334
782 let req = dma.request();
783
784 unsafe {
785 #[cfg(not(any(bdma, gpdma)))]
786 use crate::dma::{Burst, FifoThreshold};
787 use crate::dma::{Transfer, TransferOptions};
788
789 let dma_transfer_option = TransferOptions {
790 #[cfg(not(any(bdma, gpdma)))]
791 fifo_threshold: Some(FifoThreshold::Full),
792 #[cfg(not(any(bdma, gpdma)))]
793 mburst: Burst::Incr4,
794 ..Default::default()
795 };
796
797 Transfer::new_write(
798 dma,
799 req,
800 duty,
801 self.regs_gp16().dmar().as_ptr() as *mut W,
802 dma_transfer_option,
803 )
607 } 804 }
608 } 805 }
609 806
610 /// Get capture value for a channel. 807 /// Get capture value for a channel.
611 pub fn get_capture_value(&self, channel: Channel) -> u32 { 808 pub fn get_capture_value(&self, channel: Channel) -> T::Word {
612 self.get_compare_value(channel) 809 self.get_compare_value(channel)
613 } 810 }
614 811
@@ -640,6 +837,11 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
640 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde)) 837 self.regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
641 } 838 }
642 839
840 /// Set Timer Master Mode
841 pub fn set_master_mode(&self, mms: MasterMode) {
842 self.regs_gp16().cr2().modify(|w| w.set_mms(mms));
843 }
844
643 /// Set Timer Slave Mode 845 /// Set Timer Slave Mode
644 pub fn set_slave_mode(&self, sms: SlaveMode) { 846 pub fn set_slave_mode(&self, sms: SlaveMode) {
645 self.regs_gp16().smcr().modify(|r| r.set_sms(sms)); 847 self.regs_gp16().smcr().modify(|r| r.set_sms(sms));
@@ -760,6 +962,16 @@ impl<'d, T: AdvancedInstance4Channel> Timer<'d, T> {
760 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val)); 962 self.regs_advanced().cr2().modify(|w| w.set_oisn(channel.index(), val));
761 } 963 }
762 964
965 /// Set master mode selection 2
966 pub fn set_mms2_selection(&self, mms2: vals::Mms2) {
967 self.regs_advanced().cr2().modify(|w| w.set_mms2(mms2));
968 }
969
970 /// Set repetition counter
971 pub fn set_repetition_counter(&self, val: u16) {
972 self.regs_advanced().rcr().modify(|w| w.set_rep(val));
973 }
974
763 /// Trigger software break 1 or 2 975 /// Trigger software break 1 or 2
764 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware. 976 /// Setting this bit generates a break event. This bit is automatically cleared by the hardware.
765 pub fn trigger_software_break(&self, n: usize) { 977 pub fn trigger_software_break(&self, n: usize) {