aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs15
-rw-r--r--embassy-stm32/src/timer/mod.rs95
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs15
-rw-r--r--examples/stm32f4/src/bin/pwm.rs2
-rw-r--r--examples/stm32f4/src/bin/pwm_complementary.rs1
-rw-r--r--examples/stm32g4/src/bin/pwm.rs2
-rw-r--r--examples/stm32h7/src/bin/pwm.rs2
7 files changed, 115 insertions, 17 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index e1baf6b2e..6654366cd 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -57,18 +57,20 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
57 _ch4: Option<PwmPin<'d, T, Ch4>>, 57 _ch4: Option<PwmPin<'d, T, Ch4>>,
58 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>, 58 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
59 freq: Hertz, 59 freq: Hertz,
60 counting_mode: CountingMode,
60 ) -> Self { 61 ) -> Self {
61 Self::new_inner(tim, freq) 62 Self::new_inner(tim, freq, counting_mode)
62 } 63 }
63 64
64 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self { 65 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
65 into_ref!(tim); 66 into_ref!(tim);
66 67
67 T::enable_and_reset(); 68 T::enable_and_reset();
68 69
69 let mut this = Self { inner: tim }; 70 let mut this = Self { inner: tim };
70 71
71 this.inner.set_frequency(freq); 72 this.inner.set_counting_mode(counting_mode);
73 this.set_freq(freq);
72 this.inner.start(); 74 this.inner.start();
73 75
74 this.inner.enable_outputs(); 76 this.inner.enable_outputs();
@@ -95,7 +97,12 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
95 } 97 }
96 98
97 pub fn set_freq(&mut self, freq: Hertz) { 99 pub fn set_freq(&mut self, freq: Hertz) {
98 self.inner.set_frequency(freq); 100 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
101 2u8
102 } else {
103 1u8
104 };
105 self.inner.set_frequency(freq * multiplier);
99 } 106 }
100 107
101 pub fn get_max_duty(&self) -> u16 { 108 pub fn get_max_duty(&self) -> u16 {
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 4b88834cb..913bfed2b 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -29,10 +29,17 @@ pub(crate) mod sealed {
29 Self::regs().cr1().modify(|r| r.set_cen(false)); 29 Self::regs().cr1().modify(|r| r.set_cen(false));
30 } 30 }
31 31
32 /// Reset the counter value to 0
32 fn reset(&mut self) { 33 fn reset(&mut self) {
33 Self::regs().cnt().write(|r| r.set_cnt(0)); 34 Self::regs().cnt().write(|r| r.set_cnt(0));
34 } 35 }
35 36
37 /// Set the frequency of how many times per second the timer counts up to the max value or down to 0.
38 ///
39 /// This means that in the default edge-aligned mode,
40 /// the timer counter will wrap around at the same frequency as is being set.
41 /// In center-aligned mode (which not all timers support), the wrap-around frequency is effectively halved
42 /// because it needs to count up and down.
36 fn set_frequency(&mut self, frequency: Hertz) { 43 fn set_frequency(&mut self, frequency: Hertz) {
37 let f = frequency.0; 44 let f = frequency.0;
38 let timer_f = Self::frequency().0; 45 let timer_f = Self::frequency().0;
@@ -85,8 +92,21 @@ pub(crate) mod sealed {
85 pub trait GeneralPurpose16bitInstance: Basic16bitInstance { 92 pub trait GeneralPurpose16bitInstance: Basic16bitInstance {
86 fn regs_gp16() -> crate::pac::timer::TimGp16; 93 fn regs_gp16() -> crate::pac::timer::TimGp16;
87 94
88 fn set_count_direction(&mut self, direction: vals::Dir) { 95 fn set_counting_mode(&mut self, mode: CountingMode) {
89 Self::regs_gp16().cr1().modify(|r| r.set_dir(direction)); 96 let (cms, dir) = mode.into();
97
98 let timer_enabled = Self::regs().cr1().read().cen();
99 // Changing from edge aligned to center aligned (and vice versa) is not allowed while the timer is running.
100 // Changing direction is discouraged while the timer is running.
101 assert!(!timer_enabled);
102
103 Self::regs_gp16().cr1().modify(|r| r.set_dir(dir));
104 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
105 }
106
107 fn get_counting_mode(&self) -> CountingMode {
108 let cr1 = Self::regs_gp16().cr1().read();
109 (cr1.cms(), cr1.dir()).into()
90 } 110 }
91 111
92 fn set_clock_division(&mut self, ckd: vals::Ckd) { 112 fn set_clock_division(&mut self, ckd: vals::Ckd) {
@@ -293,6 +313,73 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
293 } 313 }
294} 314}
295 315
316#[repr(u8)]
317#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
318pub enum CountingMode {
319 #[default]
320 /// The timer counts up to the reload value and then resets back to 0.
321 EdgeAlignedUp,
322 /// The timer counts down to 0 and then resets back to the reload value.
323 EdgeAlignedDown,
324 /// The timer counts up to the reload value and then counts back to 0.
325 ///
326 /// The output compare interrupt flags of channels configured in output are
327 /// set when the counter is counting down.
328 CenterAlignedDownInterrupts,
329 /// The timer counts up to the reload value and then counts back to 0.
330 ///
331 /// The output compare interrupt flags of channels configured in output are
332 /// set when the counter is counting up.
333 CenterAlignedUpInterrupts,
334 /// The timer counts up to the reload value and then counts back to 0.
335 ///
336 /// The output compare interrupt flags of channels configured in output are
337 /// set when the counter is counting both up or down.
338 CenterAlignedBothInterrupts,
339}
340
341impl CountingMode {
342 pub fn is_edge_aligned(&self) -> bool {
343 match self {
344 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
345 _ => false,
346 }
347 }
348
349 pub fn is_center_aligned(&self) -> bool {
350 match self {
351 CountingMode::CenterAlignedDownInterrupts
352 | CountingMode::CenterAlignedUpInterrupts
353 | CountingMode::CenterAlignedBothInterrupts => true,
354 _ => false,
355 }
356 }
357}
358
359impl From<CountingMode> for (vals::Cms, vals::Dir) {
360 fn from(value: CountingMode) -> Self {
361 match value {
362 CountingMode::EdgeAlignedUp => (vals::Cms::EDGEALIGNED, vals::Dir::UP),
363 CountingMode::EdgeAlignedDown => (vals::Cms::EDGEALIGNED, vals::Dir::DOWN),
364 CountingMode::CenterAlignedDownInterrupts => (vals::Cms::CENTERALIGNED1, vals::Dir::UP),
365 CountingMode::CenterAlignedUpInterrupts => (vals::Cms::CENTERALIGNED2, vals::Dir::UP),
366 CountingMode::CenterAlignedBothInterrupts => (vals::Cms::CENTERALIGNED3, vals::Dir::UP),
367 }
368 }
369}
370
371impl From<(vals::Cms, vals::Dir)> for CountingMode {
372 fn from(value: (vals::Cms, vals::Dir)) -> Self {
373 match value {
374 (vals::Cms::EDGEALIGNED, vals::Dir::UP) => CountingMode::EdgeAlignedUp,
375 (vals::Cms::EDGEALIGNED, vals::Dir::DOWN) => CountingMode::EdgeAlignedDown,
376 (vals::Cms::CENTERALIGNED1, _) => CountingMode::CenterAlignedDownInterrupts,
377 (vals::Cms::CENTERALIGNED2, _) => CountingMode::CenterAlignedUpInterrupts,
378 (vals::Cms::CENTERALIGNED3, _) => CountingMode::CenterAlignedBothInterrupts,
379 }
380 }
381}
382
296#[derive(Clone, Copy)] 383#[derive(Clone, Copy)]
297pub enum OutputCompareMode { 384pub enum OutputCompareMode {
298 Frozen, 385 Frozen,
@@ -471,9 +558,5 @@ foreach_interrupt! {
471 crate::pac::$inst 558 crate::pac::$inst
472 } 559 }
473 } 560 }
474
475
476
477
478 }; 561 };
479} 562}
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 01773ff3a..1cf0ad728 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -56,18 +56,20 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
56 _ch3: Option<PwmPin<'d, T, Ch3>>, 56 _ch3: Option<PwmPin<'d, T, Ch3>>,
57 _ch4: Option<PwmPin<'d, T, Ch4>>, 57 _ch4: Option<PwmPin<'d, T, Ch4>>,
58 freq: Hertz, 58 freq: Hertz,
59 counting_mode: CountingMode,
59 ) -> Self { 60 ) -> Self {
60 Self::new_inner(tim, freq) 61 Self::new_inner(tim, freq, counting_mode)
61 } 62 }
62 63
63 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self { 64 fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz, counting_mode: CountingMode) -> Self {
64 into_ref!(tim); 65 into_ref!(tim);
65 66
66 T::enable_and_reset(); 67 T::enable_and_reset();
67 68
68 let mut this = Self { inner: tim }; 69 let mut this = Self { inner: tim };
69 70
70 this.inner.set_frequency(freq); 71 this.inner.set_counting_mode(counting_mode);
72 this.set_freq(freq);
71 this.inner.start(); 73 this.inner.start();
72 74
73 this.inner.enable_outputs(); 75 this.inner.enable_outputs();
@@ -92,7 +94,12 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
92 } 94 }
93 95
94 pub fn set_freq(&mut self, freq: Hertz) { 96 pub fn set_freq(&mut self, freq: Hertz) {
95 self.inner.set_frequency(freq); 97 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
98 2u8
99 } else {
100 1u8
101 };
102 self.inner.set_frequency(freq * multiplier);
96 } 103 }
97 104
98 pub fn get_max_duty(&self) -> u16 { 105 pub fn get_max_duty(&self) -> u16 {
diff --git a/examples/stm32f4/src/bin/pwm.rs b/examples/stm32f4/src/bin/pwm.rs
index 538427e89..8e41d0e78 100644
--- a/examples/stm32f4/src/bin/pwm.rs
+++ b/examples/stm32f4/src/bin/pwm.rs
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 17 info!("Hello World!");
18 18
19 let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull); 19 let ch1 = PwmPin::new_ch1(p.PE9, OutputType::PushPull);
20 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10)); 20 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default());
21 let max = pwm.get_max_duty(); 21 let max = pwm.get_max_duty();
22 pwm.enable(Channel::Ch1); 22 pwm.enable(Channel::Ch1);
23 23
diff --git a/examples/stm32f4/src/bin/pwm_complementary.rs b/examples/stm32f4/src/bin/pwm_complementary.rs
index a8211f6e0..d925f26d9 100644
--- a/examples/stm32f4/src/bin/pwm_complementary.rs
+++ b/examples/stm32f4/src/bin/pwm_complementary.rs
@@ -30,6 +30,7 @@ async fn main(_spawner: Spawner) {
30 None, 30 None,
31 None, 31 None,
32 khz(10), 32 khz(10),
33 Default::default(),
33 ); 34 );
34 35
35 let max = pwm.get_max_duty(); 36 let max = pwm.get_max_duty();
diff --git a/examples/stm32g4/src/bin/pwm.rs b/examples/stm32g4/src/bin/pwm.rs
index eed0b6ad7..a84394005 100644
--- a/examples/stm32g4/src/bin/pwm.rs
+++ b/examples/stm32g4/src/bin/pwm.rs
@@ -17,7 +17,7 @@ async fn main(_spawner: Spawner) {
17 info!("Hello World!"); 17 info!("Hello World!");
18 18
19 let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull); 19 let ch1 = PwmPin::new_ch1(p.PC0, OutputType::PushPull);
20 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10)); 20 let mut pwm = SimplePwm::new(p.TIM1, Some(ch1), None, None, None, khz(10), Default::default());
21 let max = pwm.get_max_duty(); 21 let max = pwm.get_max_duty();
22 pwm.enable(Channel::Ch1); 22 pwm.enable(Channel::Ch1);
23 23
diff --git a/examples/stm32h7/src/bin/pwm.rs b/examples/stm32h7/src/bin/pwm.rs
index 3bf373c7e..973a10cdd 100644
--- a/examples/stm32h7/src/bin/pwm.rs
+++ b/examples/stm32h7/src/bin/pwm.rs
@@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) {
39 info!("Hello World!"); 39 info!("Hello World!");
40 40
41 let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull); 41 let ch1 = PwmPin::new_ch1(p.PA6, OutputType::PushPull);
42 let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10)); 42 let mut pwm = SimplePwm::new(p.TIM3, Some(ch1), None, None, None, khz(10), Default::default());
43 let max = pwm.get_max_duty(); 43 let max = pwm.get_max_duty();
44 pwm.enable(Channel::Ch1); 44 pwm.enable(Channel::Ch1);
45 45