diff options
Diffstat (limited to 'embassy-stm32/src/timer/complementary_pwm.rs')
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 90 |
1 files changed, 71 insertions, 19 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 | ||
| 3 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 4 | 4 | ||
| 5 | pub use stm32_metapac::timer::vals::{Ckd, Mms2, Ossi, Ossr}; | ||
| 6 | |||
| 7 | use super::low_level::{CountingMode, OutputPolarity, Timer}; | 5 | use super::low_level::{CountingMode, OutputPolarity, Timer}; |
| 8 | use super::simple_pwm::PwmPin; | 6 | use super::simple_pwm::PwmPin; |
| 9 | use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; | 7 | use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin}; |
| 10 | use crate::Peri; | 8 | use crate::Peri; |
| 11 | use crate::gpio::{AnyPin, OutputType}; | 9 | use crate::dma::word::Word; |
| 10 | use crate::gpio::{AfType, AnyPin, OutputType}; | ||
| 11 | pub use crate::pac::timer::vals::{Ccds, Ckd, Mms2, Ossi, Ossr}; | ||
| 12 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use crate::timer::TimerChannel; | 13 | use crate::timer::TimerChannel; |
| 14 | use crate::timer::low_level::OutputCompareMode; | 14 | use crate::timer::low_level::OutputCompareMode; |
| 15 | use 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) |
