aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-stm32/src/timer')
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs33
-rw-r--r--embassy-stm32/src/timer/mod.rs163
-rw-r--r--embassy-stm32/src/timer/qei.rs25
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs47
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
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -11,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 13use crate::time::Hertz;
12use crate::Peripheral; 14use crate::Peripheral;
13 15
14pub struct ComplementaryPwmPin<'d, Perip, Channel> { 16/// Complementary PWM pin wrapper.
17///
18/// This wraps a pin to make it usable with PWM.
19pub 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
19macro_rules! complementary_channel_impl { 24macro_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);
41complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); 47complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
42complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); 48complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
43 49
50/// PWM driver with support for standard and complementary outputs.
44pub struct ComplementaryPwm<'d, T> { 51pub struct ComplementaryPwm<'d, T> {
45 inner: PeripheralRef<'d, T>, 52 inner: PeripheralRef<'d, T>,
46} 53}
47 54
48impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 55impl<'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
1pub mod complementary_pwm; 3pub mod complementary_pwm;
2pub mod qei; 4pub mod qei;
3pub mod simple_pwm; 5pub mod simple_pwm;
@@ -8,23 +10,34 @@ use crate::interrupt;
8use crate::rcc::RccPeripheral; 10use crate::rcc::RccPeripheral;
9use crate::time::Hertz; 11use crate::time::Hertz;
10 12
13/// Low-level timer access.
11#[cfg(feature = "unstable-pac")] 14#[cfg(feature = "unstable-pac")]
12pub mod low_level { 15pub mod low_level {
13 pub use super::sealed::*; 16 pub use super::sealed::*;
14} 17}
15 18
16pub(crate) mod sealed { 19pub(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)]
277pub enum Channel { 346pub 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
284impl Channel { 357impl 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)]
296pub enum InputCaptureMode { 371pub 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)]
303pub enum InputTISelection { 382pub 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)]
321pub enum CountingMode { 404pub enum CountingMode {
@@ -342,6 +425,7 @@ pub enum CountingMode {
342} 425}
343 426
344impl CountingMode { 427impl 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)]
387pub enum OutputCompareMode { 473pub 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
398impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 501impl 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)]
414pub enum OutputPolarity { 518pub 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.
428pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 535pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
429 536
537/// Gneral-purpose 16-bit timer instance.
430pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} 538pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
431 539
540/// Gneral-purpose 32-bit timer instance.
432pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} 541pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
433 542
543/// Advanced control timer instance.
434pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} 544pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
435 545
546/// Capture/Compare 16-bit timer instance.
436pub trait CaptureCompare16bitInstance: 547pub 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.
441pub trait ComplementaryCaptureCompare16bitInstance: 553pub 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.
446pub trait CaptureCompare32bitInstance: 559pub 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
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -7,23 +9,30 @@ use crate::gpio::sealed::AFType;
7use crate::gpio::AnyPin; 9use crate::gpio::AnyPin;
8use crate::Peripheral; 10use crate::Peripheral;
9 11
12/// Counting direction
10pub enum Direction { 13pub enum Direction {
14 /// Counting up.
11 Upcounting, 15 Upcounting,
16 /// Counting down.
12 Downcounting, 17 Downcounting,
13} 18}
14 19
15pub struct Ch1; 20/// Channel 1 marker type.
16pub struct Ch2; 21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
17 24
18pub struct QeiPin<'d, Perip, Channel> { 25/// Wrapper for using a pin with QEI.
26pub 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
23macro_rules! channel_impl { 31macro_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 {
43channel_impl!(new_ch1, Ch1, Channel1Pin); 52channel_impl!(new_ch1, Ch1, Channel1Pin);
44channel_impl!(new_ch2, Ch2, Channel2Pin); 53channel_impl!(new_ch2, Ch2, Channel2Pin);
45 54
55/// Quadrature decoder driver.
46pub struct Qei<'d, T> { 56pub struct Qei<'d, T> {
47 _inner: PeripheralRef<'d, T>, 57 _inner: PeripheralRef<'d, T>,
48} 58}
49 59
50impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { 60impl<'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
1use core::marker::PhantomData; 3use core::marker::PhantomData;
2 4
3use embassy_hal_internal::{into_ref, PeripheralRef}; 5use embassy_hal_internal::{into_ref, PeripheralRef};
@@ -9,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
9use crate::time::Hertz; 11use crate::time::Hertz;
10use crate::Peripheral; 12use crate::Peripheral;
11 13
12pub struct Ch1; 14/// Channel 1 marker type.
13pub struct Ch2; 15pub enum Ch1 {}
14pub struct Ch3; 16/// Channel 2 marker type.
15pub struct Ch4; 17pub enum Ch2 {}
16 18/// Channel 3 marker type.
17pub struct PwmPin<'d, Perip, Channel> { 19pub enum Ch3 {}
20/// Channel 4 marker type.
21pub enum Ch4 {}
22
23/// PWM pin wrapper.
24///
25/// This wraps a pin to make it usable with PWM.
26pub 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
22macro_rules! channel_impl { 31macro_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);
44channel_impl!(new_ch3, Ch3, Channel3Pin); 54channel_impl!(new_ch3, Ch3, Channel3Pin);
45channel_impl!(new_ch4, Ch4, Channel4Pin); 55channel_impl!(new_ch4, Ch4, Channel4Pin);
46 56
57/// Simple PWM driver.
47pub struct SimplePwm<'d, T> { 58pub struct SimplePwm<'d, T> {
48 inner: PeripheralRef<'d, T>, 59 inner: PeripheralRef<'d, T>,
49} 60}
50 61
51impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 62impl<'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 }