diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-07-28 15:29:27 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-07-28 15:29:27 +0200 |
| commit | 3690af9bea5968653780d296146a91c63994d89d (patch) | |
| tree | 02baa484846448186a13b28c52cc4221b4111b74 /embassy-stm32/src/timer | |
| parent | b1242226494bfdeed13c2f80c5df239687a398ac (diff) | |
stm32/timer: merge pwm module into timer. (#1703)
The traits there are applicable to timer use cases other than PWM.
It doesn't make sense to keep them separated.
Diffstat (limited to 'embassy-stm32/src/timer')
| -rw-r--r-- | embassy-stm32/src/timer/complementary_pwm.rs | 250 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/mod.rs | 271 | ||||
| -rw-r--r-- | embassy-stm32/src/timer/simple_pwm.rs | 107 |
3 files changed, 603 insertions, 25 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs new file mode 100644 index 000000000..64bb32c39 --- /dev/null +++ b/embassy-stm32/src/timer/complementary_pwm.rs | |||
| @@ -0,0 +1,250 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 4 | use stm32_metapac::timer::vals::Ckd; | ||
| 5 | |||
| 6 | use super::simple_pwm::*; | ||
| 7 | use super::*; | ||
| 8 | #[allow(unused_imports)] | ||
| 9 | use crate::gpio::sealed::{AFType, Pin}; | ||
| 10 | use crate::gpio::AnyPin; | ||
| 11 | use crate::time::Hertz; | ||
| 12 | use crate::Peripheral; | ||
| 13 | |||
| 14 | pub struct ComplementaryPwmPin<'d, Perip, Channel> { | ||
| 15 | _pin: PeripheralRef<'d, AnyPin>, | ||
| 16 | phantom: PhantomData<(Perip, Channel)>, | ||
| 17 | } | ||
| 18 | |||
| 19 | macro_rules! complementary_channel_impl { | ||
| 20 | ($new_chx:ident, $channel:ident, $pin_trait:ident, $complementary_pin_trait:ident) => { | ||
| 21 | impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { | ||
| 22 | pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { | ||
| 23 | into_ref!(pin); | ||
| 24 | critical_section::with(|_| { | ||
| 25 | pin.set_low(); | ||
| 26 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||
| 27 | #[cfg(gpio_v2)] | ||
| 28 | pin.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 29 | }); | ||
| 30 | ComplementaryPwmPin { | ||
| 31 | _pin: pin.map_into(), | ||
| 32 | phantom: PhantomData, | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | } | ||
| 38 | |||
| 39 | complementary_channel_impl!(new_ch1, Ch1, Channel1Pin, Channel1ComplementaryPin); | ||
| 40 | complementary_channel_impl!(new_ch2, Ch2, Channel2Pin, Channel2ComplementaryPin); | ||
| 41 | complementary_channel_impl!(new_ch3, Ch3, Channel3Pin, Channel3ComplementaryPin); | ||
| 42 | complementary_channel_impl!(new_ch4, Ch4, Channel4Pin, Channel4ComplementaryPin); | ||
| 43 | |||
| 44 | pub struct ComplementaryPwm<'d, T> { | ||
| 45 | inner: PeripheralRef<'d, T>, | ||
| 46 | } | ||
| 47 | |||
| 48 | impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { | ||
| 49 | pub fn new( | ||
| 50 | tim: impl Peripheral<P = T> + 'd, | ||
| 51 | _ch1: Option<PwmPin<'d, T, Ch1>>, | ||
| 52 | _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>, | ||
| 53 | _ch2: Option<PwmPin<'d, T, Ch2>>, | ||
| 54 | _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>, | ||
| 55 | _ch3: Option<PwmPin<'d, T, Ch3>>, | ||
| 56 | _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>, | ||
| 57 | _ch4: Option<PwmPin<'d, T, Ch4>>, | ||
| 58 | _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>, | ||
| 59 | freq: Hertz, | ||
| 60 | ) -> Self { | ||
| 61 | Self::new_inner(tim, freq) | ||
| 62 | } | ||
| 63 | |||
| 64 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self { | ||
| 65 | into_ref!(tim); | ||
| 66 | |||
| 67 | T::enable(); | ||
| 68 | <T as crate::rcc::sealed::RccPeripheral>::reset(); | ||
| 69 | |||
| 70 | let mut this = Self { inner: tim }; | ||
| 71 | |||
| 72 | this.inner.set_frequency(freq); | ||
| 73 | this.inner.start(); | ||
| 74 | |||
| 75 | this.inner.enable_outputs(true); | ||
| 76 | |||
| 77 | this.inner | ||
| 78 | .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | ||
| 79 | this.inner | ||
| 80 | .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | ||
| 81 | this.inner | ||
| 82 | .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | ||
| 83 | this.inner | ||
| 84 | .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||
| 85 | this | ||
| 86 | } | ||
| 87 | |||
| 88 | pub fn enable(&mut self, channel: Channel) { | ||
| 89 | self.inner.enable_channel(channel, true); | ||
| 90 | self.inner.enable_complementary_channel(channel, true); | ||
| 91 | } | ||
| 92 | |||
| 93 | pub fn disable(&mut self, channel: Channel) { | ||
| 94 | self.inner.enable_complementary_channel(channel, false); | ||
| 95 | self.inner.enable_channel(channel, false); | ||
| 96 | } | ||
| 97 | |||
| 98 | pub fn set_freq(&mut self, freq: Hertz) { | ||
| 99 | self.inner.set_frequency(freq); | ||
| 100 | } | ||
| 101 | |||
| 102 | pub fn get_max_duty(&self) -> u16 { | ||
| 103 | self.inner.get_max_compare_value() | ||
| 104 | } | ||
| 105 | |||
| 106 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | ||
| 107 | assert!(duty < self.get_max_duty()); | ||
| 108 | self.inner.set_compare_value(channel, duty) | ||
| 109 | } | ||
| 110 | |||
| 111 | /// Set the dead time as a proportion of max_duty | ||
| 112 | pub fn set_dead_time(&mut self, value: u16) { | ||
| 113 | let (ckd, value) = compute_dead_time_value(value); | ||
| 114 | |||
| 115 | self.inner.set_dead_time_clock_division(ckd); | ||
| 116 | self.inner.set_dead_time_value(value); | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | fn compute_dead_time_value(value: u16) -> (Ckd, u8) { | ||
| 121 | /* | ||
| 122 | Dead-time = T_clk * T_dts * T_dtg | ||
| 123 | |||
| 124 | T_dts: | ||
| 125 | This bit-field indicates the division ratio between the timer clock (CK_INT) frequency and the | ||
| 126 | dead-time and sampling clock (tDTS)used by the dead-time generators and the digital filters | ||
| 127 | (ETR, TIx), | ||
| 128 | 00: tDTS=tCK_INT | ||
| 129 | 01: tDTS=2*tCK_INT | ||
| 130 | 10: tDTS=4*tCK_INT | ||
| 131 | |||
| 132 | T_dtg: | ||
| 133 | This bit-field defines the duration of the dead-time inserted between the complementary | ||
| 134 | outputs. DT correspond to this duration. | ||
| 135 | DTG[7:5]=0xx => DT=DTG[7:0]x tdtg with tdtg=tDTS. | ||
| 136 | DTG[7:5]=10x => DT=(64+DTG[5:0])xtdtg with Tdtg=2xtDTS. | ||
| 137 | DTG[7:5]=110 => DT=(32+DTG[4:0])xtdtg with Tdtg=8xtDTS. | ||
| 138 | DTG[7:5]=111 => DT=(32+DTG[4:0])xtdtg with Tdtg=16xtDTS. | ||
| 139 | Example if TDTS=125ns (8MHz), dead-time possible values are: | ||
| 140 | 0 to 15875 ns by 125 ns steps, | ||
| 141 | 16 us to 31750 ns by 250 ns steps, | ||
| 142 | 32 us to 63us by 1 us steps, | ||
| 143 | 64 us to 126 us by 2 us steps | ||
| 144 | */ | ||
| 145 | |||
| 146 | let mut error = u16::MAX; | ||
| 147 | let mut ckd = Ckd::DIV1; | ||
| 148 | let mut bits = 0u8; | ||
| 149 | |||
| 150 | for this_ckd in [Ckd::DIV1, Ckd::DIV2, Ckd::DIV4] { | ||
| 151 | let outdiv = match this_ckd { | ||
| 152 | Ckd::DIV1 => 1, | ||
| 153 | Ckd::DIV2 => 2, | ||
| 154 | Ckd::DIV4 => 4, | ||
| 155 | _ => unreachable!(), | ||
| 156 | }; | ||
| 157 | |||
| 158 | // 127 | ||
| 159 | // 128 | ||
| 160 | // .. | ||
| 161 | // 254 | ||
| 162 | // 256 | ||
| 163 | // .. | ||
| 164 | // 504 | ||
| 165 | // 512 | ||
| 166 | // .. | ||
| 167 | // 1008 | ||
| 168 | |||
| 169 | let target = value / outdiv; | ||
| 170 | let (these_bits, result) = if target < 128 { | ||
| 171 | (target as u8, target) | ||
| 172 | } else if target < 255 { | ||
| 173 | (64 + (target / 2) as u8, (target - target % 2)) | ||
| 174 | } else if target < 508 { | ||
| 175 | (32 + (target / 8) as u8, (target - target % 8)) | ||
| 176 | } else if target < 1008 { | ||
| 177 | (32 + (target / 16) as u8, (target - target % 16)) | ||
| 178 | } else { | ||
| 179 | (u8::MAX, 1008) | ||
| 180 | }; | ||
| 181 | |||
| 182 | let this_error = value.abs_diff(result * outdiv); | ||
| 183 | if error > this_error { | ||
| 184 | ckd = this_ckd; | ||
| 185 | bits = these_bits; | ||
| 186 | error = this_error; | ||
| 187 | } | ||
| 188 | |||
| 189 | match error { | ||
| 190 | 0 => break, | ||
| 191 | _ => {} | ||
| 192 | } | ||
| 193 | } | ||
| 194 | |||
| 195 | (ckd, bits) | ||
| 196 | } | ||
| 197 | |||
| 198 | #[cfg(test)] | ||
| 199 | mod tests { | ||
| 200 | use super::{compute_dead_time_value, Ckd}; | ||
| 201 | |||
| 202 | #[test] | ||
| 203 | fn test_compute_dead_time_value() { | ||
| 204 | struct TestRun { | ||
| 205 | value: u16, | ||
| 206 | ckd: Ckd, | ||
| 207 | bits: u8, | ||
| 208 | } | ||
| 209 | |||
| 210 | let fn_results = [ | ||
| 211 | TestRun { | ||
| 212 | value: 1, | ||
| 213 | ckd: Ckd::DIV1, | ||
| 214 | bits: 1, | ||
| 215 | }, | ||
| 216 | TestRun { | ||
| 217 | value: 125, | ||
| 218 | ckd: Ckd::DIV1, | ||
| 219 | bits: 125, | ||
| 220 | }, | ||
| 221 | TestRun { | ||
| 222 | value: 245, | ||
| 223 | ckd: Ckd::DIV1, | ||
| 224 | bits: 64 + 245 / 2, | ||
| 225 | }, | ||
| 226 | TestRun { | ||
| 227 | value: 255, | ||
| 228 | ckd: Ckd::DIV2, | ||
| 229 | bits: 127, | ||
| 230 | }, | ||
| 231 | TestRun { | ||
| 232 | value: 400, | ||
| 233 | ckd: Ckd::DIV1, | ||
| 234 | bits: 32 + (400u16 / 8) as u8, | ||
| 235 | }, | ||
| 236 | TestRun { | ||
| 237 | value: 600, | ||
| 238 | ckd: Ckd::DIV4, | ||
| 239 | bits: 64 + (600u16 / 8) as u8, | ||
| 240 | }, | ||
| 241 | ]; | ||
| 242 | |||
| 243 | for test_run in fn_results { | ||
| 244 | let (ckd, bits) = compute_dead_time_value(test_run.value); | ||
| 245 | |||
| 246 | assert_eq!(ckd.to_bits(), test_run.ckd.to_bits()); | ||
| 247 | assert_eq!(bits, test_run.bits); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | } | ||
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs index 09b7a3776..6c2d6d827 100644 --- a/embassy-stm32/src/timer/mod.rs +++ b/embassy-stm32/src/timer/mod.rs | |||
| @@ -1,3 +1,6 @@ | |||
| 1 | pub mod complementary_pwm; | ||
| 2 | pub mod simple_pwm; | ||
| 3 | |||
| 1 | use stm32_metapac::timer::vals; | 4 | use stm32_metapac::timer::vals; |
| 2 | 5 | ||
| 3 | use crate::interrupt; | 6 | use crate::interrupt; |
| @@ -43,15 +46,123 @@ pub(crate) mod sealed { | |||
| 43 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { | 46 | pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { |
| 44 | fn regs_advanced() -> crate::pac::timer::TimAdv; | 47 | fn regs_advanced() -> crate::pac::timer::TimAdv; |
| 45 | } | 48 | } |
| 49 | |||
| 50 | pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { | ||
| 51 | /// Global output enable. Does not do anything on non-advanced timers. | ||
| 52 | fn enable_outputs(&mut self, enable: bool); | ||
| 53 | |||
| 54 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | ||
| 55 | |||
| 56 | fn enable_channel(&mut self, channel: Channel, enable: bool); | ||
| 57 | |||
| 58 | fn set_compare_value(&mut self, channel: Channel, value: u16); | ||
| 59 | |||
| 60 | fn get_max_compare_value(&self) -> u16; | ||
| 61 | } | ||
| 62 | |||
| 63 | pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance { | ||
| 64 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd); | ||
| 65 | |||
| 66 | fn set_dead_time_value(&mut self, value: u8); | ||
| 67 | |||
| 68 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool); | ||
| 69 | } | ||
| 70 | |||
| 71 | pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance { | ||
| 72 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode); | ||
| 73 | |||
| 74 | fn enable_channel(&mut self, channel: Channel, enable: bool); | ||
| 75 | |||
| 76 | fn set_compare_value(&mut self, channel: Channel, value: u32); | ||
| 77 | |||
| 78 | fn get_max_compare_value(&self) -> u32; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | #[derive(Clone, Copy)] | ||
| 83 | pub enum Channel { | ||
| 84 | Ch1, | ||
| 85 | Ch2, | ||
| 86 | Ch3, | ||
| 87 | Ch4, | ||
| 46 | } | 88 | } |
| 47 | 89 | ||
| 90 | impl Channel { | ||
| 91 | pub fn raw(&self) -> usize { | ||
| 92 | match self { | ||
| 93 | Channel::Ch1 => 0, | ||
| 94 | Channel::Ch2 => 1, | ||
| 95 | Channel::Ch3 => 2, | ||
| 96 | Channel::Ch4 => 3, | ||
| 97 | } | ||
| 98 | } | ||
| 99 | } | ||
| 100 | |||
| 101 | #[derive(Clone, Copy)] | ||
| 102 | pub enum OutputCompareMode { | ||
| 103 | Frozen, | ||
| 104 | ActiveOnMatch, | ||
| 105 | InactiveOnMatch, | ||
| 106 | Toggle, | ||
| 107 | ForceInactive, | ||
| 108 | ForceActive, | ||
| 109 | PwmMode1, | ||
| 110 | PwmMode2, | ||
| 111 | } | ||
| 112 | |||
| 113 | impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { | ||
| 114 | fn from(mode: OutputCompareMode) -> Self { | ||
| 115 | match mode { | ||
| 116 | OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN, | ||
| 117 | OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH, | ||
| 118 | OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH, | ||
| 119 | OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE, | ||
| 120 | OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE, | ||
| 121 | OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE, | ||
| 122 | OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1, | ||
| 123 | OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2, | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | ||
| 129 | |||
| 48 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} | 130 | pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} |
| 49 | 131 | ||
| 50 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} | 132 | pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} |
| 51 | 133 | ||
| 52 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} | 134 | pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} |
| 53 | 135 | ||
| 54 | pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} | 136 | pub trait CaptureCompare16bitInstance: |
| 137 | sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static | ||
| 138 | { | ||
| 139 | } | ||
| 140 | |||
| 141 | pub trait ComplementaryCaptureCompare16bitInstance: | ||
| 142 | sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static | ||
| 143 | { | ||
| 144 | } | ||
| 145 | |||
| 146 | pub trait CaptureCompare32bitInstance: | ||
| 147 | sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static | ||
| 148 | { | ||
| 149 | } | ||
| 150 | |||
| 151 | pin_trait!(Channel1Pin, CaptureCompare16bitInstance); | ||
| 152 | pin_trait!(Channel1ComplementaryPin, CaptureCompare16bitInstance); | ||
| 153 | pin_trait!(Channel2Pin, CaptureCompare16bitInstance); | ||
| 154 | pin_trait!(Channel2ComplementaryPin, CaptureCompare16bitInstance); | ||
| 155 | pin_trait!(Channel3Pin, CaptureCompare16bitInstance); | ||
| 156 | pin_trait!(Channel3ComplementaryPin, CaptureCompare16bitInstance); | ||
| 157 | pin_trait!(Channel4Pin, CaptureCompare16bitInstance); | ||
| 158 | pin_trait!(Channel4ComplementaryPin, CaptureCompare16bitInstance); | ||
| 159 | pin_trait!(ExternalTriggerPin, CaptureCompare16bitInstance); | ||
| 160 | pin_trait!(BreakInputPin, CaptureCompare16bitInstance); | ||
| 161 | pin_trait!(BreakInputComparator1Pin, CaptureCompare16bitInstance); | ||
| 162 | pin_trait!(BreakInputComparator2Pin, CaptureCompare16bitInstance); | ||
| 163 | pin_trait!(BreakInput2Pin, CaptureCompare16bitInstance); | ||
| 164 | pin_trait!(BreakInput2Comparator1Pin, CaptureCompare16bitInstance); | ||
| 165 | pin_trait!(BreakInput2Comparator2Pin, CaptureCompare16bitInstance); | ||
| 55 | 166 | ||
| 56 | #[allow(unused)] | 167 | #[allow(unused)] |
| 57 | macro_rules! impl_basic_16bit_timer { | 168 | macro_rules! impl_basic_16bit_timer { |
| @@ -140,33 +251,94 @@ macro_rules! impl_32bit_timer { | |||
| 140 | }; | 251 | }; |
| 141 | } | 252 | } |
| 142 | 253 | ||
| 254 | #[allow(unused)] | ||
| 255 | macro_rules! impl_compare_capable_16bit { | ||
| 256 | ($inst:ident) => { | ||
| 257 | impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { | ||
| 258 | fn enable_outputs(&mut self, _enable: bool) {} | ||
| 259 | |||
| 260 | fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { | ||
| 261 | use sealed::GeneralPurpose16bitInstance; | ||
| 262 | let r = Self::regs_gp16(); | ||
| 263 | let raw_channel: usize = channel.raw(); | ||
| 264 | r.ccmr_output(raw_channel / 2) | ||
| 265 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||
| 266 | } | ||
| 267 | |||
| 268 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||
| 269 | use sealed::GeneralPurpose16bitInstance; | ||
| 270 | Self::regs_gp16() | ||
| 271 | .ccer() | ||
| 272 | .modify(|w| w.set_cce(channel.raw(), enable)); | ||
| 273 | } | ||
| 274 | |||
| 275 | fn set_compare_value(&mut self, channel: Channel, value: u16) { | ||
| 276 | use sealed::GeneralPurpose16bitInstance; | ||
| 277 | Self::regs_gp16().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | ||
| 278 | } | ||
| 279 | |||
| 280 | fn get_max_compare_value(&self) -> u16 { | ||
| 281 | use sealed::GeneralPurpose16bitInstance; | ||
| 282 | Self::regs_gp16().arr().read().arr() | ||
| 283 | } | ||
| 284 | } | ||
| 285 | }; | ||
| 286 | } | ||
| 287 | |||
| 143 | foreach_interrupt! { | 288 | foreach_interrupt! { |
| 144 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { | 289 | ($inst:ident, timer, TIM_BASIC, UP, $irq:ident) => { |
| 145 | impl_basic_16bit_timer!($inst, $irq); | 290 | impl_basic_16bit_timer!($inst, $irq); |
| 146 | 291 | impl Basic16bitInstance for crate::peripherals::$inst {} | |
| 147 | impl Basic16bitInstance for crate::peripherals::$inst { | ||
| 148 | } | ||
| 149 | }; | 292 | }; |
| 150 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { | 293 | ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => { |
| 151 | impl_basic_16bit_timer!($inst, $irq); | 294 | impl_basic_16bit_timer!($inst, $irq); |
| 152 | 295 | impl_compare_capable_16bit!($inst); | |
| 153 | impl Basic16bitInstance for crate::peripherals::$inst { | 296 | impl Basic16bitInstance for crate::peripherals::$inst {} |
| 154 | } | 297 | impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} |
| 298 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 155 | 299 | ||
| 156 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | 300 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { |
| 157 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | 301 | fn regs_gp16() -> crate::pac::timer::TimGp16 { |
| 158 | crate::pac::$inst | 302 | crate::pac::$inst |
| 159 | } | 303 | } |
| 160 | } | 304 | } |
| 161 | |||
| 162 | impl GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||
| 163 | } | ||
| 164 | }; | 305 | }; |
| 165 | 306 | ||
| 166 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { | 307 | ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => { |
| 167 | impl_basic_16bit_timer!($inst, $irq); | 308 | impl_basic_16bit_timer!($inst, $irq); |
| 309 | impl_32bit_timer!($inst); | ||
| 310 | impl_compare_capable_16bit!($inst); | ||
| 311 | impl Basic16bitInstance for crate::peripherals::$inst {} | ||
| 312 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 313 | impl CaptureCompare32bitInstance for crate::peripherals::$inst {} | ||
| 314 | impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} | ||
| 315 | impl GeneralPurpose32bitInstance for crate::peripherals::$inst {} | ||
| 316 | |||
| 317 | impl sealed::CaptureCompare32bitInstance for crate::peripherals::$inst { | ||
| 318 | fn set_output_compare_mode( | ||
| 319 | &mut self, | ||
| 320 | channel: Channel, | ||
| 321 | mode: OutputCompareMode, | ||
| 322 | ) { | ||
| 323 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 324 | let raw_channel = channel.raw(); | ||
| 325 | Self::regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||
| 326 | } | ||
| 327 | |||
| 328 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||
| 329 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 330 | Self::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable)); | ||
| 331 | } | ||
| 168 | 332 | ||
| 169 | impl Basic16bitInstance for crate::peripherals::$inst { | 333 | fn set_compare_value(&mut self, channel: Channel, value: u32) { |
| 334 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 335 | Self::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value)); | ||
| 336 | } | ||
| 337 | |||
| 338 | fn get_max_compare_value(&self) -> u32 { | ||
| 339 | use crate::timer::sealed::GeneralPurpose32bitInstance; | ||
| 340 | Self::regs_gp32().arr().read().arr() as u32 | ||
| 341 | } | ||
| 170 | } | 342 | } |
| 171 | 343 | ||
| 172 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | 344 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { |
| @@ -174,21 +346,16 @@ foreach_interrupt! { | |||
| 174 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } | 346 | unsafe { crate::pac::timer::TimGp16::from_ptr(crate::pac::$inst.as_ptr()) } |
| 175 | } | 347 | } |
| 176 | } | 348 | } |
| 177 | |||
| 178 | impl GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||
| 179 | } | ||
| 180 | |||
| 181 | impl_32bit_timer!($inst); | ||
| 182 | |||
| 183 | impl GeneralPurpose32bitInstance for crate::peripherals::$inst { | ||
| 184 | } | ||
| 185 | }; | 349 | }; |
| 186 | 350 | ||
| 187 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { | 351 | ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => { |
| 188 | impl_basic_16bit_timer!($inst, $irq); | 352 | impl_basic_16bit_timer!($inst, $irq); |
| 189 | 353 | ||
| 190 | impl Basic16bitInstance for crate::peripherals::$inst { | 354 | impl Basic16bitInstance for crate::peripherals::$inst {} |
| 191 | } | 355 | impl GeneralPurpose16bitInstance for crate::peripherals::$inst {} |
| 356 | impl CaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 357 | impl ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst {} | ||
| 358 | impl AdvancedControlInstance for crate::peripherals::$inst {} | ||
| 192 | 359 | ||
| 193 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { | 360 | impl sealed::GeneralPurpose16bitInstance for crate::peripherals::$inst { |
| 194 | fn regs_gp16() -> crate::pac::timer::TimGp16 { | 361 | fn regs_gp16() -> crate::pac::timer::TimGp16 { |
| @@ -196,16 +363,70 @@ foreach_interrupt! { | |||
| 196 | } | 363 | } |
| 197 | } | 364 | } |
| 198 | 365 | ||
| 199 | impl GeneralPurpose16bitInstance for crate::peripherals::$inst { | ||
| 200 | } | ||
| 201 | |||
| 202 | impl sealed::AdvancedControlInstance for crate::peripherals::$inst { | 366 | impl sealed::AdvancedControlInstance for crate::peripherals::$inst { |
| 203 | fn regs_advanced() -> crate::pac::timer::TimAdv { | 367 | fn regs_advanced() -> crate::pac::timer::TimAdv { |
| 204 | crate::pac::$inst | 368 | crate::pac::$inst |
| 205 | } | 369 | } |
| 206 | } | 370 | } |
| 207 | 371 | ||
| 208 | impl AdvancedControlInstance for crate::peripherals::$inst { | 372 | impl sealed::CaptureCompare16bitInstance for crate::peripherals::$inst { |
| 373 | fn enable_outputs(&mut self, enable: bool) { | ||
| 374 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 375 | let r = Self::regs_advanced(); | ||
| 376 | r.bdtr().modify(|w| w.set_moe(enable)); | ||
| 377 | } | ||
| 378 | |||
| 379 | fn set_output_compare_mode( | ||
| 380 | &mut self, | ||
| 381 | channel: Channel, | ||
| 382 | mode: OutputCompareMode, | ||
| 383 | ) { | ||
| 384 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 385 | let r = Self::regs_advanced(); | ||
| 386 | let raw_channel: usize = channel.raw(); | ||
| 387 | r.ccmr_output(raw_channel / 2) | ||
| 388 | .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); | ||
| 389 | } | ||
| 390 | |||
| 391 | fn enable_channel(&mut self, channel: Channel, enable: bool) { | ||
| 392 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 393 | Self::regs_advanced() | ||
| 394 | .ccer() | ||
| 395 | .modify(|w| w.set_cce(channel.raw(), enable)); | ||
| 396 | } | ||
| 397 | |||
| 398 | fn set_compare_value(&mut self, channel: Channel, value: u16) { | ||
| 399 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 400 | Self::regs_advanced() | ||
| 401 | .ccr(channel.raw()) | ||
| 402 | .modify(|w| w.set_ccr(value)); | ||
| 403 | } | ||
| 404 | |||
| 405 | fn get_max_compare_value(&self) -> u16 { | ||
| 406 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 407 | Self::regs_advanced().arr().read().arr() | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | impl sealed::ComplementaryCaptureCompare16bitInstance for crate::peripherals::$inst { | ||
| 412 | fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { | ||
| 413 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 414 | Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); | ||
| 415 | } | ||
| 416 | |||
| 417 | fn set_dead_time_value(&mut self, value: u8) { | ||
| 418 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 419 | Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); | ||
| 420 | } | ||
| 421 | |||
| 422 | fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { | ||
| 423 | use crate::timer::sealed::AdvancedControlInstance; | ||
| 424 | Self::regs_advanced() | ||
| 425 | .ccer() | ||
| 426 | .modify(|w| w.set_ccne(channel.raw(), enable)); | ||
| 427 | } | ||
| 209 | } | 428 | } |
| 429 | |||
| 430 | |||
| 210 | }; | 431 | }; |
| 211 | } | 432 | } |
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs new file mode 100644 index 000000000..514796930 --- /dev/null +++ b/embassy-stm32/src/timer/simple_pwm.rs | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_internal::{into_ref, PeripheralRef}; | ||
| 4 | |||
| 5 | use super::*; | ||
| 6 | #[allow(unused_imports)] | ||
| 7 | use crate::gpio::sealed::{AFType, Pin}; | ||
| 8 | use crate::gpio::AnyPin; | ||
| 9 | use crate::time::Hertz; | ||
| 10 | use crate::Peripheral; | ||
| 11 | |||
| 12 | pub struct Ch1; | ||
| 13 | pub struct Ch2; | ||
| 14 | pub struct Ch3; | ||
| 15 | pub struct Ch4; | ||
| 16 | |||
| 17 | pub struct PwmPin<'d, Perip, Channel> { | ||
| 18 | _pin: PeripheralRef<'d, AnyPin>, | ||
| 19 | phantom: PhantomData<(Perip, Channel)>, | ||
| 20 | } | ||
| 21 | |||
| 22 | macro_rules! channel_impl { | ||
| 23 | ($new_chx:ident, $channel:ident, $pin_trait:ident) => { | ||
| 24 | impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { | ||
| 25 | pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { | ||
| 26 | into_ref!(pin); | ||
| 27 | critical_section::with(|_| { | ||
| 28 | pin.set_low(); | ||
| 29 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||
| 30 | #[cfg(gpio_v2)] | ||
| 31 | pin.set_speed(crate::gpio::Speed::VeryHigh); | ||
| 32 | }); | ||
| 33 | PwmPin { | ||
| 34 | _pin: pin.map_into(), | ||
| 35 | phantom: PhantomData, | ||
| 36 | } | ||
| 37 | } | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | } | ||
| 41 | |||
| 42 | channel_impl!(new_ch1, Ch1, Channel1Pin); | ||
| 43 | channel_impl!(new_ch2, Ch2, Channel2Pin); | ||
| 44 | channel_impl!(new_ch3, Ch3, Channel3Pin); | ||
| 45 | channel_impl!(new_ch4, Ch4, Channel4Pin); | ||
| 46 | |||
| 47 | pub struct SimplePwm<'d, T> { | ||
| 48 | inner: PeripheralRef<'d, T>, | ||
| 49 | } | ||
| 50 | |||
| 51 | impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { | ||
| 52 | pub fn new( | ||
| 53 | tim: impl Peripheral<P = T> + 'd, | ||
| 54 | _ch1: Option<PwmPin<'d, T, Ch1>>, | ||
| 55 | _ch2: Option<PwmPin<'d, T, Ch2>>, | ||
| 56 | _ch3: Option<PwmPin<'d, T, Ch3>>, | ||
| 57 | _ch4: Option<PwmPin<'d, T, Ch4>>, | ||
| 58 | freq: Hertz, | ||
| 59 | ) -> Self { | ||
| 60 | Self::new_inner(tim, freq) | ||
| 61 | } | ||
| 62 | |||
| 63 | fn new_inner(tim: impl Peripheral<P = T> + 'd, freq: Hertz) -> Self { | ||
| 64 | into_ref!(tim); | ||
| 65 | |||
| 66 | T::enable(); | ||
| 67 | <T as crate::rcc::sealed::RccPeripheral>::reset(); | ||
| 68 | |||
| 69 | let mut this = Self { inner: tim }; | ||
| 70 | |||
| 71 | this.inner.set_frequency(freq); | ||
| 72 | this.inner.start(); | ||
| 73 | |||
| 74 | this.inner.enable_outputs(true); | ||
| 75 | |||
| 76 | this.inner | ||
| 77 | .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1); | ||
| 78 | this.inner | ||
| 79 | .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1); | ||
| 80 | this.inner | ||
| 81 | .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1); | ||
| 82 | this.inner | ||
| 83 | .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1); | ||
| 84 | this | ||
| 85 | } | ||
| 86 | |||
| 87 | pub fn enable(&mut self, channel: Channel) { | ||
| 88 | self.inner.enable_channel(channel, true); | ||
| 89 | } | ||
| 90 | |||
| 91 | pub fn disable(&mut self, channel: Channel) { | ||
| 92 | self.inner.enable_channel(channel, false); | ||
| 93 | } | ||
| 94 | |||
| 95 | pub fn set_freq(&mut self, freq: Hertz) { | ||
| 96 | self.inner.set_frequency(freq); | ||
| 97 | } | ||
| 98 | |||
| 99 | pub fn get_max_duty(&self) -> u16 { | ||
| 100 | self.inner.get_max_compare_value() | ||
| 101 | } | ||
| 102 | |||
| 103 | pub fn set_duty(&mut self, channel: Channel, duty: u16) { | ||
| 104 | assert!(duty < self.get_max_duty()); | ||
| 105 | self.inner.set_compare_value(channel, duty) | ||
| 106 | } | ||
| 107 | } | ||
