aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-12-01 15:53:52 +0000
committerGitHub <[email protected]>2025-12-01 15:53:52 +0000
commitec417c70565aac291403fb5f8e2a93c773fb25e7 (patch)
tree77ebf80cf9cc905f07f85be26c1c52af0ab78d51 /embassy-stm32
parentcf6a27da33479d2ba11ac73066a4bb31746c5e04 (diff)
parent970138277bdbf176a3a9320c9d0de9256945d21e (diff)
Merge pull request #4959 from xoviat/timer
stm32: use typelevel timer type
Diffstat (limited to 'embassy-stm32')
-rw-r--r--embassy-stm32/CHANGELOG.md1
-rw-r--r--embassy-stm32/src/dma/word.rs4
-rw-r--r--embassy-stm32/src/fmt.rs10
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs41
-rw-r--r--embassy-stm32/src/timer/input_capture.rs2
-rw-r--r--embassy-stm32/src/timer/low_level.rs209
-rw-r--r--embassy-stm32/src/timer/mod.rs30
-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.rs62
11 files changed, 208 insertions, 206 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 867f83065..70c46b025 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- change: stm32: use typelevel timer type to allow dma for 32 bit timers
10- fix: fix incorrect handling of split interrupts in timer driver 11- fix: fix incorrect handling of split interrupts in timer driver
11- feat: allow granular stop for regular usart 12- feat: allow granular stop for regular usart
12- feat: Add continuous waveform method to SimplePWM 13- feat: Add continuous waveform method to SimplePWM
diff --git a/embassy-stm32/src/dma/word.rs b/embassy-stm32/src/dma/word.rs
index fb1bde860..5c3bb8f7f 100644
--- a/embassy-stm32/src/dma/word.rs
+++ b/embassy-stm32/src/dma/word.rs
@@ -31,6 +31,10 @@ pub trait Word: SealedWord + Default + Copy + 'static {
31 fn size() -> WordSize; 31 fn size() -> WordSize;
32 /// Amount of bits of this word size. 32 /// Amount of bits of this word size.
33 fn bits() -> usize; 33 fn bits() -> usize;
34 /// Maximum value of this type.
35 fn max() -> usize {
36 (1 << Self::bits()) - 1
37 }
34} 38}
35 39
36macro_rules! impl_word { 40macro_rules! impl_word {
diff --git a/embassy-stm32/src/fmt.rs b/embassy-stm32/src/fmt.rs
index b6ae24ee8..b731796f0 100644
--- a/embassy-stm32/src/fmt.rs
+++ b/embassy-stm32/src/fmt.rs
@@ -207,6 +207,16 @@ macro_rules! error {
207} 207}
208 208
209#[cfg(feature = "defmt")] 209#[cfg(feature = "defmt")]
210trait_set::trait_set! {
211 pub trait Debuggable = Debug + defmt::Format;
212}
213
214#[cfg(not(feature = "defmt"))]
215trait_set::trait_set! {
216 pub trait Debuggable = Debug;
217}
218
219#[cfg(feature = "defmt")]
210#[collapse_debuginfo(yes)] 220#[collapse_debuginfo(yes)]
211macro_rules! unwrap { 221macro_rules! unwrap {
212 ($($x:tt)*) => { 222 ($($x:tt)*) => {
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 77f19a37b..6ca13820a 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -8,6 +8,7 @@ use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::PwmPin; 8use super::simple_pwm::PwmPin;
9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; 9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
10use crate::Peri; 10use crate::Peri;
11use crate::dma::word::Word;
11use crate::gpio::{AnyPin, OutputType}; 12use crate::gpio::{AnyPin, OutputType};
12use crate::time::Hertz; 13use crate::time::Hertz;
13use crate::timer::TimerChannel; 14use crate::timer::TimerChannel;
@@ -176,20 +177,20 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
176 /// Get max duty value. 177 /// Get max duty value.
177 /// 178 ///
178 /// This value depends on the configured frequency and the timer's clock rate from RCC. 179 /// This value depends on the configured frequency and the timer's clock rate from RCC.
179 pub fn get_max_duty(&self) -> u16 { 180 pub fn get_max_duty(&self) -> u32 {
180 if self.inner.get_counting_mode().is_center_aligned() { 181 if self.inner.get_counting_mode().is_center_aligned() {
181 self.inner.get_max_compare_value() as u16 182 self.inner.get_max_compare_value().into()
182 } else { 183 } else {
183 self.inner.get_max_compare_value() as u16 + 1 184 self.inner.get_max_compare_value().into() + 1
184 } 185 }
185 } 186 }
186 187
187 /// Set the duty for a given channel. 188 /// Set the duty for a given channel.
188 /// 189 ///
189 /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. 190 /// 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) { 191 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
191 assert!(duty <= self.get_max_duty()); 192 assert!(duty <= self.get_max_duty());
192 self.inner.set_compare_value(channel, duty as _) 193 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
193 } 194 }
194 195
195 /// Set the output polarity for a given channel. 196 /// Set the output polarity for a given channel.
@@ -220,8 +221,14 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
220 /// 221 ///
221 /// Note: 222 /// Note:
222 /// you will need to provide corresponding TIMx_UP DMA channel to use this method. 223 /// 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]) { 224 pub async fn waveform_up<W: Word + Into<T::Word>>(
225 &mut self,
226 dma: Peri<'_, impl super::UpDma<T>>,
227 channel: Channel,
228 duty: &[W],
229 ) {
224 self.inner.enable_channel(channel, true); 230 self.inner.enable_channel(channel, true);
231 self.inner.clamp_compare_value::<W>(channel);
225 self.inner.enable_update_dma(true); 232 self.inner.enable_update_dma(true);
226 self.inner.setup_update_dma(dma, channel, duty).await; 233 self.inner.setup_update_dma(dma, channel, duty).await;
227 self.inner.enable_update_dma(false); 234 self.inner.enable_update_dma(false);
@@ -256,13 +263,21 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
256 /// Also be aware that embassy timers use one of timers internally. It is possible to 263 /// 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. 264 /// switch this timer by using `time-driver-timX` feature.
258 /// 265 ///
259 pub async fn waveform_up_multi_channel( 266 pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>(
260 &mut self, 267 &mut self,
261 dma: Peri<'_, impl super::UpDma<T>>, 268 dma: Peri<'_, impl super::UpDma<T>>,
262 starting_channel: Channel, 269 starting_channel: Channel,
263 ending_channel: Channel, 270 ending_channel: Channel,
264 duty: &[u16], 271 duty: &[W],
265 ) { 272 ) {
273 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
274 .iter()
275 .filter(|ch| ch.index() >= starting_channel.index())
276 .filter(|ch| ch.index() <= ending_channel.index())
277 .for_each(|ch| {
278 self.inner.enable_channel(*ch, true);
279 self.inner.clamp_compare_value::<W>(*ch);
280 });
266 self.inner.enable_update_dma(true); 281 self.inner.enable_update_dma(true);
267 self.inner 282 self.inner
268 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) 283 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
@@ -291,20 +306,20 @@ impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<
291 } 306 }
292 307
293 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 308 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
294 self.inner.get_compare_value(channel) as u16 309 unwrap!(self.inner.get_compare_value(channel).try_into())
295 } 310 }
296 311
297 fn get_max_duty(&self) -> Self::Duty { 312 fn get_max_duty(&self) -> Self::Duty {
298 if self.inner.get_counting_mode().is_center_aligned() { 313 if self.inner.get_counting_mode().is_center_aligned() {
299 self.inner.get_max_compare_value() as u16 314 unwrap!(self.inner.get_max_compare_value().try_into())
300 } else { 315 } else {
301 self.inner.get_max_compare_value() as u16 + 1 316 unwrap!(self.inner.get_max_compare_value().try_into()) + 1
302 } 317 }
303 } 318 }
304 319
305 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 320 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
306 assert!(duty <= self.get_max_duty()); 321 assert!(duty <= unwrap!(self.get_max_duty().try_into()));
307 self.inner.set_compare_value(channel, duty as u32) 322 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
308 } 323 }
309 324
310 fn set_period<P>(&mut self, period: P) 325 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..6a70d2a40 100644
--- a/embassy-stm32/src/timer/low_level.rs
+++ b/embassy-stm32/src/timer/low_level.rs
@@ -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();
401 393 let psc = regs.psc().read();
402 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 394
410 timer_f / arr / (psc + 1) 395 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,11 +676,11 @@ 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 #[allow(clippy::let_unit_value)] // eg. stm32f334
707 let req = dma.request(); 686 let req = dma.request();
@@ -719,29 +698,13 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
719 ..Default::default() 698 ..Default::default()
720 }; 699 };
721 700
722 match self.bits() { 701 Transfer::new_write(
723 TimerBits::Bits16 => Transfer::new_write( 702 dma,
724 dma, 703 req,
725 req, 704 duty,
726 duty, 705 self.regs_gp16().ccr(channel.index()).as_ptr() as *mut W,
727 self.regs_1ch().ccr(channel.index()).as_ptr() as *mut u16, 706 dma_transfer_option,
728 dma_transfer_option, 707 )
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 } 708 }
746 } 709 }
747 710
@@ -774,12 +737,12 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
774 /// Also be aware that embassy timers use one of timers internally. It is possible to 737 /// 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. 738 /// switch this timer by using `time-driver-timX` feature.
776 /// 739 ///
777 pub fn setup_update_dma_burst<'a>( 740 pub fn setup_update_dma_burst<'a, W: Word + Into<T::Word>>(
778 &mut self, 741 &mut self,
779 dma: Peri<'a, impl super::UpDma<T>>, 742 dma: Peri<'a, impl super::UpDma<T>>,
780 starting_channel: Channel, 743 starting_channel: Channel,
781 ending_channel: Channel, 744 ending_channel: Channel,
782 duty: &'a [u16], 745 duty: &'a [W],
783 ) -> Transfer<'a> { 746 ) -> Transfer<'a> {
784 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32; 747 let cr1_addr = self.regs_gp16().cr1().as_ptr() as u32;
785 let start_ch_index = starting_channel.index(); 748 let start_ch_index = starting_channel.index();
@@ -815,14 +778,14 @@ impl<'d, T: GeneralInstance4Channel> Timer<'d, T> {
815 dma, 778 dma,
816 req, 779 req,
817 duty, 780 duty,
818 self.regs_gp16().dmar().as_ptr() as *mut u16, 781 self.regs_gp16().dmar().as_ptr() as *mut W,
819 dma_transfer_option, 782 dma_transfer_option,
820 ) 783 )
821 } 784 }
822 } 785 }
823 786
824 /// Get capture value for a channel. 787 /// Get capture value for a channel.
825 pub fn get_capture_value(&self, channel: Channel) -> u32 { 788 pub fn get_capture_value(&self, channel: Channel) -> T::Word {
826 self.get_compare_value(channel) 789 self.get_compare_value(channel)
827 } 790 }
828 791
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 3fa363881..74d1c9e77 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);
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..b79ed364b 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -7,6 +7,7 @@ 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};
@@ -98,18 +99,16 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
98 /// Get max duty value. 99 /// Get max duty value.
99 /// 100 ///
100 /// This value depends on the configured frequency and the timer's clock rate from RCC. 101 /// This value depends on the configured frequency and the timer's clock rate from RCC.
101 pub fn max_duty_cycle(&self) -> u16 { 102 pub fn max_duty_cycle(&self) -> u32 {
102 let max = self.timer.get_max_compare_value(); 103 self.timer.get_max_compare_value().into() + 1
103 assert!(max < u16::MAX as u32);
104 max as u16 + 1
105 } 104 }
106 105
107 /// Set the duty for a given channel. 106 /// Set the duty for a given channel.
108 /// 107 ///
109 /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. 108 /// 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) { 109 pub fn set_duty_cycle(&mut self, duty: u32) {
111 assert!(duty <= (*self).max_duty_cycle()); 110 assert!(duty <= (*self).max_duty_cycle());
112 self.timer.set_compare_value(self.channel, duty.into()) 111 self.timer.set_compare_value(self.channel, unwrap!(duty.try_into()))
113 } 112 }
114 113
115 /// Set the duty cycle to 0%, or always inactive. 114 /// Set the duty cycle to 0%, or always inactive.
@@ -126,21 +125,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
126 /// 125 ///
127 /// The caller is responsible for ensuring that `num` is less than or equal to `denom`, 126 /// The caller is responsible for ensuring that `num` is less than or equal to `denom`,
128 /// and that `denom` is not zero. 127 /// and that `denom` is not zero.
129 pub fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { 128 pub fn set_duty_cycle_fraction(&mut self, num: u32, denom: u32) {
130 assert!(denom != 0); 129 assert!(denom != 0);
131 assert!(num <= denom); 130 assert!(num <= denom);
132 let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); 131 let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom);
133 132
134 // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16) 133 // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16)
135 #[allow(clippy::cast_possible_truncation)] 134 #[allow(clippy::cast_possible_truncation)]
136 self.set_duty_cycle(duty as u16); 135 self.set_duty_cycle(unwrap!(duty.try_into()));
137 } 136 }
138 137
139 /// Set the duty cycle to `percent / 100` 138 /// Set the duty cycle to `percent / 100`
140 /// 139 ///
141 /// The caller is responsible for ensuring that `percent` is less than or equal to 100. 140 /// 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) { 141 pub fn set_duty_cycle_percent(&mut self, percent: u8) {
143 self.set_duty_cycle_fraction(u16::from(percent), 100) 142 self.set_duty_cycle_fraction(percent as u32, 100)
144 } 143 }
145 144
146 /// Get the duty for a given channel. 145 /// Get the duty for a given channel.
@@ -171,13 +170,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> {
171 /// 170 ///
172 /// # Panics 171 /// # Panics
173 /// Panics if `dma_buf` is empty or longer than 65535 elements. 172 /// Panics if `dma_buf` is empty or longer than 65535 elements.
174 pub fn into_ring_buffered_channel( 173 pub fn into_ring_buffered_channel<W: Word + Into<T::Word>>(
175 mut self, 174 mut self,
176 tx_dma: Peri<'d, impl super::UpDma<T>>, 175 tx_dma: Peri<'d, impl super::UpDma<T>>,
177 dma_buf: &'d mut [u16], 176 dma_buf: &'d mut [W],
178 ) -> RingBufferedPwmChannel<'d, T> { 177 ) -> RingBufferedPwmChannel<'d, T, W> {
179 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 178 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
180 179
180 self.timer.clamp_compare_value::<W>(self.channel);
181 self.timer.enable_update_dma(true); 181 self.timer.enable_update_dma(true);
182 182
183 RingBufferedPwmChannel::new( 183 RingBufferedPwmChannel::new(
@@ -332,10 +332,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
332 /// Get max duty value. 332 /// Get max duty value.
333 /// 333 ///
334 /// This value depends on the configured frequency and the timer's clock rate from RCC. 334 /// This value depends on the configured frequency and the timer's clock rate from RCC.
335 pub fn max_duty_cycle(&self) -> u16 { 335 pub fn max_duty_cycle(&self) -> u32 {
336 let max = self.inner.get_max_compare_value(); 336 self.inner.get_max_compare_value().into() + 1
337 assert!(max < u16::MAX as u32);
338 max as u16 + 1
339 } 337 }
340 338
341 /// Generate a sequence of PWM waveform 339 /// Generate a sequence of PWM waveform
@@ -344,8 +342,14 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
344 /// You will need to provide corresponding `TIMx_UP` DMA channel to use this method. 342 /// 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 343 /// 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. 344 /// 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]) { 345 pub async fn waveform_up<W: Word + Into<T::Word>>(
346 &mut self,
347 dma: Peri<'_, impl super::UpDma<T>>,
348 channel: Channel,
349 duty: &[W],
350 ) {
348 self.inner.enable_channel(channel, true); 351 self.inner.enable_channel(channel, true);
352 self.inner.clamp_compare_value::<W>(channel);
349 self.inner.enable_update_dma(true); 353 self.inner.enable_update_dma(true);
350 self.inner.setup_update_dma(dma, channel, duty).await; 354 self.inner.setup_update_dma(dma, channel, duty).await;
351 self.inner.enable_update_dma(false); 355 self.inner.enable_update_dma(false);
@@ -380,13 +384,21 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
380 /// Also be aware that embassy timers use one of timers internally. It is possible to 384 /// 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. 385 /// switch this timer by using `time-driver-timX` feature.
382 /// 386 ///
383 pub async fn waveform_up_multi_channel( 387 pub async fn waveform_up_multi_channel<W: Word + Into<T::Word>>(
384 &mut self, 388 &mut self,
385 dma: Peri<'_, impl super::UpDma<T>>, 389 dma: Peri<'_, impl super::UpDma<T>>,
386 starting_channel: Channel, 390 starting_channel: Channel,
387 ending_channel: Channel, 391 ending_channel: Channel,
388 duty: &[u16], 392 duty: &[W],
389 ) { 393 ) {
394 [Channel::Ch1, Channel::Ch2, Channel::Ch3, Channel::Ch4]
395 .iter()
396 .filter(|ch| ch.index() >= starting_channel.index())
397 .filter(|ch| ch.index() <= ending_channel.index())
398 .for_each(|ch| {
399 self.inner.enable_channel(*ch, true);
400 self.inner.clamp_compare_value::<W>(*ch);
401 });
390 self.inner.enable_update_dma(true); 402 self.inner.enable_update_dma(true);
391 self.inner 403 self.inner
392 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty) 404 .setup_update_dma_burst(dma, starting_channel, ending_channel, duty)
@@ -401,11 +413,11 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePw
401 413
402impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { 414impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> {
403 fn max_duty_cycle(&self) -> u16 { 415 fn max_duty_cycle(&self) -> u16 {
404 self.max_duty_cycle() 416 unwrap!(self.max_duty_cycle().try_into())
405 } 417 }
406 418
407 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { 419 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
408 self.set_duty_cycle(duty); 420 self.set_duty_cycle(duty.into());
409 Ok(()) 421 Ok(())
410 } 422 }
411 423
@@ -420,7 +432,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for Simpl
420 } 432 }
421 433
422 fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> { 434 fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> {
423 self.set_duty_cycle_fraction(num, denom); 435 self.set_duty_cycle_fraction(num.into(), denom.into());
424 Ok(()) 436 Ok(())
425 } 437 }
426 438
@@ -448,16 +460,16 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> {
448 } 460 }
449 461
450 fn get_duty(&self, channel: Self::Channel) -> Self::Duty { 462 fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
451 self.inner.get_compare_value(channel) 463 self.inner.get_compare_value(channel).into()
452 } 464 }
453 465
454 fn get_max_duty(&self) -> Self::Duty { 466 fn get_max_duty(&self) -> Self::Duty {
455 self.inner.get_max_compare_value() + 1 467 self.inner.get_max_compare_value().into() + 1
456 } 468 }
457 469
458 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 470 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
459 assert!(duty <= self.max_duty_cycle() as u32); 471 assert!(duty <= self.max_duty_cycle() as u32);
460 self.inner.set_compare_value(channel, duty) 472 self.inner.set_compare_value(channel, unwrap!(duty.try_into()))
461 } 473 }
462 474
463 fn set_period<P>(&mut self, period: P) 475 fn set_period<P>(&mut self, period: P)