aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer/complementary_pwm.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/timer/complementary_pwm.rs')
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs90
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
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)