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 | |
| parent | b7cd7952c890f585ff876c622482534e5d58d4a4 (diff) | |
| parent | 0be9b0599aaf2e425d76ec7852ff4b3535defddf (diff) | |
Merge remote-tracking branch 'origin'
Diffstat (limited to 'embassy-stm32/src/timer')
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 33 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/mod.rs | 163 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/qei.rs | 25 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 47 |
4 files changed, 220 insertions, 48 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); |
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 2313a5b94..74120adad 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Timers, PWM, quadrature decoder. | ||
| 2 | |||
| 1 | pub mod complementary_pwm; | 3 | pub mod complementary_pwm; |
| 2 | pub mod qei; | 4 | pub mod qei; |
| 3 | pub mod simple_pwm; | 5 | pub mod simple_pwm; |
| @@ -8,23 +10,34 @@ use crate::interrupt; | |||
| 8 | use crate::rcc::RccPeripheral; | 10 | use crate::rcc::RccPeripheral; |
| 9 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 10 | 12 | ||
| 13 | /// Low-level timer access. | ||
| 11 | #[cfg(feature = "unstable-pac")] | 14 | #[cfg(feature = "unstable-pac")] |
| 12 | pub mod low_level { | 15 | pub mod low_level { |
| 13 | pub use super::sealed::*; | 16 | pub use super::sealed::*; |
| 14 | } | 17 | } |
| 15 | 18 | ||
| 16 | pub(crate) mod sealed { | 19 | pub(crate) mod sealed { |
| 17 | |||
| 18 | use super::*; | 20 | use super::*; |
| 21 | |||
| 22 | /// Basic 16-bit timer instance. | ||
| 19 | pub trait Basic16bitInstance: RccPeripheral { | 23 | pub trait Basic16bitInstance: RccPeripheral { |
| 24 | /// Interrupt for this timer. | ||
| 20 | type Interrupt: interrupt::typelevel::Interrupt; | 25 | type Interrupt: interrupt::typelevel::Interrupt; |
| 21 | 26 | ||
| 27 | /// Get access to the basic 16bit timer registers. | ||
| 28 | /// | ||
| 29 | /// Note: This works even if the timer is more capable, because registers | ||
| 30 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 31 | /// for a given set of capabilities, and having it transparently work with | ||
| 32 | /// more capable timers. | ||
| 22 | fn regs() -> crate::pac::timer::TimBasic; | 33 | fn regs() -> crate::pac::timer::TimBasic; |
| 23 | 34 | ||
| 35 | /// Start the timer. | ||
| 24 | fn start(&mut self) { | 36 | fn start(&mut self) { |
| 25 | Self::regs().cr1().modify(|r| r.set_cen(true)); | 37 | Self::regs().cr1().modify(|r| r.set_cen(true)); |
| 26 | } | 38 | } |
| 27 | 39 | ||
| 40 | /// Stop the timer. | ||
| 28 | fn stop(&mut self) { | 41 | fn stop(&mut self) { |
| 29 | Self::regs().cr1().modify(|r| r.set_cen(false)); | 42 | Self::regs().cr1().modify(|r| r.set_cen(false)); |
| 30 | } | 43 | } |
| @@ -60,6 +73,9 @@ pub(crate) mod sealed { | |||
| 60 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 73 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 61 | } | 74 | } |
| 62 | 75 | ||
| 76 | /// Clear update interrupt. | ||
| 77 | /// | ||
| 78 | /// Returns whether the update interrupt flag was set. | ||
| 63 | fn clear_update_interrupt(&mut self) -> bool { | 79 | fn clear_update_interrupt(&mut self) -> bool { |
| 64 | let regs = Self::regs(); | 80 | let regs = Self::regs(); |
| 65 | let sr = regs.sr().read(); | 81 | let sr = regs.sr().read(); |
| @@ -73,14 +89,17 @@ pub(crate) mod sealed { | |||
| 73 | } | 89 | } |
| 74 | } | 90 | } |
| 75 | 91 | ||
| 92 | /// Enable/disable the update interrupt. | ||
| 76 | fn enable_update_interrupt(&mut self, enable: bool) { | 93 | fn enable_update_interrupt(&mut self, enable: bool) { |
| 77 | Self::regs().dier().write(|r| r.set_uie(enable)); | 94 | Self::regs().dier().write(|r| r.set_uie(enable)); |
| 78 | } | 95 | } |
| 79 | 96 | ||
| 80 | fn set_autoreload_preload(&mut self, enable: vals::Arpe) { | 97 | /// Enable/disable autoreload preload. |
| 98 | fn set_autoreload_preload(&mut self, enable: bool) { | ||
| 81 | Self::regs().cr1().modify(|r| r.set_arpe(enable)); | 99 | Self::regs().cr1().modify(|r| r.set_arpe(enable)); |
| 82 | } | 100 | } |
| 83 | 101 | ||
| 102 | /// Get the timer frequency. | ||
| 84 | fn get_frequency(&self) -> Hertz { | 103 | fn get_frequency(&self) -> Hertz { |
| 85 | let timer_f = Self::frequency(); | 104 | let timer_f = Self::frequency(); |
| 86 | 105 | ||
| @@ -92,9 +111,17 @@ pub(crate) mod sealed { | |||
| 92 | } | 111 | } |
| 93 | } | 112 | } |
| 94 | 113 | ||
| 114 | /// Gneral-purpose 16-bit timer instance. | ||
| 95 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { | 115 | pub trait GeneralPurpose16bitInstance: Basic16bitInstance { |
| 116 | /// Get access to the general purpose 16bit timer registers. | ||
| 117 | /// | ||
| 118 | /// Note: This works even if the timer is more capable, because registers | ||
| 119 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 120 | /// for a given set of capabilities, and having it transparently work with | ||
| 121 | /// more capable timers. | ||
| 96 | fn regs_gp16() -> crate::pac::timer::TimGp16; | 122 | fn regs_gp16() -> crate::pac::timer::TimGp16; |
| 97 | 123 | ||
| 124 | /// Set counting mode. | ||
| 98 | fn set_counting_mode(&mut self, mode: CountingMode) { | 125 | fn set_counting_mode(&mut self, mode: CountingMode) { |
| 99 | let (cms, dir) = mode.into(); | 126 | let (cms, dir) = mode.into(); |
| 100 | 127 | ||
| @@ -107,19 +134,29 @@ pub(crate) mod sealed { | |||
| 107 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) | 134 | Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) |
| 108 | } | 135 | } |
| 109 | 136 | ||
| 137 | /// Get counting mode. | ||
| 110 | fn get_counting_mode(&self) -> CountingMode { | 138 | fn get_counting_mode(&self) -> CountingMode { |
| 111 | let cr1 = Self::regs_gp16().cr1().read(); | 139 | let cr1 = Self::regs_gp16().cr1().read(); |
| 112 | (cr1.cms(), cr1.dir()).into() | 140 | (cr1.cms(), cr1.dir()).into() |
| 113 | } | 141 | } |
| 114 | 142 | ||
| 143 | /// Set clock divider. | ||
| 115 | fn set_clock_division(&mut self, ckd: vals::Ckd) { | 144 | fn set_clock_division(&mut self, ckd: vals::Ckd) { |
| 116 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); | 145 | Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); |
| 117 | } | 146 | } |
| 118 | } | 147 | } |
| 119 | 148 | ||
| 149 | /// Gneral-purpose 32-bit timer instance. | ||
| 120 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { | 150 | pub trait GeneralPurpose32bitInstance: GeneralPurpose16bitInstance { |
| 151 | /// Get access to the general purpose 32bit timer registers. | ||
| 152 | /// | ||
| 153 | /// Note: This works even if the timer is more capable, because registers | ||
| 154 | /// for the less capable timers are a subset. This allows writing a driver | ||
| 155 | /// for a given set of capabilities, and having it transparently work with | ||
| 156 | /// more capable timers. | ||
| 121 | fn regs_gp32() -> crate::pac::timer::TimGp32; | 157 | fn regs_gp32() -> crate::pac::timer::TimGp32; |
| 122 | 158 | ||
| 159 | /// Set timer frequency. | ||
| 123 | fn set_frequency(&mut self, frequency: Hertz) { | 160 | fn set_frequency(&mut self, frequency: Hertz) { |
| 124 | let f = frequency.0; | 161 | let f = frequency.0; |
| 125 | assert!(f > 0); | 162 | assert!(f > 0); |
| @@ -137,6 +174,7 @@ pub(crate) mod sealed { | |||
| 137 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); | 174 | regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); |
| 138 | } | 175 | } |
| 139 | 176 | ||
| 177 | /// Get timer frequency. | ||
| 140 | fn get_frequency(&self) -> Hertz { | 178 | fn get_frequency(&self) -> Hertz { |
| 141 | let timer_f = Self::frequency(); | 179 | let timer_f = Self::frequency(); |
| 142 | 180 | ||
| @@ -148,141 +186,177 @@ pub(crate) mod sealed { | |||
| 148 | } | 186 | } |
| 149 | } | 187 | } |
| 150 | 188 | ||
| 189 | /// Advanced control timer instance. | ||
| 151 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { | 190 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { |
| 191 | /// Get access to the advanced timer registers. | ||
| 152 | fn regs_advanced() -> crate::pac::timer::TimAdv; | 192 | fn regs_advanced() -> crate::pac::timer::TimAdv; |
| 153 | } | 193 | } |
| 154 | 194 | ||
| 195 | /// Capture/Compare 16-bit timer instance. | ||
| 155 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { | 196 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { |
| 197 | /// Set input capture filter. | ||
| 156 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { | 198 | fn set_input_capture_filter(&mut self, channel: Channel, icf: vals::Icf) { |
| 157 | let raw_channel = channel.raw(); | 199 | let raw_channel = channel.index(); |
| 158 | Self::regs_gp16() | 200 | Self::regs_gp16() |
| 159 | .ccmr_input(raw_channel / 2) | 201 | .ccmr_input(raw_channel / 2) |
| 160 | .modify(|r| r.set_icf(raw_channel % 2, icf)); | 202 | .modify(|r| r.set_icf(raw_channel % 2, icf)); |
| 161 | } | 203 | } |
| 162 | 204 | ||
| 205 | /// Clear input interrupt. | ||
| 163 | fn clear_input_interrupt(&mut self, channel: Channel) { | 206 | fn clear_input_interrupt(&mut self, channel: Channel) { |
| 164 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.raw(), false)); | 207 | Self::regs_gp16().sr().modify(|r| r.set_ccif(channel.index(), false)); |
| 165 | } | 208 | } |
| 166 | 209 | ||
| 210 | /// Enable input interrupt. | ||
| 167 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { | 211 | fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { |
| 168 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.raw(), enable)); | 212 | Self::regs_gp16().dier().modify(|r| r.set_ccie(channel.index(), enable)); |
| 169 | } | 213 | } |
| 214 | |||
| 215 | /// Set input capture prescaler. | ||
| 170 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { | 216 | fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { |
| 171 | let raw_channel = channel.raw(); | 217 | let raw_channel = channel.index(); |
| 172 | Self::regs_gp16() | 218 | Self::regs_gp16() |
| 173 | .ccmr_input(raw_channel / 2) | 219 | .ccmr_input(raw_channel / 2) |
| 174 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); | 220 | .modify(|r| r.set_icpsc(raw_channel % 2, factor)); |
| 175 | } | 221 | } |
| 176 | 222 | ||
| 223 | /// Set input TI selection. | ||
| 177 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { | 224 | fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { |
| 178 | let raw_channel = channel.raw(); | 225 | let raw_channel = channel.index(); |
| 179 | Self::regs_gp16() | 226 | Self::regs_gp16() |
| 180 | .ccmr_input(raw_channel / 2) | 227 | .ccmr_input(raw_channel / 2) |
| 181 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); | 228 | .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); |
| 182 | } | 229 | } |
| 230 | |||
| 231 | /// Set input capture mode. | ||
| 183 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { | 232 | fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { |
| 184 | Self::regs_gp16().ccer().modify(|r| match mode { | 233 | Self::regs_gp16().ccer().modify(|r| match mode { |
| 185 | InputCaptureMode::Rising => { | 234 | InputCaptureMode::Rising => { |
| 186 | r.set_ccnp(channel.raw(), false); | 235 | r.set_ccnp(channel.index(), false); |
| 187 | r.set_ccp(channel.raw(), false); | 236 | r.set_ccp(channel.index(), false); |
| 188 | } | 237 | } |
| 189 | InputCaptureMode::Falling => { | 238 | InputCaptureMode::Falling => { |
| 190 | r.set_ccnp(channel.raw(), false); | 239 | r.set_ccnp(channel.index(), false); |
| 191 | r.set_ccp(channel.raw(), true); | 240 | r.set_ccp(channel.index(), true); |
| 192 | } | 241 | } |
| 193 | InputCaptureMode::BothEdges => { | 242 | InputCaptureMode::BothEdges => { |
| 194 | r.set_ccnp(channel.raw(), true); | 243 | r.set_ccnp(channel.index(), true); |
| 195 | r.set_ccp(channel.raw(), true); | 244 | r.set_ccp(channel.index(), true); |
| 196 | } | 245 | } |
| 197 | }); | 246 | }); |
| 198 | } | 247 | } |
| 248 | |||
| 249 | /// Enable timer outputs. | ||
| 199 | fn enable_outputs(&mut self); | 250 | fn enable_outputs(&mut self); |
| 200 | 251 | ||
| 252 | /// Set output compare mode. | ||
| 201 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { | 253 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { |
| 202 | let r = Self::regs_gp16(); | 254 | let r = Self::regs_gp16(); |
| 203 | let raw_channel: usize = channel.raw(); | 255 | let raw_channel: usize = channel.index(); |
| 204 | r.ccmr_output(raw_channel / 2) | 256 | r.ccmr_output(raw_channel / 2) |
| 205 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | 257 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); |
| 206 | } | 258 | } |
| 207 | 259 | ||
| 260 | /// Set output polarity. | ||
| 208 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 261 | fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 209 | Self::regs_gp16() | 262 | Self::regs_gp16() |
| 210 | .ccer() | 263 | .ccer() |
| 211 | .modify(|w| w.set_ccp(channel.raw(), polarity.into())); | 264 | .modify(|w| w.set_ccp(channel.index(), polarity.into())); |
| 212 | } | 265 | } |
| 213 | 266 | ||
| 267 | /// Enable/disable a channel. | ||
| 214 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | 268 | fn enable_channel(&mut self, channel: Channel, enable: bool) { |
| 215 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.raw(), enable)); | 269 | Self::regs_gp16().ccer().modify(|w| w.set_cce(channel.index(), enable)); |
| 216 | } | 270 | } |
| 217 | 271 | ||
| 272 | /// Set compare value for a channel. | ||
| 218 | fn set_compare_value(&mut self, channel: Channel, value: u16) { | 273 | fn set_compare_value(&mut self, channel: Channel, value: u16) { |
| 219 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 274 | Self::regs_gp16().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 220 | } | 275 | } |
| 221 | 276 | ||
| 277 | /// Get capture value for a channel. | ||
| 222 | fn get_capture_value(&mut self, channel: Channel) -> u16 { | 278 | fn get_capture_value(&mut self, channel: Channel) -> u16 { |
| 223 | Self::regs_gp16().ccr(channel.raw()).read().ccr() | 279 | Self::regs_gp16().ccr(channel.index()).read().ccr() |
| 224 | } | 280 | } |
| 225 | 281 | ||
| 282 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 226 | fn get_max_compare_value(&self) -> u16 { | 283 | fn get_max_compare_value(&self) -> u16 { |
| 227 | Self::regs_gp16().arr().read().arr() | 284 | Self::regs_gp16().arr().read().arr() |
| 228 | } | 285 | } |
| 229 | 286 | ||
| 287 | /// Get compare value for a channel. | ||
| 230 | fn get_compare_value(&self, channel: Channel) -> u16 { | 288 | fn get_compare_value(&self, channel: Channel) -> u16 { |
| 231 | Self::regs_gp16().ccr(channel.raw()).read().ccr() | 289 | Self::regs_gp16().ccr(channel.index()).read().ccr() |
| 232 | } | 290 | } |
| 233 | } | 291 | } |
| 234 | 292 | ||
| 293 | /// Capture/Compare 16-bit timer instance with complementary pin support. | ||
| 235 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { | 294 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { |
| 295 | /// Set complementary output polarity. | ||
| 236 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 296 | fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 237 | Self::regs_advanced() | 297 | Self::regs_advanced() |
| 238 | .ccer() | 298 | .ccer() |
| 239 | .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); | 299 | .modify(|w| w.set_ccnp(channel.index(), polarity.into())); |
| 240 | } | 300 | } |
| 241 | 301 | ||
| 302 | /// Set clock divider for the dead time. | ||
| 242 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { | 303 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { |
| 243 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); | 304 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); |
| 244 | } | 305 | } |
| 245 | 306 | ||
| 307 | /// Set dead time, as a fraction of the max duty value. | ||
| 246 | fn set_dead_time_value(&mut self, value: u8) { | 308 | fn set_dead_time_value(&mut self, value: u8) { |
| 247 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); | 309 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); |
| 248 | } | 310 | } |
| 249 | 311 | ||
| 312 | /// Enable/disable a complementary channel. | ||
| 250 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | 313 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { |
| 251 | Self::regs_advanced() | 314 | Self::regs_advanced() |
| 252 | .ccer() | 315 | .ccer() |
| 253 | .modify(|w| w.set_ccne(channel.raw(), enable)); | 316 | .modify(|w| w.set_ccne(channel.index(), enable)); |
| 254 | } | 317 | } |
| 255 | } | 318 | } |
| 256 | 319 | ||
| 320 | /// Capture/Compare 32-bit timer instance. | ||
| 257 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { | 321 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { |
| 322 | /// Set comapre value for a channel. | ||
| 258 | fn set_compare_value(&mut self, channel: Channel, value: u32) { | 323 | fn set_compare_value(&mut self, channel: Channel, value: u32) { |
| 259 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | 324 | Self::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(value)); |
| 260 | } | 325 | } |
| 261 | 326 | ||
| 327 | /// Get capture value for a channel. | ||
| 262 | fn get_capture_value(&mut self, channel: Channel) -> u32 { | 328 | fn get_capture_value(&mut self, channel: Channel) -> u32 { |
| 263 | Self::regs_gp32().ccr(channel.raw()).read().ccr() | 329 | Self::regs_gp32().ccr(channel.index()).read().ccr() |
| 264 | } | 330 | } |
| 265 | 331 | ||
| 332 | /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC. | ||
| 266 | fn get_max_compare_value(&self) -> u32 { | 333 | fn get_max_compare_value(&self) -> u32 { |
| 267 | Self::regs_gp32().arr().read().arr() | 334 | Self::regs_gp32().arr().read().arr() |
| 268 | } | 335 | } |
| 269 | 336 | ||
| 337 | /// Get compare value for a channel. | ||
| 270 | fn get_compare_value(&self, channel: Channel) -> u32 { | 338 | fn get_compare_value(&self, channel: Channel) -> u32 { |
| 271 | Self::regs_gp32().ccr(channel.raw()).read().ccr() | 339 | Self::regs_gp32().ccr(channel.index()).read().ccr() |
| 272 | } | 340 | } |
| 273 | } | 341 | } |
| 274 | } | 342 | } |
| 275 | 343 | ||
| 344 | /// Timer channel. | ||
| 276 | #[derive(Clone, Copy)] | 345 | #[derive(Clone, Copy)] |
| 277 | pub enum Channel { | 346 | pub enum Channel { |
| 347 | /// Channel 1. | ||
| 278 | Ch1, | 348 | Ch1, |
| 349 | /// Channel 2. | ||
| 279 | Ch2, | 350 | Ch2, |
| 351 | /// Channel 3. | ||
| 280 | Ch3, | 352 | Ch3, |
| 353 | /// Channel 4. | ||
| 281 | Ch4, | 354 | Ch4, |
| 282 | } | 355 | } |
| 283 | 356 | ||
| 284 | impl Channel { | 357 | impl Channel { |
| 285 | pub fn raw(&self) -> usize { | 358 | /// Get the channel index (0..3) |
| 359 | pub fn index(&self) -> usize { | ||
| 286 | match self { | 360 | match self { |
| 287 | Channel::Ch1 => 0, | 361 | Channel::Ch1 => 0, |
| 288 | Channel::Ch2 => 1, | 362 | Channel::Ch2 => 1, |
| @@ -292,17 +366,25 @@ impl Channel { | |||
| 292 | } | 366 | } |
| 293 | } | 367 | } |
| 294 | 368 | ||
| 369 | /// Input capture mode. | ||
| 295 | #[derive(Clone, Copy)] | 370 | #[derive(Clone, Copy)] |
| 296 | pub enum InputCaptureMode { | 371 | pub enum InputCaptureMode { |
| 372 | /// Rising edge only. | ||
| 297 | Rising, | 373 | Rising, |
| 374 | /// Falling edge only. | ||
| 298 | Falling, | 375 | Falling, |
| 376 | /// Both rising or falling edges. | ||
| 299 | BothEdges, | 377 | BothEdges, |
| 300 | } | 378 | } |
| 301 | 379 | ||
| 380 | /// Input TI selection. | ||
| 302 | #[derive(Clone, Copy)] | 381 | #[derive(Clone, Copy)] |
| 303 | pub enum InputTISelection { | 382 | pub enum InputTISelection { |
| 383 | /// Normal | ||
| 304 | Normal, | 384 | Normal, |
| 385 | /// Alternate | ||
| 305 | Alternate, | 386 | Alternate, |
| 387 | /// TRC | ||
| 306 | TRC, | 388 | TRC, |
| 307 | } | 389 | } |
| 308 | 390 | ||
| @@ -316,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs { | |||
| 316 | } | 398 | } |
| 317 | } | 399 | } |
| 318 | 400 | ||
| 401 | /// Timer counting mode. | ||
| 319 | #[repr(u8)] | 402 | #[repr(u8)] |
| 320 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] | 403 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] |
| 321 | pub enum CountingMode { | 404 | pub enum CountingMode { |
| @@ -342,6 +425,7 @@ pub enum CountingMode { | |||
| 342 | } | 425 | } |
| 343 | 426 | ||
| 344 | impl CountingMode { | 427 | impl CountingMode { |
| 428 | /// Return whether this mode is edge-aligned (up or down). | ||
| 345 | pub fn is_edge_aligned(&self) -> bool { | 429 | pub fn is_edge_aligned(&self) -> bool { |
| 346 | match self { | 430 | match self { |
| 347 | CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, | 431 | CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, |
| @@ -349,6 +433,7 @@ impl CountingMode { | |||
| 349 | } | 433 | } |
| 350 | } | 434 | } |
| 351 | 435 | ||
| 436 | /// Return whether this mode is center-aligned. | ||
| 352 | pub fn is_center_aligned(&self) -> bool { | 437 | pub fn is_center_aligned(&self) -> bool { |
| 353 | match self { | 438 | match self { |
| 354 | CountingMode::CenterAlignedDownInterrupts | 439 | CountingMode::CenterAlignedDownInterrupts |
| @@ -383,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode { | |||
| 383 | } | 468 | } |
| 384 | } | 469 | } |
| 385 | 470 | ||
| 471 | /// Output compare mode. | ||
| 386 | #[derive(Clone, Copy)] | 472 | #[derive(Clone, Copy)] |
| 387 | pub enum OutputCompareMode { | 473 | pub enum OutputCompareMode { |
| 474 | /// The comparison between the output compare register TIMx_CCRx and | ||
| 475 | /// the counter TIMx_CNT has no effect on the outputs. | ||
| 476 | /// (this mode is used to generate a timing base). | ||
| 388 | Frozen, | 477 | Frozen, |
| 478 | /// Set channel to active level on match. OCxREF signal is forced high when the | ||
| 479 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 389 | ActiveOnMatch, | 480 | ActiveOnMatch, |
| 481 | /// Set channel to inactive level on match. OCxREF signal is forced low when the | ||
| 482 | /// counter TIMx_CNT matches the capture/compare register x (TIMx_CCRx). | ||
| 390 | InactiveOnMatch, | 483 | InactiveOnMatch, |
| 484 | /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx. | ||
| 391 | Toggle, | 485 | Toggle, |
| 486 | /// Force inactive level - OCxREF is forced low. | ||
| 392 | ForceInactive, | 487 | ForceInactive, |
| 488 | /// Force active level - OCxREF is forced high. | ||
| 393 | ForceActive, | 489 | ForceActive, |
| 490 | /// PWM mode 1 - In upcounting, channel is active as long as TIMx_CNT<TIMx_CCRx | ||
| 491 | /// else inactive. In downcounting, channel is inactive (OCxREF=0) as long as | ||
| 492 | /// TIMx_CNT>TIMx_CCRx else active (OCxREF=1). | ||
| 394 | PwmMode1, | 493 | PwmMode1, |
| 494 | /// PWM mode 2 - In upcounting, channel is inactive as long as | ||
| 495 | /// TIMx_CNT<TIMx_CCRx else active. In downcounting, channel is active as long as | ||
| 496 | /// TIMx_CNT>TIMx_CCRx else inactive. | ||
| 395 | PwmMode2, | 497 | PwmMode2, |
| 498 | // TODO: there's more modes here depending on the chip family. | ||
| 396 | } | 499 | } |
| 397 | 500 | ||
| 398 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | 501 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { |
| @@ -410,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | |||
| 410 | } | 513 | } |
| 411 | } | 514 | } |
| 412 | 515 | ||
| 516 | /// Timer output pin polarity. | ||
| 413 | #[derive(Clone, Copy)] | 517 | #[derive(Clone, Copy)] |
| 414 | pub enum OutputPolarity { | 518 | pub enum OutputPolarity { |
| 519 | /// Active high (higher duty value makes the pin spend more time high). | ||
| 415 | ActiveHigh, | 520 | ActiveHigh, |
| 521 | /// Active low (higher duty value makes the pin spend more time low). | ||
| 416 | ActiveLow, | 522 | ActiveLow, |
| 417 | } | 523 | } |
| 418 | 524 | ||
| @@ -425,24 +531,31 @@ impl From<OutputPolarity> for bool { | |||
| 425 | } | 531 | } |
| 426 | } | 532 | } |
| 427 | 533 | ||
| 534 | /// Basic 16-bit timer instance. | ||
| 428 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | 535 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} |
| 429 | 536 | ||
| 537 | /// Gneral-purpose 16-bit timer instance. | ||
| 430 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} | 538 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} |
| 431 | 539 | ||
| 540 | /// Gneral-purpose 32-bit timer instance. | ||
| 432 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} | 541 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} |
| 433 | 542 | ||
| 543 | /// Advanced control timer instance. | ||
| 434 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} | 544 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} |
| 435 | 545 | ||
| 546 | /// Capture/Compare 16-bit timer instance. | ||
| 436 | pub trait CaptureCompare16bitInstance: | 547 | pub trait CaptureCompare16bitInstance: |
| 437 | sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static | 548 | sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static |
| 438 | { | 549 | { |
| 439 | } | 550 | } |
| 440 | 551 | ||
| 552 | /// Capture/Compare 16-bit timer instance with complementary pin support. | ||
| 441 | pub trait ComplementaryCaptureCompare16bitInstance: | 553 | pub trait ComplementaryCaptureCompare16bitInstance: |
| 442 | sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static | 554 | sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static |
| 443 | { | 555 | { |
| 444 | } | 556 | } |
| 445 | 557 | ||
| 558 | /// Capture/Compare 32-bit timer instance. | ||
| 446 | pub trait CaptureCompare32bitInstance: | 559 | pub trait CaptureCompare32bitInstance: |
| 447 | sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static | 560 | sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static |
| 448 | { | 561 | { |
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs index 01d028bf9..59efb72ba 100644 --- a/embassy-stm32/src/timer/qei.rs +++ b/embassy-stm32/src/timer/qei.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Quadrature decoder using a timer. | ||
| 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}; |
| @@ -7,23 +9,30 @@ use crate::gpio::sealed::AFType; | |||
| 7 | use crate::gpio::AnyPin; | 9 | use crate::gpio::AnyPin; |
| 8 | use crate::Peripheral; | 10 | use crate::Peripheral; |
| 9 | 11 | ||
| 12 | /// Counting direction | ||
| 10 | pub enum Direction { | 13 | pub enum Direction { |
| 14 | /// Counting up. | ||
| 11 | Upcounting, | 15 | Upcounting, |
| 16 | /// Counting down. | ||
| 12 | Downcounting, | 17 | Downcounting, |
| 13 | } | 18 | } |
| 14 | 19 | ||
| 15 | pub struct Ch1; | 20 | /// Channel 1 marker type. |
| 16 | pub struct Ch2; | 21 | pub enum Ch1 {} |
| 22 | /// Channel 2 marker type. | ||
| 23 | pub enum Ch2 {} | ||
| 17 | 24 | ||
| 18 | pub struct QeiPin<'d, Perip, Channel> { | 25 | /// Wrapper for using a pin with QEI. |
| 26 | pub struct QeiPin<'d, T, Channel> { | ||
| 19 | _pin: PeripheralRef<'d, AnyPin>, | 27 | _pin: PeripheralRef<'d, AnyPin>, |
| 20 | phantom: PhantomData<(Perip, Channel)>, | 28 | phantom: PhantomData<(T, Channel)>, |
| 21 | } | 29 | } |
| 22 | 30 | ||
| 23 | macro_rules! channel_impl { | 31 | macro_rules! channel_impl { |
| 24 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 25 | impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { | 33 | impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> { |
| 26 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | 34 | #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self { | ||
| 27 | into_ref!(pin); | 36 | into_ref!(pin); |
| 28 | critical_section::with(|_| { | 37 | critical_section::with(|_| { |
| 29 | pin.set_low(); | 38 | pin.set_low(); |
| @@ -43,11 +52,13 @@ macro_rules! channel_impl { | |||
| 43 | channel_impl!(new_ch1, Ch1, Channel1Pin); | 52 | channel_impl!(new_ch1, Ch1, Channel1Pin); |
| 44 | channel_impl!(new_ch2, Ch2, Channel2Pin); | 53 | channel_impl!(new_ch2, Ch2, Channel2Pin); |
| 45 | 54 | ||
| 55 | /// Quadrature decoder driver. | ||
| 46 | pub struct Qei<'d, T> { | 56 | pub struct Qei<'d, T> { |
| 47 | _inner: PeripheralRef<'d, T>, | 57 | _inner: PeripheralRef<'d, T>, |
| 48 | } | 58 | } |
| 49 | 59 | ||
| 50 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | 60 | impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { |
| 61 | /// Create a new quadrature decoder driver. | ||
| 51 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { | 62 | pub fn new(tim: impl Peripheral<P = T> + 'd, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { |
| 52 | Self::new_inner(tim) | 63 | Self::new_inner(tim) |
| 53 | } | 64 | } |
| @@ -82,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 82 | Self { _inner: tim } | 93 | Self { _inner: tim } |
| 83 | } | 94 | } |
| 84 | 95 | ||
| 96 | /// Get direction. | ||
| 85 | pub fn read_direction(&self) -> Direction { | 97 | pub fn read_direction(&self) -> Direction { |
| 86 | match T::regs_gp16().cr1().read().dir() { | 98 | match T::regs_gp16().cr1().read().dir() { |
| 87 | vals::Dir::DOWN => Direction::Downcounting, | 99 | vals::Dir::DOWN => Direction::Downcounting, |
| @@ -89,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { | |||
| 89 | } | 101 | } |
| 90 | } | 102 | } |
| 91 | 103 | ||
| 104 | /// Get count. | ||
| 92 | pub fn count(&self) -> u16 { | 105 | pub fn count(&self) -> u16 { |
| 93 | T::regs_gp16().cnt().read().cnt() | 106 | T::regs_gp16().cnt().read().cnt() |
| 94 | } | 107 | } |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs index 1cf0ad728..e6072aa15 100644 --- a/embassy-stm32/src/timer/simple_pwm.rs +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | //! Simple PWM driver. | ||
| 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}; |
| @@ -9,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType}; | |||
| 9 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 10 | use crate::Peripheral; | 12 | use crate::Peripheral; |
| 11 | 13 | ||
| 12 | pub struct Ch1; | 14 | /// Channel 1 marker type. |
| 13 | pub struct Ch2; | 15 | pub enum Ch1 {} |
| 14 | pub struct Ch3; | 16 | /// Channel 2 marker type. |
| 15 | pub struct Ch4; | 17 | pub enum Ch2 {} |
| 16 | 18 | /// Channel 3 marker type. | |
| 17 | pub struct PwmPin<'d, Perip, Channel> { | 19 | pub enum Ch3 {} |
| 20 | /// Channel 4 marker type. | ||
| 21 | pub enum Ch4 {} | ||
| 22 | |||
| 23 | /// PWM pin wrapper. | ||
| 24 | /// | ||
| 25 | /// This wraps a pin to make it usable with PWM. | ||
| 26 | pub struct PwmPin<'d, T, C> { | ||
| 18 | _pin: PeripheralRef<'d, AnyPin>, | 27 | _pin: PeripheralRef<'d, AnyPin>, |
| 19 | phantom: PhantomData<(Perip, Channel)>, | 28 | phantom: PhantomData<(T, C)>, |
| 20 | } | 29 | } |
| 21 | 30 | ||
| 22 | macro_rules! channel_impl { | 31 | macro_rules! channel_impl { |
| 23 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | 32 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { |
| 24 | impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { | 33 | impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> { |
| 25 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd, output_type: OutputType) -> Self { | 34 | #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] |
| 35 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd, output_type: OutputType) -> Self { | ||
| 26 | into_ref!(pin); | 36 | into_ref!(pin); |
| 27 | critical_section::with(|_| { | 37 | critical_section::with(|_| { |
| 28 | pin.set_low(); | 38 | pin.set_low(); |
| @@ -44,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin); | |||
| 44 | channel_impl!(new_ch3, Ch3, Channel3Pin); | 54 | channel_impl!(new_ch3, Ch3, Channel3Pin); |
| 45 | channel_impl!(new_ch4, Ch4, Channel4Pin); | 55 | channel_impl!(new_ch4, Ch4, Channel4Pin); |
| 46 | 56 | ||
| 57 | /// Simple PWM driver. | ||
| 47 | pub struct SimplePwm<'d, T> { | 58 | pub struct SimplePwm<'d, T> { |
| 48 | inner: PeripheralRef<'d, T>, | 59 | inner: PeripheralRef<'d, T>, |
| 49 | } | 60 | } |
| 50 | 61 | ||
| 51 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | 62 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { |
| 63 | /// Create a new simple PWM driver. | ||
| 52 | pub fn new( | 64 | pub fn new( |
| 53 | tim: impl Peripheral<P = T> + 'd, | 65 | tim: impl Peripheral<P = T> + 'd, |
| 54 | _ch1: Option<PwmPin<'d, T, Ch1>>, | 66 | _ch1: Option<PwmPin<'d, T, Ch1>>, |
| @@ -69,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 69 | let mut this = Self { inner: tim }; | 81 | let mut this = Self { inner: tim }; |
| 70 | 82 | ||
| 71 | this.inner.set_counting_mode(counting_mode); | 83 | this.inner.set_counting_mode(counting_mode); |
| 72 | this.set_freq(freq); | 84 | this.set_frequency(freq); |
| 73 | this.inner.start(); | 85 | this.inner.start(); |
| 74 | 86 | ||
| 75 | this.inner.enable_outputs(); | 87 | this.inner.enable_outputs(); |
| @@ -85,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 85 | this | 97 | this |
| 86 | } | 98 | } |
| 87 | 99 | ||
| 100 | /// Enable the given channel. | ||
| 88 | pub fn enable(&mut self, channel: Channel) { | 101 | pub fn enable(&mut self, channel: Channel) { |
| 89 | self.inner.enable_channel(channel, true); | 102 | self.inner.enable_channel(channel, true); |
| 90 | } | 103 | } |
| 91 | 104 | ||
| 105 | /// Disable the given channel. | ||
| 92 | pub fn disable(&mut self, channel: Channel) { | 106 | pub fn disable(&mut self, channel: Channel) { |
| 93 | self.inner.enable_channel(channel, false); | 107 | self.inner.enable_channel(channel, false); |
| 94 | } | 108 | } |
| 95 | 109 | ||
| 96 | pub fn set_freq(&mut self, freq: Hertz) { | 110 | /// Set PWM frequency. |
| 111 | /// | ||
| 112 | /// Note: when you call this, the max duty value changes, so you will have to | ||
| 113 | /// call `set_duty` on all channels with the duty calculated based on the new max duty. | ||
| 114 | pub fn set_frequency(&mut self, freq: Hertz) { | ||
| 97 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { | 115 | let multiplier = if self.inner.get_counting_mode().is_center_aligned() { |
| 98 | 2u8 | 116 | 2u8 |
| 99 | } else { | 117 | } else { |
| @@ -102,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | |||
| 102 | self.inner.set_frequency(freq * multiplier); | 120 | self.inner.set_frequency(freq * multiplier); |
| 103 | } | 121 | } |
| 104 | 122 | ||
| 123 | /// Get max duty value. | ||
| 124 | /// | ||
| 125 | /// This value depends on the configured frequency and the timer's clock rate from RCC. | ||
| 105 | pub fn get_max_duty(&self) -> u16 { | 126 | pub fn get_max_duty(&self) -> u16 { |
| 106 | self.inner.get_max_compare_value() + 1 | 127 | self.inner.get_max_compare_value() + 1 |
| 107 | } | 128 | } |
| 108 | 129 | ||
| 130 | /// Set the duty for a given channel. | ||
| 131 | /// | ||
| 132 | /// The value ranges from 0 for 0% duty, to [`get_max_duty`](Self::get_max_duty) for 100% duty, both included. | ||
| 109 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | 133 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { |
| 110 | assert!(duty <= self.get_max_duty()); | 134 | assert!(duty <= self.get_max_duty()); |
| 111 | self.inner.set_compare_value(channel, duty) | 135 | self.inner.set_compare_value(channel, duty) |
| 112 | } | 136 | } |
| 113 | 137 | ||
| 138 | /// Set the output polarity for a given channel. | ||
| 114 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { | 139 | pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { |
| 115 | self.inner.set_output_polarity(channel, polarity); | 140 | self.inner.set_output_polarity(channel, polarity); |
| 116 | } | 141 | } |
