diff options
| author | Grant Miller <[email protected]> | 2024-09-06 13:29:54 -0500 |
|---|---|---|
| committer | Grant Miller <[email protected]> | 2024-09-06 13:29:54 -0500 |
| commit | cfc76cec711447300e2d957439a32d6ad418a58c (patch) | |
| tree | 35ed5afb8c766f65b61f2ebd58b063e37ee4e9a1 | |
| parent | f7f062e0a3f303dfc4f976907b2555f2cfb48621 (diff) | |
Match embedded-hal api
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 105 |
1 files changed, 72 insertions, 33 deletions
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 7179a7a59..23c727731 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -81,23 +81,45 @@ impl<'d, T: GeneralInstance4Channel> SimplePwmChannel<'d, T> { | |||
| 81 | /// Get max duty value. | 81 | /// Get max duty value. |
| 82 | /// | 82 | /// |
| 83 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 83 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 84 | pub fn get_max_duty(&self) -> u32 { | 84 | pub fn max_duty_cycle(&self) -> u16 { |
| 85 | self.timer.get_max_compare_value() + 1 | 85 | unwrap!(self.timer.get_max_compare_value().checked_add(1)) |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | /// Set the duty for a given channel. | 88 | /// Set the duty for a given channel. |
| 89 | /// | 89 | /// |
| 90 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 90 | /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. |
| 91 | pub fn set_duty(&mut self, duty: u32) { | 91 | pub fn set_duty_cycle(&mut self, duty: u16) { |
| 92 | assert!(duty <= self.get_max_duty()); | 92 | assert!(duty <= (*self).max_duty_cycle()); |
| 93 | self.timer.set_compare_value(self.channel, duty) | 93 | self.timer.set_compare_value(self.channel, duty.into()) |
| 94 | } | ||
| 95 | |||
| 96 | fn set_duty_cycle_fully_off(&mut self) { | ||
| 97 | self.set_duty_cycle(0); | ||
| 98 | } | ||
| 99 | |||
| 100 | fn set_duty_cycle_fully_on(&mut self) { | ||
| 101 | self.set_duty_cycle((*self).max_duty_cycle()); | ||
| 102 | } | ||
| 103 | |||
| 104 | fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) { | ||
| 105 | assert!(denom != 0); | ||
| 106 | assert!(num <= denom); | ||
| 107 | let duty = u32::from(num) * u32::from(self.max_duty_cycle()) / u32::from(denom); | ||
| 108 | |||
| 109 | // This is safe because we know that `num <= denom`, so `duty <= self.max_duty_cycle()` (u16) | ||
| 110 | #[allow(clippy::cast_possible_truncation)] | ||
| 111 | self.set_duty_cycle(duty as u16); | ||
| 112 | } | ||
| 113 | |||
| 114 | fn set_duty_cycle_percent(&mut self, percent: u8) { | ||
| 115 | self.set_duty_cycle_fraction(u16::from(percent), 100) | ||
| 94 | } | 116 | } |
| 95 | 117 | ||
| 96 | /// Get the duty for a given channel. | 118 | /// Get the duty for a given channel. |
| 97 | /// | 119 | /// |
| 98 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | 120 | /// The value ranges from 0 for 0% duty, to [`max_duty_cycle`](Self::max_duty_cycle) for 100% duty, both included. |
| 99 | pub fn get_duty(&self) -> u32 { | 121 | pub fn get_duty(&self) -> u16 { |
| 100 | self.timer.get_compare_value(self.channel) | 122 | unwrap!(self.timer.get_compare_value(self.channel).try_into()) |
| 101 | } | 123 | } |
| 102 | 124 | ||
| 103 | /// Set the output polarity for a given channel. | 125 | /// Set the output polarity for a given channel. |
| @@ -123,25 +145,6 @@ pub struct SimplePwmChannels<'d, T: GeneralInstance4Channel> { | |||
| 123 | pub ch4: SimplePwmChannel<'d, T>, | 145 | pub ch4: SimplePwmChannel<'d, T>, |
| 124 | } | 146 | } |
| 125 | 147 | ||
| 126 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { | ||
| 127 | type Error = core::convert::Infallible; | ||
| 128 | } | ||
| 129 | |||
| 130 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { | ||
| 131 | fn max_duty_cycle(&self) -> u16 { | ||
| 132 | // TODO: panics if CCR is 0xFFFF | ||
| 133 | // TODO: rename get_max_duty to max_duty_cycle | ||
| 134 | unwrap!(self.get_max_duty().try_into()) | ||
| 135 | } | ||
| 136 | |||
| 137 | fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { | ||
| 138 | self.set_duty(duty.into()); | ||
| 139 | Ok(()) | ||
| 140 | } | ||
| 141 | |||
| 142 | // TODO: default methods? | ||
| 143 | } | ||
| 144 | |||
| 145 | /// Simple PWM driver. | 148 | /// Simple PWM driver. |
| 146 | pub struct SimplePwm<'d, T: GeneralInstance4Channel> { | 149 | pub struct SimplePwm<'d, T: GeneralInstance4Channel> { |
| 147 | inner: Timer<'d, T>, | 150 | inner: Timer<'d, T>, |
| @@ -253,6 +256,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 253 | /// Note: when you call this, the max duty value changes, so you will have to | 256 | /// Note: when you call this, the max duty value changes, so you will have to |
| 254 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | 257 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. |
| 255 | pub fn set_frequency(&mut self, freq: Hertz) { | 258 | pub fn set_frequency(&mut self, freq: Hertz) { |
| 259 | // TODO: prevent ARR = u16::MAX? | ||
| 256 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 260 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 257 | 2u8 | 261 | 2u8 |
| 258 | } else { | 262 | } else { |
| @@ -264,8 +268,8 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 264 | /// Get max duty value. | 268 | /// Get max duty value. |
| 265 | /// | 269 | /// |
| 266 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | 270 | /// This value depends on the configured frequency and the timer's clock rate from RCC. |
| 267 | pub fn get_max_duty(&self) -> u32 { | 271 | pub fn max_duty_cycle(&self) -> u16 { |
| 268 | self.inner.get_max_compare_value() + 1 | 272 | unwrap!(self.inner.get_max_compare_value().checked_add(1)) |
| 269 | } | 273 | } |
| 270 | 274 | ||
| 271 | /// Generate a sequence of PWM waveform | 275 | /// Generate a sequence of PWM waveform |
| @@ -323,7 +327,7 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { | |||
| 323 | self.channel(channel).disable(); | 327 | self.channel(channel).disable(); |
| 324 | } | 328 | } |
| 325 | 329 | ||
| 326 | self.channel(channel).set_duty(original_duty_state); | 330 | self.channel(channel).set_duty_cycle(original_duty_state); |
| 327 | 331 | ||
| 328 | // Since DMA is closed before timer update event trigger DMA is turn off, | 332 | // Since DMA is closed before timer update event trigger DMA is turn off, |
| 329 | // this can almost always trigger a DMA FIFO error. | 333 | // this can almost always trigger a DMA FIFO error. |
| @@ -399,7 +403,7 @@ macro_rules! impl_waveform_chx { | |||
| 399 | self.channel(cc_channel).disable(); | 403 | self.channel(cc_channel).disable(); |
| 400 | } | 404 | } |
| 401 | 405 | ||
| 402 | self.channel(cc_channel).set_duty(original_duty_state); | 406 | self.channel(cc_channel).set_duty_cycle(original_duty_state); |
| 403 | 407 | ||
| 404 | // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, | 408 | // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, |
| 405 | // this can almost always trigger a DMA FIFO error. | 409 | // this can almost always trigger a DMA FIFO error. |
| @@ -423,6 +427,41 @@ impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2); | |||
| 423 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); | 427 | impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3); |
| 424 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); | 428 | impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4); |
| 425 | 429 | ||
| 430 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { | ||
| 431 | type Error = core::convert::Infallible; | ||
| 432 | } | ||
| 433 | |||
| 434 | impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::SetDutyCycle for SimplePwmChannel<'d, T> { | ||
| 435 | fn max_duty_cycle(&self) -> u16 { | ||
| 436 | self.max_duty_cycle() | ||
| 437 | } | ||
| 438 | |||
| 439 | fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { | ||
| 440 | self.set_duty_cycle(duty); | ||
| 441 | Ok(()) | ||
| 442 | } | ||
| 443 | |||
| 444 | fn set_duty_cycle_fully_off(&mut self) -> Result<(), Self::Error> { | ||
| 445 | self.set_duty_cycle_fully_off(); | ||
| 446 | Ok(()) | ||
| 447 | } | ||
| 448 | |||
| 449 | fn set_duty_cycle_fully_on(&mut self) -> Result<(), Self::Error> { | ||
| 450 | self.set_duty_cycle_fully_on(); | ||
| 451 | Ok(()) | ||
| 452 | } | ||
| 453 | |||
| 454 | fn set_duty_cycle_fraction(&mut self, num: u16, denom: u16) -> Result<(), Self::Error> { | ||
| 455 | self.set_duty_cycle_fraction(num, denom); | ||
| 456 | Ok(()) | ||
| 457 | } | ||
| 458 | |||
| 459 | fn set_duty_cycle_percent(&mut self, percent: u8) -> Result<(), Self::Error> { | ||
| 460 | self.set_duty_cycle_percent(percent); | ||
| 461 | Ok(()) | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 426 | impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { | 465 | impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { |
| 427 | type Channel = Channel; | 466 | type Channel = Channel; |
| 428 | type Time = Hertz; | 467 | type Time = Hertz; |
| @@ -449,7 +488,7 @@ impl<'d, T: GeneralInstance4Channel> embedded_hal_02::Pwm for SimplePwm<'d, T> { | |||
| 449 | } | 488 | } |
| 450 | 489 | ||
| 451 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { | 490 | fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { |
| 452 | assert!(duty <= self.get_max_duty()); | 491 | assert!(duty <= self.max_duty_cycle() as u32); |
| 453 | self.inner.set_compare_value(channel, duty) | 492 | self.inner.set_compare_value(channel, duty) |
| 454 | } | 493 | } |
| 455 | 494 | ||
