aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-12-11 09:08:50 -0600
committerGitHub <[email protected]>2025-12-11 09:08:50 -0600
commit1aadce76847a7686bf66e3a6532e18e05042f78a (patch)
treeca42d80e784a6746065bd4e0c676db3ef0f10b93 /embassy-stm32/src/timer
parent52a9b08f0ca13d23bfb039c884a9101997c10567 (diff)
parentf650afc33b2d6b39116f27c6545c5f2d9e3c7d06 (diff)
Merge branch 'main' into main
Diffstat (limited to 'embassy-stm32/src/timer')
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs90
-rw-r--r--embassy-stm32/src/timer/input_capture.rs2
-rw-r--r--embassy-stm32/src/timer/low_level.rs235
-rw-r--r--embassy-stm32/src/timer/mod.rs34
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs12
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs14
-rw-r--r--embassy-stm32/src/timer/ringbuffered.rs29
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs82
8 files changed, 281 insertions, 217 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 77f19a37b..620d7858e 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -2,16 +2,17 @@
2 2
3use core::marker::PhantomData; 3use core::marker::PhantomData;
4 4
5pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr};
6
7use super::low_level::{CountingMode, OutputPolarity, Timer}; 5use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::PwmPin; 6use super::simple_pwm::PwmPin;
9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; 7use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
10use crate::Peri; 8use crate::Peri;
11use crate::gpio::{AnyPin, OutputType}; 9use crate::dma::word::Word;
10use crate::gpio::{AfType, AnyPin, OutputType};
11pub use crate::pac::timer::vals::{Ccds, Ckd, Mms2, Ossi, Ossr};
12use crate::time::Hertz; 12use crate::time::Hertz;
13use crate::timer::TimerChannel; 13use crate::timer::TimerChannel;
14use crate::timer::low_level::OutputCompareMode; 14use crate::timer::low_level::OutputCompareMode;
15use crate::timer::simple_pwm::PwmPinConfig;
15 16
16/// Complementary PWM pin wrapper. 17/// Complementary PWM pin wrapper.
17/// 18///
@@ -27,9 +28,27 @@ impl<'d, T: AdvancedInstance4Channel, C: TimerChannel, #[cfg(afio)] A> if_afio!(
27 pub fn new(pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, output_type: OutputType) -> Self { 28 pub fn new(pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>, output_type: OutputType) -> Self {
28 critical_section::with(|_| { 29 critical_section::with(|_| {
29 pin.set_low(); 30 pin.set_low();
30 set_as_af!( 31 set_as_af!(pin, AfType::output(output_type, crate::gpio::Speed::VeryHigh));
31 pin, 32 });
32 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh) 33 ComplementaryPwmPin {
34 pin: pin.into(),
35 phantom: PhantomData,
36 }
37 }
38
39 /// Create a new PWM pin instance with config.
40 pub fn new_with_config(
41 pin: Peri<'d, if_afio!(impl TimerComplementaryPin<T, C, A>)>,
42 pin_config: PwmPinConfig,
43 ) -> Self {
44 critical_section::with(|_| {
45 pin.set_low();
46 #[cfg(gpio_v1)]
47 set_as_af!(pin, AfType::output(pin_config.output_type, pin_config.speed));
48 #[cfg(gpio_v2)]
49 pin.set_as_af(
50 pin.af_num(),
51 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
33 ); 52 );
34 }); 53 });
35 ComplementaryPwmPin { 54 ComplementaryPwmPin {
@@ -176,20 +195,20 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
176 /// Get max duty value. 195 /// Get max duty value.
177 /// 196 ///
178 /// This value depends on the configured frequency and the timer's clock rate from RCC. 197 /// This value depends on the configured frequency and the timer's clock rate from RCC.
179 pub fn get_max_duty(&self) -> u16 { 198 pub fn get_max_duty(&self) -> u32 {
180 if self.inner.get_counting_mode().is_center_aligned() { 199 if self.inner.get_counting_mode().is_center_aligned() {
181 self.inner.get_max_compare_value() as u16 200 self.inner.get_max_compare_value().into()
182 } else { 201 } else {
183 self.inner.get_max_compare_value() as u16 + 1 202 self.inner.get_max_compare_value().into() + 1
184 } 203 }
185 } 204 }
186 205
187 /// Set the duty for a given channel. 206 /// Set the duty for a given channel.
188 /// 207 ///
189 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 208 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included.
190 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 209 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
191 assert!(duty <= self.get_max_duty()); 210 assert!(duty <= self.get_max_duty());
192 self.inner.set_compare_value(channel, duty as _) 211 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
193 } 212 }
194 213
195 /// Set the output polarity for a given channel. 214 /// Set the output polarity for a given channel.
@@ -219,9 +238,34 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
219 /// Generate a sequence of PWM waveform 238 /// Generate a sequence of PWM waveform
220 /// 239 ///
221 /// Note: 240 /// Note:
241 /// The DMA channel provided does not need to correspond to the requested channel.
242 pub async fn waveform<C: TimerChannel, W: Word + Into<T::Word>>(
243 &mut self,
244 dma: Peri<'_, impl super::Dma<T, C>>,
245 channel: Channel,
246 duty: &[W],
247 ) {
248 self.inner.enable_channel(channel, true);
249 self.inner.enable_channel(C::CHANNEL, true);
250 self.inner.clamp_compare_value::<W>(channel);
251 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE);
252 self.inner.set_cc_dma_enable_state(C::CHANNEL, true);
253 self.inner.setup_channel_update_dma(dma, channel, duty).await;
254 self.inner.set_cc_dma_enable_state(C::CHANNEL, false);
255 }
256
257 /// Generate a sequence of PWM waveform
258 ///
259 /// Note:
222 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 260 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
223 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 261 pub async fn waveform_up<W: Word + Into<T::Word>>(
262 &mut self,
263 dma: Peri<'_, impl super::UpDma<T>>,
264 channel: Channel,
265 duty: &[W],
266 ) {
224 self.inner.enable_channel(channel, true); 267 self.inner.enable_channel(channel, true);
268 self.inner.clamp_compare_value::<W>(channel);
225 self.inner.enable_update_dma(true); 269 self.inner.enable_update_dma(true);
226 self.inner.setup_update_dma(dma, channel, duty).await; 270 self.inner.setup_update_dma(dma, channel, duty).await;
227 self.inner.enable_update_dma(false); 271 self.inner.enable_update_dma(false);
@@ -256,13 +300,21 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
256 /// Also be aware that embassy timers use one of timers internally. It is possible to 300 /// Also be aware that embassy timers use one of timers internally. It is possible to
257 /// switch this timer by using `time-driver-timX` feature. 301 /// switch this timer by using `time-driver-timX` feature.
258 /// 302 ///
259 pub async fn waveform_up_multi_channel( 303 pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>(
260 &mut self, 304 &mut self,
261 dma: Peri<'_, impl super::UpDma<T>>, 305 dma: Peri<'_, impl super::UpDma<T>>,
262 starting_channel: Channel, 306 starting_channel: Channel,
263 ending_channel: Channel, 307 ending_channel: Channel,
264 duty: &[u16], 308 duty: &[W],
265 ) { 309 ) {
310 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
311 .iter()
312 .filter(|ch| ch.index() >= starting_channel.index())
313 .filter(|ch| ch.index() <= ending_channel.index())
314 .for_each(|ch| {
315 self.inner.enable_channel(*ch, true);
316 self.inner.clamp_compare_value::<W>(*ch);
317 });
266 self.inner.enable_update_dma(true); 318 self.inner.enable_update_dma(true);
267 self.inner 319 self.inner
268 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) 320 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
@@ -291,20 +343,20 @@ impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<
291 } 343 }
292 344
293 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 345 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
294 self.inner.get_compare_value(channel) as u16 346 unwrap!(self.inner.get_compare_value(channel).try_into())
295 } 347 }
296 348
297 fn get_max_duty(&self) -> Self::Duty { 349 fn get_max_duty(&self) -> Self::Duty {
298 if self.inner.get_counting_mode().is_center_aligned() { 350 if self.inner.get_counting_mode().is_center_aligned() {
299 self.inner.get_max_compare_value() as u16 351 unwrap!(self.inner.get_max_compare_value().try_into())
300 } else { 352 } else {
301 self.inner.get_max_compare_value() as u16 + 1 353 unwrap!(self.inner.get_max_compare_value().try_into()) + 1
302 } 354 }
303 } 355 }
304 356
305 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 357 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
306 assert!(duty <= self.get_max_duty()); 358 assert!(duty <= unwrap!(self.get_max_duty().try_into()));
307 self.inner.set_compare_value(channel, duty as u32) 359 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
308 } 360 }
309 361
310 fn set_period<P>(&mut self, period: P) 362 fn set_period<P>(&mut self, period: P)
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index 9cf0f8c34..3e1482b67 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -97,7 +97,7 @@ impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
97 97
98 /// Get capture value for a channel. 98 /// Get capture value for a channel.
99 pub fn get_capture_value(&self, channel: Channel) -> u32 { 99 pub fn get_capture_value(&self, channel: Channel) -> u32 {
100 self.inner.get_capture_value(channel) 100 self.inner.get_capture_value(channel).into()
101 } 101 }
102 102
103 /// Get input interrupt. 103 /// Get input interrupt.
diff --git a/embassy-stm32/src/timer/low_level.rs b/embassy-stm32/src/timer/low_level.rs
index aba08081f..82e936f3a 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;
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, WritableRingBuffer}; 16use crate::dma::{self, Transfer, WritableRingBuffer};
17use crate::pac::timer::vals; 17use crate::pac::timer::vals;
18use crate::rcc; 18use crate::rcc;
19use crate::time::Hertz; 19use crate::time::Hertz;
@@ -268,6 +268,11 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
268 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) } 268 unsafe { crate::pac::timer::TimGp32::from_ptr(T::regs()) }
269 } 269 }
270 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
271 /// Start the timer. 276 /// Start the timer.
272 pub fn start(&self) { 277 pub fn start(&self) {
273 self.regs_core().cr1().modify(|r| r.set_cen(true)); 278 self.regs_core().cr1().modify(|r| r.set_cen(true));
@@ -296,7 +301,12 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
296 301
297 /// get the capability of the timer 302 /// get the capability of the timer
298 pub fn bits(&self) -> TimerBits { 303 pub fn bits(&self) -> TimerBits {
299 T::BITS 304 match T::Word::bits() {
305 16 => TimerBits::Bits16,
306 #[cfg(not(stm32l0))]
307 32 => TimerBits::Bits32,
308 _ => unreachable!(),
309 }
300 } 310 }
301 311
302 /// 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.
@@ -306,18 +316,10 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
306 /// 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
307 /// because it needs to count up and down. 317 /// because it needs to count up and down.
308 pub fn set_frequency(&self, frequency: Hertz) { 318 pub fn set_frequency(&self, frequency: Hertz) {
309 match T::BITS { 319 self.set_frequency_internal(frequency, T::Word::bits());
310 TimerBits::Bits16 => {
311 self.set_frequency_internal(frequency, 16);
312 }
313 #[cfg(not(stm32l0))]
314 TimerBits::Bits32 => {
315 self.set_frequency_internal(frequency, 32);
316 }
317 }
318 } 320 }
319 321
320 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) {
321 let f = frequency.0; 323 let f = frequency.0;
322 assert!(f > 0); 324 assert!(f > 0);
323 let timer_f = T::frequency().0; 325 let timer_f = T::frequency().0;
@@ -326,25 +328,15 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
326 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());
327 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);
328 330
329 match T::BITS { 331 // the timer counts `0..=arr`, we want it to count `0..divide_by`
330 TimerBits::Bits16 => { 332 let arr: T::Word = unwrap!(T::Word::try_from(divide_by - 1));
331 // the timer counts `0..=arr`, we want it to count `0..divide_by`
332 let arr = unwrap!(u16::try_from(divide_by - 1));
333
334 let regs = self.regs_core();
335 regs.psc().write_value(psc);
336 regs.arr().write(|r| r.set_arr(arr));
337 }
338 #[cfg(not(stm32l0))]
339 TimerBits::Bits32 => {
340 // the timer counts `0..=arr`, we want it to count `0..divide_by`
341 let arr: u32 = unwrap!(u32::try_from(divide_by - 1));
342 333
343 let regs = self.regs_gp32_unchecked(); 334 let regs = self.regs_gp32_unchecked();
344 regs.psc().write_value(psc); 335 regs.psc().write_value(psc);
345 regs.arr().write_value(arr); 336 #[cfg(stm32l0)]
346 } 337 regs.arr().write(|r| r.set_arr(unwrap!(arr.try_into())));
347 } 338 #[cfg(not(stm32l0))]
339 regs.arr().write_value(arr.into());
348 } 340 }
349 341
350 /// Set tick frequency. 342 /// Set tick frequency.
@@ -393,23 +385,14 @@ impl<'d, T: CoreInstance> Timer<'d, T> {
393 pub fn get_frequency(&self) -> Hertz { 385 pub fn get_frequency(&self) -> Hertz {
394 let timer_f = T::frequency(); 386 let timer_f = T::frequency();
395 387
396 match T::BITS { 388 let regs = self.regs_gp32_unchecked();
397 TimerBits::Bits16 => { 389 #[cfg(not(stm32l0))]
398 let regs = self.regs_core(); 390 let arr = regs.arr().read();
399 let arr = regs.arr().read().arr(); 391 #[cfg(stm32l0)]
400 let psc = regs.psc().read(); 392 let arr = regs.arr().read().arr();
393 let psc = regs.psc().read();
401 394
402 timer_f / arr / (psc + 1) 395 timer_f / arr / (psc + 1)
403 }
404 #[cfg(not(stm32l0))]
405 TimerBits::Bits32 => {
406 let regs = self.regs_gp32_unchecked();
407 let arr = regs.arr().read();
408 let psc = regs.psc().read();
409
410 timer_f / arr / (psc + 1)
411 }
412 }
413 } 396 }
414 397
415 /// Get the clock frequency of the timer (before prescaler is applied). 398 /// Get the clock frequency of the timer (before prescaler is applied).
@@ -469,42 +452,29 @@ impl<'d, T: GeneralInstance1Channel> Timer<'d, T> {
469 } 452 }
470 453
471 /// 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.
472 pub fn get_max_compare_value(&self) -> u32 { 455 pub fn get_max_compare_value(&self) -> T::Word {
473 match T::BITS { 456 #[cfg(not(stm32l0))]
474 TimerBits::Bits16 => self.regs_1ch().arr().read().arr() as u32, 457 return unwrap!(self.regs_gp32_unchecked().arr().read().try_into());
475 #[cfg(not(stm32l0))] 458 #[cfg(stm32l0)]
476 TimerBits::Bits32 => self.regs_gp32_unchecked().arr().read(), 459 return unwrap!(self.regs_gp32_unchecked().arr().read().arr().try_into());
477 }
478 } 460 }
479 461
480 /// Set the max compare value. 462 /// Set the max compare value.
481 /// 463 ///
482 /// 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
483 /// 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.
484 pub fn set_max_compare_value(&self, ticks: u32) { 466 pub fn set_max_compare_value(&self, ticks: T::Word) {
485 match T::BITS { 467 let arr = ticks;
486 TimerBits::Bits16 => {
487 let arr = unwrap!(u16::try_from(ticks));
488 468
489 let regs = self.regs_1ch(); 469 let regs = self.regs_gp32_unchecked();
490 regs.arr().write(|r| r.set_arr(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())));
491 474
492 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY)); 475 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
493 regs.egr().write(|r| r.set_ug(true)); 476 regs.egr().write(|r| r.set_ug(true));
494 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT)); 477 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
495 }
496 #[cfg(not(stm32l0))]
497 TimerBits::Bits32 => {
498 let arr = ticks;
499
500 let regs = self.regs_gp32_unchecked();
501 regs.arr().write_value(arr);
502
503 regs.cr1().modify(|r| r.set_urs(vals::Urs::COUNTER_ONLY));
504 regs.egr().write(|r| r.set_ug(true));
505 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANY_EVENT));
506 }
507 }
508 } 478 }
509} 479}
510 480
@@ -638,35 +608,44 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
638 } 608 }
639 609
640 /// Set compare value for a channel. 610 /// Set compare value for a channel.
641 pub fn set_compare_value(&self, channel: Channel, value: u32) { 611 pub fn set_compare_value(&self, channel: Channel, value: T::Word) {
642 match T::BITS { 612 #[cfg(not(stm32l0))]
643 TimerBits::Bits16 => { 613 self.regs_gp32_unchecked()
644 let value = unwrap!(u16::try_from(value)); 614 .ccr(channel.index())
645 self.regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); 615 .write_value(value.into());
646 } 616 #[cfg(stm32l0)]
647 #[cfg(not(stm32l0))] 617 self.regs_gp16()
648 TimerBits::Bits32 => { 618 .ccr(channel.index())
649 self.regs_gp32_unchecked().ccr(channel.index()).write_value(value); 619 .modify(|w| w.set_ccr(unwrap!(value.try_into())));
650 }
651 }
652 } 620 }
653 621
654 /// Get compare value for a channel. 622 /// Get compare value for a channel.
655 pub fn get_compare_value(&self, channel: Channel) -> u32 { 623 pub fn get_compare_value(&self, channel: Channel) -> T::Word {
656 match T::BITS { 624 #[cfg(not(stm32l0))]
657 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());
658 #[cfg(not(stm32l0))] 626 #[cfg(stm32l0)]
659 TimerBits::Bits32 => self.regs_gp32_unchecked().ccr(channel.index()).read(), 627 return unwrap!(self.regs_gp32_unchecked().ccr(channel.index()).read().ccr().try_into());
660 } 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 );
661 } 640 }
662 641
663 /// Setup a ring buffer for the channel 642 /// Setup a ring buffer for the channel
664 pub fn setup_ring_buffer<'a>( 643 pub fn setup_ring_buffer<'a, W: Word + Into<T::Word>>(
665 &mut self, 644 &mut self,
666 dma: Peri<'a, impl super::UpDma<T>>, 645 dma: Peri<'a, impl super::UpDma<T>>,
667 channel: Channel, 646 channel: Channel,
668 dma_buf: &'a mut [u16], 647 dma_buf: &'a mut [W],
669 ) -> WritableRingBuffer<'a, u16> { 648 ) -> WritableRingBuffer<'a, W> {
670 #[allow(clippy::let_unit_value)] // eg. stm32f334 649 #[allow(clippy::let_unit_value)] // eg. stm32f334
671 let req = dma.request(); 650 let req = dma.request();
672 651
@@ -686,7 +665,7 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
686 WritableRingBuffer::new( 665 WritableRingBuffer::new(
687 dma, 666 dma,
688 req, 667 req,
689 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, 668 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut W,
690 dma_buf, 669 dma_buf,
691 dma_transfer_option, 670 dma_transfer_option,
692 ) 671 )
@@ -697,15 +676,35 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
697 /// 676 ///
698 /// Note: 677 /// Note:
699 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 678 /// you will need to provide corresponding TIMx_UP DMA channel to use this method.
700 pub fn setup_update_dma<'a>( 679 pub fn setup_update_dma<'a, W: Word + Into<T::Word>>(
701 &mut self, 680 &mut self,
702 dma: Peri<'a, impl super::UpDma<T>>, 681 dma: Peri<'a, impl super::UpDma<T>>,
703 channel: Channel, 682 channel: Channel,
704 duty: &'a [u16], 683 duty: &'a [W],
705 ) -> Transfer<'a> { 684 ) -> Transfer<'a> {
706 #[allow(clippy::let_unit_value)] // eg. stm32f334 685 self.setup_update_dma_inner(dma.request(), dma, channel, duty)
707 let req = dma.request(); 686 }
708 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> {
709 unsafe { 708 unsafe {
710 #[cfg(not(any(bdma, gpdma)))] 709 #[cfg(not(any(bdma, gpdma)))]
711 use crate::dma::{Burst, FifoThreshold}; 710 use crate::dma::{Burst, FifoThreshold};
@@ -719,29 +718,13 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
719 ..Default::default() 718 ..Default::default()
720 }; 719 };
721 720
722 match self.bits() { 721 Transfer::new_write(
723 TimerBits::Bits16 => Transfer::new_write( 722 dma,
724 dma, 723 request,
725 req, 724 duty,
726 duty, 725 self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W,
727 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, 726 dma_transfer_option,
728 dma_transfer_option, 727 )
729 ),
730 #[cfg(not(any(stm32l0)))]
731 TimerBits::Bits32 => {
732 #[cfg(not(any(bdma, gpdma)))]
733 panic!("unsupported timer bits");
734
735 #[cfg(any(bdma, gpdma))]
736 Transfer::new_write(
737 dma,
738 req,
739 duty,
740 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u32,
741 dma_transfer_option,
742 )
743 }
744 }
745 } 728 }
746 } 729 }
747 730
@@ -774,12 +757,12 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
774 /// Also be aware that embassy timers use one of timers internally. It is possible to 757 /// Also be aware that embassy timers use one of timers internally. It is possible to
775 /// switch this timer by using `time-driver-timX` feature. 758 /// switch this timer by using `time-driver-timX` feature.
776 /// 759 ///
777 pub fn setup_update_dma_burst<'a>( 760 pub fn setup_update_dma_burst<'a, W: Word + Into<T::Word>>(
778 &mut self, 761 &mut self,
779 dma: Peri<'a, impl super::UpDma<T>>, 762 dma: Peri<'a, impl super::UpDma<T>>,
780 starting_channel: Channel, 763 starting_channel: Channel,
781 ending_channel: Channel, 764 ending_channel: Channel,
782 duty: &'a [u16], 765 duty: &'a [W],
783 ) -> Transfer<'a> { 766 ) -> Transfer<'a> {
784 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; 767 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
785 let start_ch_index = starting_channel.index(); 768 let start_ch_index = starting_channel.index();
@@ -815,14 +798,14 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
815 dma, 798 dma,
816 req, 799 req,
817 duty, 800 duty,
818 self.regs_gp16().dmar().as_ptr() as *mut u16, 801 self.regs_gp16().dmar().as_ptr() as *mut W,
819 dma_transfer_option, 802 dma_transfer_option,
820 ) 803 )
821 } 804 }
822 } 805 }
823 806
824 /// Get capture value for a channel. 807 /// Get capture value for a channel.
825 pub fn get_capture_value(&self, channel: Channel) -> u32 { 808 pub fn get_capture_value(&self, channel: Channel) -> T::Word {
826 self.get_compare_value(channel) 809 self.get_compare_value(channel)
827 } 810 }
828 811
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 3fa363881..998e3a6f4 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -15,6 +15,8 @@ pub mod qei;
15pub mod ringbuffered; 15pub mod ringbuffered;
16pub mod simple_pwm; 16pub mod simple_pwm;
17 17
18use crate::dma::word::Word;
19use crate::fmt::Debuggable;
18use crate::interrupt; 20use crate::interrupt;
19use crate::rcc::RccPeripheral; 21use crate::rcc::RccPeripheral;
20 22
@@ -163,7 +165,12 @@ pub trait CoreInstance: SealedInstance + 'static {
163 type UpdateInterrupt: interrupt::typelevel::Interrupt; 165 type UpdateInterrupt: interrupt::typelevel::Interrupt;
164 166
165 /// Amount of bits this timer has. 167 /// Amount of bits this timer has.
166 const BITS: TimerBits; 168 type Word: Word
169 + TryInto<u16, Error: Debuggable>
170 + From<u16>
171 + TryFrom<u32, Error: Debuggable>
172 + Into<u32>
173 + TryFrom<u64, Error: Debuggable>;
167 174
168 /// Registers for this timer. 175 /// Registers for this timer.
169 /// 176 ///
@@ -241,7 +248,7 @@ dma_trait!(Dma, GeneralInstance4Channel, TimerChannel);
241 248
242#[allow(unused)] 249#[allow(unused)]
243macro_rules! impl_core_timer { 250macro_rules! impl_core_timer {
244 ($inst:ident, $bits:expr) => { 251 ($inst:ident, $bits:ident) => {
245 impl SealedInstance for crate::peripherals::$inst { 252 impl SealedInstance for crate::peripherals::$inst {
246 fn state() -> &'static State { 253 fn state() -> &'static State {
247 static STATE: State = State::new(); 254 static STATE: State = State::new();
@@ -251,8 +258,7 @@ macro_rules! impl_core_timer {
251 258
252 impl CoreInstance for crate::peripherals::$inst { 259 impl CoreInstance for crate::peripherals::$inst {
253 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP; 260 type UpdateInterrupt = crate::_generated::peripheral_interrupts::$inst::UP;
254 261 type Word = $bits;
255 const BITS: TimerBits = $bits;
256 262
257 fn regs() -> *mut () { 263 fn regs() -> *mut () {
258 crate::pac::$inst.as_ptr() 264 crate::pac::$inst.as_ptr()
@@ -306,13 +312,13 @@ macro_rules! impl_general_4ch_blank_sealed {
306 312
307foreach_interrupt! { 313foreach_interrupt! {
308 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { 314 ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => {
309 impl_core_timer!($inst, TimerBits::Bits16); 315 impl_core_timer!($inst, u16);
310 impl BasicNoCr2Instance for crate::peripherals::$inst {} 316 impl BasicNoCr2Instance for crate::peripherals::$inst {}
311 impl BasicInstance for crate::peripherals::$inst {} 317 impl BasicInstance for crate::peripherals::$inst {}
312 }; 318 };
313 319
314 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => { 320 ($inst:ident, timer, TIM_1CH, UP, $irq:ident) => {
315 impl_core_timer!($inst, TimerBits::Bits16); 321 impl_core_timer!($inst, u16);
316 impl BasicNoCr2Instance for crate::peripherals::$inst {} 322 impl BasicNoCr2Instance for crate::peripherals::$inst {}
317 impl BasicInstance for crate::peripherals::$inst {} 323 impl BasicInstance for crate::peripherals::$inst {}
318 impl_general_1ch!($inst); 324 impl_general_1ch!($inst);
@@ -322,7 +328,7 @@ foreach_interrupt! {
322 }; 328 };
323 329
324 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => { 330 ($inst:ident, timer, TIM_2CH, UP, $irq:ident) => {
325 impl_core_timer!($inst, TimerBits::Bits16); 331 impl_core_timer!($inst, u16);
326 impl BasicNoCr2Instance for crate::peripherals::$inst {} 332 impl BasicNoCr2Instance for crate::peripherals::$inst {}
327 impl BasicInstance for crate::peripherals::$inst {} 333 impl BasicInstance for crate::peripherals::$inst {}
328 impl_general_1ch!($inst); 334 impl_general_1ch!($inst);
@@ -332,7 +338,7 @@ foreach_interrupt! {
332 }; 338 };
333 339
334 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { 340 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
335 impl_core_timer!($inst, TimerBits::Bits16); 341 impl_core_timer!($inst, u16);
336 impl BasicNoCr2Instance for crate::peripherals::$inst {} 342 impl BasicNoCr2Instance for crate::peripherals::$inst {}
337 impl BasicInstance for crate::peripherals::$inst {} 343 impl BasicInstance for crate::peripherals::$inst {}
338 impl_general_1ch!($inst); 344 impl_general_1ch!($inst);
@@ -342,7 +348,7 @@ foreach_interrupt! {
342 }; 348 };
343 349
344 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { 350 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
345 impl_core_timer!($inst, TimerBits::Bits32); 351 impl_core_timer!($inst, u32);
346 impl BasicNoCr2Instance for crate::peripherals::$inst {} 352 impl BasicNoCr2Instance for crate::peripherals::$inst {}
347 impl BasicInstance for crate::peripherals::$inst {} 353 impl BasicInstance for crate::peripherals::$inst {}
348 impl_general_1ch!($inst); 354 impl_general_1ch!($inst);
@@ -353,7 +359,7 @@ foreach_interrupt! {
353 }; 359 };
354 360
355 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => { 361 ($inst:ident, timer, TIM_1CH_CMP, UP, $irq:ident) => {
356 impl_core_timer!($inst, TimerBits::Bits16); 362 impl_core_timer!($inst, u16);
357 impl BasicNoCr2Instance for crate::peripherals::$inst {} 363 impl BasicNoCr2Instance for crate::peripherals::$inst {}
358 impl BasicInstance for crate::peripherals::$inst {} 364 impl BasicInstance for crate::peripherals::$inst {}
359 impl_general_1ch!($inst); 365 impl_general_1ch!($inst);
@@ -366,7 +372,7 @@ foreach_interrupt! {
366 }; 372 };
367 373
368 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => { 374 ($inst:ident, timer, TIM_2CH_CMP, UP, $irq:ident) => {
369 impl_core_timer!($inst, TimerBits::Bits16); 375 impl_core_timer!($inst, u16);
370 impl BasicNoCr2Instance for crate::peripherals::$inst {} 376 impl BasicNoCr2Instance for crate::peripherals::$inst {}
371 impl BasicInstance for crate::peripherals::$inst {} 377 impl BasicInstance for crate::peripherals::$inst {}
372 impl_general_1ch!($inst); 378 impl_general_1ch!($inst);
@@ -379,7 +385,7 @@ foreach_interrupt! {
379 }; 385 };
380 386
381 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { 387 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
382 impl_core_timer!($inst, TimerBits::Bits16); 388 impl_core_timer!($inst, u16);
383 impl BasicNoCr2Instance for crate::peripherals::$inst {} 389 impl BasicNoCr2Instance for crate::peripherals::$inst {}
384 impl BasicInstance for crate::peripherals::$inst {} 390 impl BasicInstance for crate::peripherals::$inst {}
385 impl_general_1ch!($inst); 391 impl_general_1ch!($inst);
@@ -400,7 +406,7 @@ pub struct UpdateInterruptHandler<T: CoreInstance> {
400impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> { 406impl<T: CoreInstance> interrupt::typelevel::Handler<T::UpdateInterrupt> for UpdateInterruptHandler<T> {
401 unsafe fn on_interrupt() { 407 unsafe fn on_interrupt() {
402 #[cfg(feature = "low-power")] 408 #[cfg(feature = "low-power")]
403 crate::low_power::Executor::on_wakeup_irq(); 409 crate::low_power::Executor::on_wakeup_irq_or_event();
404 410
405 let regs = crate::pac::timer::TimCore::from_ptr(T::regs()); 411 let regs = crate::pac::timer::TimCore::from_ptr(T::regs());
406 412
@@ -430,7 +436,7 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
430{ 436{
431 unsafe fn on_interrupt() { 437 unsafe fn on_interrupt() {
432 #[cfg(feature = "low-power")] 438 #[cfg(feature = "low-power")]
433 crate::low_power::Executor::on_wakeup_irq(); 439 crate::low_power::Executor::on_wakeup_irq_or_event();
434 440
435 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs()); 441 let regs = crate::pac::timer::TimGp16::from_ptr(T::regs());
436 442
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
index fe8681356..989e1d630 100644
--- a/embassy-stm32/src/timer/one_pulse.rs
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -199,7 +199,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
199 fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) { 199 fn new_inner(&mut self, freq: Hertz, pulse_end: u32, counting_mode: CountingMode) {
200 self.inner.set_counting_mode(counting_mode); 200 self.inner.set_counting_mode(counting_mode);
201 self.inner.set_tick_freq(freq); 201 self.inner.set_tick_freq(freq);
202 self.inner.set_max_compare_value(pulse_end); 202 self.inner.set_max_compare_value(unwrap!(pulse_end.try_into()));
203 self.inner.regs_core().cr1().modify(|r| r.set_opm(true)); 203 self.inner.regs_core().cr1().modify(|r| r.set_opm(true));
204 // Required for advanced timers, see GeneralInstance4Channel for details 204 // Required for advanced timers, see GeneralInstance4Channel for details
205 self.inner.enable_outputs(); 205 self.inner.enable_outputs();
@@ -211,14 +211,14 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
211 211
212 /// Get the end of the pulse in ticks from the trigger. 212 /// Get the end of the pulse in ticks from the trigger.
213 pub fn pulse_end(&self) -> u32 { 213 pub fn pulse_end(&self) -> u32 {
214 let max = self.inner.get_max_compare_value(); 214 let max: u32 = self.inner.get_max_compare_value().into();
215 assert!(max < u32::MAX); 215 assert!(max < u32::MAX);
216 max + 1 216 max + 1
217 } 217 }
218 218
219 /// Set the end of the pulse in ticks from the trigger. 219 /// Set the end of the pulse in ticks from the trigger.
220 pub fn set_pulse_end(&mut self, ticks: u32) { 220 pub fn set_pulse_end(&mut self, ticks: u32) {
221 self.inner.set_max_compare_value(ticks) 221 self.inner.set_max_compare_value(unwrap!(ticks.try_into()))
222 } 222 }
223 223
224 /// Reset the timer on each trigger 224 /// Reset the timer on each trigger
@@ -327,7 +327,7 @@ pub struct OnePulseChannel<'d, T: GeneralInstance4Channel> {
327impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> { 327impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
328 /// Get the end of the pulse in ticks from the trigger. 328 /// Get the end of the pulse in ticks from the trigger.
329 pub fn pulse_end(&self) -> u32 { 329 pub fn pulse_end(&self) -> u32 {
330 let max = self.inner.get_max_compare_value(); 330 let max: u32 = self.inner.get_max_compare_value().into();
331 assert!(max < u32::MAX); 331 assert!(max < u32::MAX);
332 max + 1 332 max + 1
333 } 333 }
@@ -339,13 +339,13 @@ impl<'d, T: GeneralInstance4Channel> OnePulseChannel<'d, T> {
339 339
340 /// Get the start of the pulse in ticks from the trigger. 340 /// Get the start of the pulse in ticks from the trigger.
341 pub fn pulse_delay(&mut self) -> u32 { 341 pub fn pulse_delay(&mut self) -> u32 {
342 self.inner.get_compare_value(self.channel) 342 self.inner.get_compare_value(self.channel).into()
343 } 343 }
344 344
345 /// Set the start of the pulse in ticks from the trigger. 345 /// Set the start of the pulse in ticks from the trigger.
346 pub fn set_pulse_delay(&mut self, delay: u32) { 346 pub fn set_pulse_delay(&mut self, delay: u32) {
347 assert!(delay <= self.pulse_end()); 347 assert!(delay <= self.pulse_end());
348 self.inner.set_compare_value(self.channel, delay); 348 self.inner.set_compare_value(self.channel, unwrap!(delay.try_into()));
349 } 349 }
350 350
351 /// Set the pulse width in ticks. 351 /// Set the pulse width in ticks.
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index 057ab011a..f2f00927d 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -91,16 +91,18 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
91 91
92 /// Get the period tick count 92 /// Get the period tick count
93 pub fn get_period_ticks(&self) -> u32 { 93 pub fn get_period_ticks(&self) -> u32 {
94 self.inner.get_capture_value(self.channel) 94 self.inner.get_capture_value(self.channel).into()
95 } 95 }
96 96
97 /// Get the pulse width tick count 97 /// Get the pulse width tick count
98 pub fn get_width_ticks(&self) -> u32 { 98 pub fn get_width_ticks(&self) -> u32 {
99 self.inner.get_capture_value(match self.channel { 99 self.inner
100 Channel::Ch1 => Channel::Ch2, 100 .get_capture_value(match self.channel {
101 Channel::Ch2 => Channel::Ch1, 101 Channel::Ch1 => Channel::Ch2,
102 _ => panic!("Invalid channel for PWM input"), 102 Channel::Ch2 => Channel::Ch1,
103 }) 103 _ => panic!("Invalid channel for PWM input"),
104 })
105 .into()
104 } 106 }
105 107
106 /// Get the duty cycle in 100% 108 /// Get the duty cycle in 100%
diff --git a/embassy-stm32/src/timer/ringbuffered.rs b/embassy-stm32/src/timer/ringbuffered.rs
index e8f97bf59..fbb6b19ea 100644
--- a/embassy-stm32/src/timer/ringbuffered.rs
+++ b/embassy-stm32/src/timer/ringbuffered.rs
@@ -7,6 +7,7 @@ use super::low_level::Timer;
7use super::{Channel, GeneralInstance4Channel}; 7use super::{Channel, GeneralInstance4Channel};
8use crate::dma::WritableRingBuffer; 8use crate::dma::WritableRingBuffer;
9use crate::dma::ringbuffer::Error; 9use crate::dma::ringbuffer::Error;
10use crate::dma::word::Word;
10 11
11/// A PWM channel that uses a DMA ring buffer for continuous waveform generation. 12/// A PWM channel that uses a DMA ring buffer for continuous waveform generation.
12/// 13///
@@ -23,17 +24,17 @@ use crate::dma::ringbuffer::Error;
23/// channel.start(); // Start DMA transfer 24/// channel.start(); // Start DMA transfer
24/// channel.write(&[100, 200, 300]).ok(); // Update duty cycles 25/// channel.write(&[100, 200, 300]).ok(); // Update duty cycles
25/// ``` 26/// ```
26pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel> { 27pub struct RingBufferedPwmChannel<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> {
27 timer: ManuallyDrop<Timer<'d, T>>, 28 timer: ManuallyDrop<Timer<'d, T>>,
28 ring_buf: WritableRingBuffer<'d, u16>, 29 ring_buf: WritableRingBuffer<'d, W>,
29 channel: Channel, 30 channel: Channel,
30} 31}
31 32
32impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> { 33impl<'d, T: GeneralInstance4Channel, W: Word + Into<T::Word>> RingBufferedPwmChannel<'d, T, W> {
33 pub(crate) fn new( 34 pub(crate) fn new(
34 timer: ManuallyDrop<Timer<'d, T>>, 35 timer: ManuallyDrop<Timer<'d, T>>,
35 channel: Channel, 36 channel: Channel,
36 ring_buf: WritableRingBuffer<'d, u16>, 37 ring_buf: WritableRingBuffer<'d, W>,
37 ) -> Self { 38 ) -> Self {
38 Self { 39 Self {
39 timer, 40 timer,
@@ -55,18 +56,18 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> {
55 } 56 }
56 57
57 /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer. 58 /// Write elements directly to the raw buffer. This can be used to fill the buffer before starting the DMA transfer.
58 pub fn write_immediate(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> { 59 pub fn write_immediate(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
59 self.ring_buf.write_immediate(buf) 60 self.ring_buf.write_immediate(buf)
60 } 61 }
61 62
62 /// Write elements from the ring buffer 63 /// Write elements from the ring buffer
63 /// Return a tuple of the length written and the length remaining in the buffer 64 /// Return a tuple of the length written and the length remaining in the buffer
64 pub fn write(&mut self, buf: &[u16]) -> Result<(usize, usize), Error> { 65 pub fn write(&mut self, buf: &[W]) -> Result<(usize, usize), Error> {
65 self.ring_buf.write(buf) 66 self.ring_buf.write(buf)
66 } 67 }
67 68
68 /// Write an exact number of elements to the ringbuffer. 69 /// Write an exact number of elements to the ringbuffer.
69 pub async fn write_exact(&mut self, buffer: &[u16]) -> Result<usize, Error> { 70 pub async fn write_exact(&mut self, buffer: &[W]) -> Result<usize, Error> {
70 self.ring_buf.write_exact(buffer).await 71 self.ring_buf.write_exact(buffer).await
71 } 72 }
72 73
@@ -140,7 +141,7 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> {
140 /// 141 ///
141 /// This value depends on the configured frequency and the timer's clock rate from RCC. 142 /// This value depends on the configured frequency and the timer's clock rate from RCC.
142 pub fn max_duty_cycle(&self) -> u16 { 143 pub fn max_duty_cycle(&self) -> u16 {
143 let max = self.timer.get_max_compare_value(); 144 let max: u32 = self.timer.get_max_compare_value().into();
144 assert!(max < u16::MAX as u32); 145 assert!(max < u16::MAX as u32);
145 max as u16 + 1 146 max as u16 + 1
146 } 147 }
@@ -155,15 +156,3 @@ impl<'d, T: GeneralInstance4Channel> RingBufferedPwmChannel<'d, T> {
155 self.timer.set_output_compare_mode(self.channel, mode); 156 self.timer.set_output_compare_mode(self.channel, mode);
156 } 157 }
157} 158}
158
159/// A group of four [`SimplePwmChannel`]s, obtained from [`SimplePwm::split`].
160pub struct RingBufferedPwmChannels<'d, T: GeneralInstance4Channel> {
161 /// Channel 1
162 pub ch1: RingBufferedPwmChannel<'d, T>,
163 /// Channel 2
164 pub ch2: RingBufferedPwmChannel<'d, T>,
165 /// Channel 3
166 pub ch3: RingBufferedPwmChannel<'d, T>,
167 /// Channel 4
168 pub ch4: RingBufferedPwmChannel<'d, T>,
169}
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 484e9fd81..9a5f0fd1d 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -7,9 +7,11 @@ use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
7use super::ringbuffered::RingBufferedPwmChannel; 7use super::ringbuffered::RingBufferedPwmChannel;
8use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin}; 8use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerChannel, TimerPin};
9use crate::Peri; 9use crate::Peri;
10use crate::dma::word::Word;
10#[cfg(gpio_v2)] 11#[cfg(gpio_v2)]
11use crate::gpio::Pull; 12use crate::gpio::Pull;
12use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 13use crate::gpio::{AfType, AnyPin, OutputType, Speed};
14use crate::pac::timer::vals::Ccds;
13use crate::time::Hertz; 15use crate::time::Hertz;
14 16
15/// PWM pin wrapper. 17/// PWM pin wrapper.
@@ -98,18 +100,16 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
98 /// Get max duty value. 100 /// Get max duty value.
99 /// 101 ///
100 /// This value depends on the configured frequency and the timer's clock rate from RCC. 102 /// This value depends on the configured frequency and the timer's clock rate from RCC.
101 pub fn max_duty_cycle(&self) -> u16 { 103 pub fn max_duty_cycle(&self) -> u32 {
102 let max = self.timer.get_max_compare_value(); 104 self.timer.get_max_compare_value().into() + 1
103 assert!(max < u16::MAX as u32);
104 max as u16 + 1
105 } 105 }
106 106
107 /// Set the duty for a given channel. 107 /// Set the duty for a given channel.
108 /// 108 ///
109 /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. 109 /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included.
110 pub fn set_duty_cycle(&mut self, duty: u16) { 110 pub fn set_duty_cycle(&mut self, duty: u32) {
111 assert!(duty <= (*self).max_duty_cycle()); 111 assert!(duty <= (*self).max_duty_cycle());
112 self.timer.set_compare_value(self.channel, duty.into()) 112 self.timer.set_compare_value(self.channel, unwrap!(duty.try_into()))
113 } 113 }
114 114
115 /// Set the duty cycle to 0%, or always inactive. 115 /// Set the duty cycle to 0%, or always inactive.
@@ -126,21 +126,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
126 /// 126 ///
127 /// The caller is responsible for ensuring that `num` is less than or equal to `denom`, 127 /// The caller is responsible for ensuring that `num` is less than or equal to `denom`,
128 /// and that `denom` is not zero. 128 /// and that `denom` is not zero.
129 pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { 129 pub fn set_duty_cycle_fraction(&mut self, num: u32, denom: u32) {
130 assert!(denom != 0); 130 assert!(denom != 0);
131 assert!(num <= denom); 131 assert!(num <= denom);
132 let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); 132 let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom);
133 133
134 // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16) 134 // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16)
135 #[allow(clippy::cast_possible_truncation)] 135 #[allow(clippy::cast_possible_truncation)]
136 self.set_duty_cycle(duty as u16); 136 self.set_duty_cycle(unwrap!(duty.try_into()));
137 } 137 }
138 138
139 /// Set the duty cycle to `percent / 100` 139 /// Set the duty cycle to `percent / 100`
140 /// 140 ///
141 /// The caller is responsible for ensuring that `percent` is less than or equal to 100. 141 /// The caller is responsible for ensuring that `percent` is less than or equal to 100.
142 pub fn set_duty_cycle_percent(&mut self, percent: u8) { 142 pub fn set_duty_cycle_percent(&mut self, percent: u8) {
143 self.set_duty_cycle_fraction(u16::from(percent), 100) 143 self.set_duty_cycle_fraction(percent as u32, 100)
144 } 144 }
145 145
146 /// Get the duty for a given channel. 146 /// Get the duty for a given channel.
@@ -171,13 +171,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
171 /// 171 ///
172 /// # Panics 172 /// # Panics
173 /// Panics if `dma_buf` is empty or longer than 65535 elements. 173 /// Panics if `dma_buf` is empty or longer than 65535 elements.
174 pub fn into_ring_buffered_channel( 174 pub fn into_ring_buffered_channel<W: Word + Into<T::Word>>(
175 mut self, 175 mut self,
176 tx_dma: Peri<'d, impl super::UpDma<T>>, 176 tx_dma: Peri<'d, impl super::UpDma<T>>,
177 dma_buf: &'d mut [u16], 177 dma_buf: &'d mut [W],
178 ) -> RingBufferedPwmChannel<'d, T> { 178 ) -> RingBufferedPwmChannel<'d, T, W> {
179 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 179 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
180 180
181 self.timer.clamp_compare_value::<W>(self.channel);
181 self.timer.enable_update_dma(true); 182 self.timer.enable_update_dma(true);
182 183
183 RingBufferedPwmChannel::new( 184 RingBufferedPwmChannel::new(
@@ -332,10 +333,27 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
332 /// Get max duty value. 333 /// Get max duty value.
333 /// 334 ///
334 /// This value depends on the configured frequency and the timer's clock rate from RCC. 335 /// This value depends on the configured frequency and the timer's clock rate from RCC.
335 pub fn max_duty_cycle(&self) -> u16 { 336 pub fn max_duty_cycle(&self) -> u32 {
336 let max = self.inner.get_max_compare_value(); 337 self.inner.get_max_compare_value().into() + 1
337 assert!(max < u16::MAX as u32); 338 }
338 max as u16 + 1 339
340 /// Generate a sequence of PWM waveform
341 ///
342 /// Note:
343 /// The DMA channel provided does not need to correspond to the requested channel.
344 pub async fn waveform<C: TimerChannel, W: Word + Into<T::Word>>(
345 &mut self,
346 dma: Peri<'_, impl super::Dma<T, C>>,
347 channel: Channel,
348 duty: &[W],
349 ) {
350 self.inner.enable_channel(channel, true);
351 self.inner.enable_channel(C::CHANNEL, true);
352 self.inner.clamp_compare_value::<W>(channel);
353 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE);
354 self.inner.set_cc_dma_enable_state(C::CHANNEL, true);
355 self.inner.setup_channel_update_dma(dma, channel, duty).await;
356 self.inner.set_cc_dma_enable_state(C::CHANNEL, false);
339 } 357 }
340 358
341 /// Generate a sequence of PWM waveform 359 /// Generate a sequence of PWM waveform
@@ -344,8 +362,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
344 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. 362 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method.
345 /// Also be aware that embassy timers use one of timers internally. It is possible to 363 /// Also be aware that embassy timers use one of timers internally. It is possible to
346 /// switch this timer by using `time-driver-timX` feature. 364 /// switch this timer by using `time-driver-timX` feature.
347 pub async fn waveform_up(&mut self, dma: Peri<'_, impl super::UpDma<T>>, channel: Channel, duty: &[u16]) { 365 pub async fn waveform_up<W: Word + Into<T::Word>>(
366 &mut self,
367 dma: Peri<'_, impl super::UpDma<T>>,
368 channel: Channel,
369 duty: &[W],
370 ) {
348 self.inner.enable_channel(channel, true); 371 self.inner.enable_channel(channel, true);
372 self.inner.clamp_compare_value::<W>(channel);
349 self.inner.enable_update_dma(true); 373 self.inner.enable_update_dma(true);
350 self.inner.setup_update_dma(dma, channel, duty).await; 374 self.inner.setup_update_dma(dma, channel, duty).await;
351 self.inner.enable_update_dma(false); 375 self.inner.enable_update_dma(false);
@@ -380,13 +404,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
380 /// Also be aware that embassy timers use one of timers internally. It is possible to 404 /// Also be aware that embassy timers use one of timers internally. It is possible to
381 /// switch this timer by using `time-driver-timX` feature. 405 /// switch this timer by using `time-driver-timX` feature.
382 /// 406 ///
383 pub async fn waveform_up_multi_channel( 407 pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>(
384 &mut self, 408 &mut self,
385 dma: Peri<'_, impl super::UpDma<T>>, 409 dma: Peri<'_, impl super::UpDma<T>>,
386 starting_channel: Channel, 410 starting_channel: Channel,
387 ending_channel: Channel, 411 ending_channel: Channel,
388 duty: &[u16], 412 duty: &[W],
389 ) { 413 ) {
414 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
415 .iter()
416 .filter(|ch| ch.index() >= starting_channel.index())
417 .filter(|ch| ch.index() <= ending_channel.index())
418 .for_each(|ch| {
419 self.inner.enable_channel(*ch, true);
420 self.inner.clamp_compare_value::<W>(*ch);
421 });
390 self.inner.enable_update_dma(true); 422 self.inner.enable_update_dma(true);
391 self.inner 423 self.inner
392 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) 424 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
@@ -401,11 +433,11 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePw
401 433
402impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { 434impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> {
403 fn max_duty_cycle(&self) -> u16 { 435 fn max_duty_cycle(&self) -> u16 {
404 self.max_duty_cycle() 436 unwrap!(self.max_duty_cycle().try_into())
405 } 437 }
406 438
407 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { 439 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
408 self.set_duty_cycle(duty); 440 self.set_duty_cycle(duty.into());
409 Ok(()) 441 Ok(())
410 } 442 }
411 443
@@ -420,7 +452,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for Simpl
420 } 452 }
421 453
422 fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> { 454 fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> {
423 self.set_duty_cycle_fraction(num, denom); 455 self.set_duty_cycle_fraction(num.into(), denom.into());
424 Ok(()) 456 Ok(())
425 } 457 }
426 458
@@ -448,16 +480,16 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
448 } 480 }
449 481
450 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 482 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
451 self.inner.get_compare_value(channel) 483 self.inner.get_compare_value(channel).into()
452 } 484 }
453 485
454 fn get_max_duty(&self) -> Self::Duty { 486 fn get_max_duty(&self) -> Self::Duty {
455 self.inner.get_max_compare_value() + 1 487 self.inner.get_max_compare_value().into() + 1
456 } 488 }
457 489
458 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 490 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
459 assert!(duty <= self.max_duty_cycle() as u32); 491 assert!(duty <= self.max_duty_cycle() as u32);
460 self.inner.set_compare_value(channel, duty) 492 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
461 } 493 }
462 494
463 fn set_period<P>(&mut self, period: P) 495 fn set_period<P>(&mut self, period: P)