diff options
| author | sodo <[email protected]> | 2024-01-02 01:37:00 +0900 |
|---|---|---|
| committer | sodo <[email protected]> | 2024-01-02 13:34:22 +0900 |
| commit | 6ee153a3e2eec284c0d9d87f31801265c0604f74 (patch) | |
| tree | 8b801cbd15f9ad5052d5942c731e75736dc9d7eb /embassy-stm32/src/timer/complementary_pwm.rs | |
| parent | b7cd7952c890f585ff876c622482534e5d58d4a4 (diff) | |
| parent | 0be9b0599aaf2e425d76ec7852ff4b3535defddf (diff) | |
Merge remote-tracking branch 'origin'
Diffstat (limited to 'embassy-stm32/src/timer/complementary_pwm.rs')
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs index 6654366cd..71d7110b5 100644 --- a/embassy-stm32/src/timer/complementary_pwm.rs +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! PWM driver with complementary output support. | ||
| 2 | |||
| 1 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 2 | 4 | ||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | 5 | use embassy_hal_internal::{into_ref, PeripheralRef}; |
| @@ -11,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType}; | |||
| 11 | use crate::time::Hertz; | 13 | use crate::time::Hertz; |
| 12 | use crate::Peripheral; | 14 | use crate::Peripheral; |
| 13 | 15 | ||
| 14 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | 16 | /// Complementary PWM pin wrapper. |
| 17 | /// | ||
| 18 | /// This wraps a pin to make it usable with PWM. | ||
| 19 | pub struct ComplementaryPwmPin<'d, T, C> { | ||
| 15 | _pin: PeripheralRef<'d, AnyPin>, | 20 | _pin: PeripheralRef<'d, AnyPin>, |
| 16 | phantom: PhantomData<(Perip, Channel)>, | 21 | phantom: PhantomData<(T, C)>, |
| 17 | } | 22 | } |
| 18 | 23 | ||
| 19 | macro_rules! complementary_channel_impl { | 24 | macro_rules! complementary_channel_impl { |
| 20 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 25 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 21 | impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { | 26 | impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> { |
| 22 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { | 27 | #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] |
| 28 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | ||
| 23 | into_ref!(pin); | 29 | into_ref!(pin); |
| 24 | critical_section::with(|_| { | 30 | critical_section::with(|_| { |
| 25 | pin.set_low(); | 31 | pin.set_low(); |
| @@ -41,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin); | |||
| 41 | complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); | 47 | complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); |
| 42 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); | 48 | complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); |
| 43 | 49 | ||
| 50 | /// PWM driver with support for standard and complementary outputs. | ||
| 44 | pub struct ComplementaryPwm<'d, T> { | 51 | pub struct ComplementaryPwm<'d, T> { |
| 45 | inner: PeripheralRef<'d, T>, | 52 | inner: PeripheralRef<'d, T>, |
| 46 | } | 53 | } |
| 47 | 54 | ||
| 48 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | 55 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { |
| 56 | /// Create a new complementary PWM driver. | ||
| 49 | pub fn new( | 57 | pub fn new( |
| 50 | tim: impl Peripheral<P = T> + 'd, | 58 | tim: impl Peripheral<P = T> + 'd, |
| 51 | _ch1: Option<PwmPin<'d, T, Ch1>>, | 59 | _ch1: Option<PwmPin<'d, T, Ch1>>, |
| @@ -70,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 70 | let mut this = Self { inner: tim }; | 78 | let mut this = Self { inner: tim }; |
| 71 | 79 | ||
| 72 | this.inner.set_counting_mode(counting_mode); | 80 | this.inner.set_counting_mode(counting_mode); |
| 73 | this.set_freq(freq); | 81 | this.set_frequency(freq); |
| 74 | this.inner.start(); | 82 | this.inner.start(); |
| 75 | 83 | ||
| 76 | this.inner.enable_outputs(); | 84 | this.inner.enable_outputs(); |
| @@ -86,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 86 | this | 94 | this |
| 87 | } | 95 | } |
| 88 | 96 | ||
| 97 | /// Enable the given channel. | ||
| 89 | pub fn enable(&mut self, channel: Channel) { | 98 | pub fn enable(&mut self, channel: Channel) { |
| 90 | self.inner.enable_channel(channel, true); | 99 | self.inner.enable_channel(channel, true); |
| 91 | self.inner.enable_complementary_channel(channel, true); | 100 | self.inner.enable_complementary_channel(channel, true); |
| 92 | } | 101 | } |
| 93 | 102 | ||
| 103 | /// Disable the given channel. | ||
| 94 | pub fn disable(&mut self, channel: Channel) { | 104 | pub fn disable(&mut self, channel: Channel) { |
| 95 | self.inner.enable_complementary_channel(channel, false); | 105 | self.inner.enable_complementary_channel(channel, false); |
| 96 | self.inner.enable_channel(channel, false); | 106 | self.inner.enable_channel(channel, false); |
| 97 | } | 107 | } |
| 98 | 108 | ||
| 99 | pub fn set_freq(&mut self, freq: Hertz) { | 109 | /// Set PWM frequency. |
| 110 | /// | ||
| 111 | /// Note: when you call this, the max duty value changes, so you will have to | ||
| 112 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | ||
| 113 | pub fn set_frequency(&mut self, freq: Hertz) { | ||
| 100 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 114 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 101 | 2u8 | 115 | 2u8 |
| 102 | } else { | 116 | } else { |
| @@ -105,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | |||
| 105 | self.inner.set_frequency(freq * multiplier); | 119 | self.inner.set_frequency(freq * multiplier); |
| 106 | } | 120 | } |
| 107 | 121 | ||
| 122 | /// Get max duty value. | ||
| 123 | /// | ||
| 124 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | ||
| 108 | pub fn get_max_duty(&self) -> u16 { | 125 | pub fn get_max_duty(&self) -> u16 { |
| 109 | self.inner.get_max_compare_value() + 1 | 126 | self.inner.get_max_compare_value() + 1 |
| 110 | } | 127 | } |
| 111 | 128 | ||
| 129 | /// Set the duty for a given channel. | ||
| 130 | /// | ||
| 131 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | ||
| 112 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 132 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 113 | assert!(duty <= self.get_max_duty()); | 133 | assert!(duty <= self.get_max_duty()); |
| 114 | self.inner.set_compare_value(channel, duty) | 134 | self.inner.set_compare_value(channel, duty) |
| 115 | } | 135 | } |
| 116 | 136 | ||
| 137 | /// Set the output polarity for a given channel. | ||
| 117 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 138 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 118 | self.inner.set_output_polarity(channel, polarity); | 139 | self.inner.set_output_polarity(channel, polarity); |
| 119 | self.inner.set_complementary_output_polarity(channel, polarity); | 140 | self.inner.set_complementary_output_polarity(channel, polarity); |
