aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-12-19 17:35:38 +0100
committerDario Nieuwenhuis <[email protected]>2023-12-19 17:35:38 +0100
commit189b15c426a3a9ef7d4024ba7e5de6a255f88ee7 (patch)
tree50a5c64c14cd2b920bc99ebcbd7fdf276ebe0ae0
parent41c3c26beb5d9ef683073c257c1269307be6ad43 (diff)
stm32/timer: docs.
-rw-r--r--embassy-stm32/src/hrtim/mod.rs16
-rw-r--r--embassy-stm32/src/lib.rs25
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs31
-rw-r--r--embassy-stm32/src/timer/mod.rs158
-rw-r--r--embassy-stm32/src/timer/qei.rs23
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs45
-rw-r--r--examples/stm32f4/src/bin/ws2812_pwm_dma.rs2
-rw-r--r--examples/stm32h7/src/bin/low_level_timer_api.rs10
8 files changed, 248 insertions, 62 deletions
diff --git a/embassy-stm32/src/hrtim/mod.rs b/embassy-stm32/src/hrtim/mod.rs
index 1e6626a58..faefaabbc 100644
--- a/embassy-stm32/src/hrtim/mod.rs
+++ b/embassy-stm32/src/hrtim/mod.rs
@@ -68,22 +68,22 @@ mod sealed {
68pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {} 68pub trait AdvancedChannel<T: Instance>: sealed::AdvancedChannel<T> {}
69 69
70/// HRTIM PWM pin. 70/// HRTIM PWM pin.
71pub struct PwmPin<'d, Perip, Channel> { 71pub struct PwmPin<'d, T, C> {
72 _pin: PeripheralRef<'d, AnyPin>, 72 _pin: PeripheralRef<'d, AnyPin>,
73 phantom: PhantomData<(Perip, Channel)>, 73 phantom: PhantomData<(T, C)>,
74} 74}
75 75
76/// HRTIM complementary PWM pin. 76/// HRTIM complementary PWM pin.
77pub struct ComplementaryPwmPin<'d, Perip, Channel> { 77pub struct ComplementaryPwmPin<'d, T, C> {
78 _pin: PeripheralRef<'d, AnyPin>, 78 _pin: PeripheralRef<'d, AnyPin>,
79 phantom: PhantomData<(Perip, Channel)>, 79 phantom: PhantomData<(T, C)>,
80} 80}
81 81
82macro_rules! advanced_channel_impl { 82macro_rules! advanced_channel_impl {
83 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => { 83 ($new_chx:ident, $channel:tt, $ch_num:expr, $pin_trait:ident, $complementary_pin_trait:ident) => {
84 impl<'d, Perip: Instance> PwmPin<'d, Perip, $channel<Perip>> { 84 impl<'d, T: Instance> PwmPin<'d, T, $channel<T>> {
85 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 85 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")]
86 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<Perip>> + 'd) -> Self { 86 pub fn $new_chx(pin: impl Peripheral<P = impl $pin_trait<T>> + 'd) -> Self {
87 into_ref!(pin); 87 into_ref!(pin);
88 critical_section::with(|_| { 88 critical_section::with(|_| {
89 pin.set_low(); 89 pin.set_low();
@@ -98,9 +98,9 @@ macro_rules! advanced_channel_impl {
98 } 98 }
99 } 99 }
100 100
101 impl<'d, Perip: Instance> ComplementaryPwmPin<'d, Perip, $channel<Perip>> { 101 impl<'d, T: Instance> ComplementaryPwmPin<'d, T, $channel<T>> {
102 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 102 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")]
103 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<Perip>> + 'd) -> Self { 103 pub fn $new_chx(pin: impl Peripheral<P = impl $complementary_pin_trait<T>> + 'd) -> Self {
104 into_ref!(pin); 104 into_ref!(pin);
105 critical_section::with(|_| { 105 critical_section::with(|_| {
106 pin.set_low(); 106 pin.set_low();
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 5d9b4e6a0..4952d26eb 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -79,6 +79,7 @@ pub(crate) mod _generated {
79 #![allow(dead_code)] 79 #![allow(dead_code)]
80 #![allow(unused_imports)] 80 #![allow(unused_imports)]
81 #![allow(non_snake_case)] 81 #![allow(non_snake_case)]
82 #![allow(missing_docs)]
82 83
83 include!(concat!(env!("OUT_DIR"), "/_generated.rs")); 84 include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
84} 85}
@@ -149,15 +150,33 @@ use crate::interrupt::Priority;
149pub use crate::pac::NVIC_PRIO_BITS; 150pub use crate::pac::NVIC_PRIO_BITS;
150use crate::rcc::sealed::RccPeripheral; 151use crate::rcc::sealed::RccPeripheral;
151 152
153/// `embassy-stm32` global configuration.
152#[non_exhaustive] 154#[non_exhaustive]
153pub struct Config { 155pub struct Config {
156 /// RCC config.
154 pub rcc: rcc::Config, 157 pub rcc: rcc::Config,
158
159 /// Enable debug during sleep.
160 ///
161 /// May incrase power consumption. Defaults to true.
155 #[cfg(dbgmcu)] 162 #[cfg(dbgmcu)]
156 pub enable_debug_during_sleep: bool, 163 pub enable_debug_during_sleep: bool,
164
165 /// BDMA interrupt priority.
166 ///
167 /// Defaults to P0 (highest).
157 #[cfg(bdma)] 168 #[cfg(bdma)]
158 pub bdma_interrupt_priority: Priority, 169 pub bdma_interrupt_priority: Priority,
170
171 /// DMA interrupt priority.
172 ///
173 /// Defaults to P0 (highest).
159 #[cfg(dma)] 174 #[cfg(dma)]
160 pub dma_interrupt_priority: Priority, 175 pub dma_interrupt_priority: Priority,
176
177 /// GPDMA interrupt priority.
178 ///
179 /// Defaults to P0 (highest).
161 #[cfg(gpdma)] 180 #[cfg(gpdma)]
162 pub gpdma_interrupt_priority: Priority, 181 pub gpdma_interrupt_priority: Priority,
163} 182}
@@ -178,7 +197,11 @@ impl Default for Config {
178 } 197 }
179} 198}
180 199
181/// Initialize embassy. 200/// Initialize the `embassy-stm32` HAL with the provided configuration.
201///
202/// This returns the peripheral singletons that can be used for creating drivers.
203///
204/// This should only be called once at startup, otherwise it panics.
182pub fn init(config: Config) -> Peripherals { 205pub fn init(config: Config) -> Peripherals {
183 critical_section::with(|cs| { 206 critical_section::with(|cs| {
184 let p = Peripherals::take_with_cs(cs); 207 let p = Peripherals::take_with_cs(cs);
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index e543a5b43..71d7110b5 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -13,15 +13,19 @@ use crate::gpio::{AnyPin, OutputType};
13use crate::time::Hertz; 13use crate::time::Hertz;
14use crate::Peripheral; 14use crate::Peripheral;
15 15
16pub 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> {
17 _pin: PeripheralRef<'d, AnyPin>, 20 _pin: PeripheralRef<'d, AnyPin>,
18 phantom: PhantomData<(Perip, Channel)>, 21 phantom: PhantomData<(T, C)>,
19} 22}
20 23
21macro_rules! complementary_channel_impl { 24macro_rules! complementary_channel_impl {
22 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
23 impl<'d, Perip: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, Perip, $channel> { 26 impl<'d, T: CaptureCompare16bitInstance> ComplementaryPwmPin<'d, T, $channel> {
24 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 {
25 into_ref!(pin); 29 into_ref!(pin);
26 critical_section::with(|_| { 30 critical_section::with(|_| {
27 pin.set_low(); 31 pin.set_low();
@@ -43,11 +47,13 @@ complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
43complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin); 47complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
44complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin); 48complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
45 49
50/// PWM driver with support for standard and complementary outputs.
46pub struct ComplementaryPwm<'d, T> { 51pub struct ComplementaryPwm<'d, T> {
47 inner: PeripheralRef<'d, T>, 52 inner: PeripheralRef<'d, T>,
48} 53}
49 54
50impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> { 55impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver.
51 pub fn new( 57 pub fn new(
52 tim: impl Peripheral<P = T> + 'd, 58 tim: impl Peripheral<P = T> + 'd,
53 _ch1: Option<PwmPin<'d, T, Ch1>>, 59 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -72,7 +78,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
72 let mut this = Self { inner: tim }; 78 let mut this = Self { inner: tim };
73 79
74 this.inner.set_counting_mode(counting_mode); 80 this.inner.set_counting_mode(counting_mode);
75 this.set_freq(freq); 81 this.set_frequency(freq);
76 this.inner.start(); 82 this.inner.start();
77 83
78 this.inner.enable_outputs(); 84 this.inner.enable_outputs();
@@ -88,17 +94,23 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
88 this 94 this
89 } 95 }
90 96
97 /// Enable the given channel.
91 pub fn enable(&mut self, channel: Channel) { 98 pub fn enable(&mut self, channel: Channel) {
92 self.inner.enable_channel(channel, true); 99 self.inner.enable_channel(channel, true);
93 self.inner.enable_complementary_channel(channel, true); 100 self.inner.enable_complementary_channel(channel, true);
94 } 101 }
95 102
103 /// Disable the given channel.
96 pub fn disable(&mut self, channel: Channel) { 104 pub fn disable(&mut self, channel: Channel) {
97 self.inner.enable_complementary_channel(channel, false); 105 self.inner.enable_complementary_channel(channel, false);
98 self.inner.enable_channel(channel, false); 106 self.inner.enable_channel(channel, false);
99 } 107 }
100 108
101 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) {
102 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 114 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
103 2u8 115 2u8
104 } else { 116 } else {
@@ -107,15 +119,22 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
107 self.inner.set_frequency(freq * multiplier); 119 self.inner.set_frequency(freq * multiplier);
108 } 120 }
109 121
122 /// Get max duty value.
123 ///
124 /// This value depends on the configured frequency and the timer's clock rate from RCC.
110 pub fn get_max_duty(&self) -> u16 { 125 pub fn get_max_duty(&self) -> u16 {
111 self.inner.get_max_compare_value() + 1 126 self.inner.get_max_compare_value() + 1
112 } 127 }
113 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.
114 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 132 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
115 assert!(duty <= self.get_max_duty()); 133 assert!(duty <= self.get_max_duty());
116 self.inner.set_compare_value(channel, duty) 134 self.inner.set_compare_value(channel, duty)
117 } 135 }
118 136
137 /// Set the output polarity for a given channel.
119 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 138 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
120 self.inner.set_output_polarity(channel, polarity); 139 self.inner.set_output_polarity(channel, polarity);
121 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 42ef878f7..74120adad 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -17,17 +17,27 @@ pub mod low_level {
17} 17}
18 18
19pub(crate) mod sealed { 19pub(crate) mod sealed {
20
21 use super::*; 20 use super::*;
21
22 /// Basic 16-bit timer instance.
22 pub trait Basic16bitInstance: RccPeripheral { 23 pub trait Basic16bitInstance: RccPeripheral {
24 /// Interrupt for this timer.
23 type Interrupt: interrupt::typelevel::Interrupt; 25 type Interrupt: interrupt::typelevel::Interrupt;
24 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.
25 fn regs() -> crate::pac::timer::TimBasic; 33 fn regs() -> crate::pac::timer::TimBasic;
26 34
35 /// Start the timer.
27 fn start(&mut self) { 36 fn start(&mut self) {
28 Self::regs().cr1().modify(|r| r.set_cen(true)); 37 Self::regs().cr1().modify(|r| r.set_cen(true));
29 } 38 }
30 39
40 /// Stop the timer.
31 fn stop(&mut self) { 41 fn stop(&mut self) {
32 Self::regs().cr1().modify(|r| r.set_cen(false)); 42 Self::regs().cr1().modify(|r| r.set_cen(false));
33 } 43 }
@@ -63,6 +73,9 @@ pub(crate) mod sealed {
63 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 73 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
64 } 74 }
65 75
76 /// Clear update interrupt.
77 ///
78 /// Returns whether the update interrupt flag was set.
66 fn clear_update_interrupt(&mut self) -> bool { 79 fn clear_update_interrupt(&mut self) -> bool {
67 let regs = Self::regs(); 80 let regs = Self::regs();
68 let sr = regs.sr().read(); 81 let sr = regs.sr().read();
@@ -76,14 +89,17 @@ pub(crate) mod sealed {
76 } 89 }
77 } 90 }
78 91
92 /// Enable/disable the update interrupt.
79 fn enable_update_interrupt(&mut self, enable: bool) { 93 fn enable_update_interrupt(&mut self, enable: bool) {
80 Self::regs().dier().write(|r| r.set_uie(enable)); 94 Self::regs().dier().write(|r| r.set_uie(enable));
81 } 95 }
82 96
97 /// Enable/disable autoreload preload.
83 fn set_autoreload_preload(&mut self, enable: bool) { 98 fn set_autoreload_preload(&mut self, enable: bool) {
84 Self::regs().cr1().modify(|r| r.set_arpe(enable)); 99 Self::regs().cr1().modify(|r| r.set_arpe(enable));
85 } 100 }
86 101
102 /// Get the timer frequency.
87 fn get_frequency(&self) -> Hertz { 103 fn get_frequency(&self) -> Hertz {
88 let timer_f = Self::frequency(); 104 let timer_f = Self::frequency();
89 105
@@ -95,9 +111,17 @@ pub(crate) mod sealed {
95 } 111 }
96 } 112 }
97 113
114 /// Gneral-purpose 16-bit timer instance.
98 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.
99 fn regs_gp16() -> crate::pac::timer::TimGp16; 122 fn regs_gp16() -> crate::pac::timer::TimGp16;
100 123
124 /// Set counting mode.
101 fn set_counting_mode(&mut self, mode: CountingMode) { 125 fn set_counting_mode(&mut self, mode: CountingMode) {
102 let (cms, dir) = mode.into(); 126 let (cms, dir) = mode.into();
103 127
@@ -110,19 +134,29 @@ pub(crate) mod sealed {
110 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms)) 134 Self::regs_gp16().cr1().modify(|r| r.set_cms(cms))
111 } 135 }
112 136
137 /// Get counting mode.
113 fn get_counting_mode(&self) -> CountingMode { 138 fn get_counting_mode(&self) -> CountingMode {
114 let cr1 = Self::regs_gp16().cr1().read(); 139 let cr1 = Self::regs_gp16().cr1().read();
115 (cr1.cms(), cr1.dir()).into() 140 (cr1.cms(), cr1.dir()).into()
116 } 141 }
117 142
143 /// Set clock divider.
118 fn set_clock_division(&mut self, ckd: vals::Ckd) { 144 fn set_clock_division(&mut self, ckd: vals::Ckd) {
119 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd)); 145 Self::regs_gp16().cr1().modify(|r| r.set_ckd(ckd));
120 } 146 }
121 } 147 }
122 148
149 /// Gneral-purpose 32-bit timer instance.
123 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.
124 fn regs_gp32() -> crate::pac::timer::TimGp32; 157 fn regs_gp32() -> crate::pac::timer::TimGp32;
125 158
159 /// Set timer frequency.
126 fn set_frequency(&mut self, frequency: Hertz) { 160 fn set_frequency(&mut self, frequency: Hertz) {
127 let f = frequency.0; 161 let f = frequency.0;
128 assert!(f > 0); 162 assert!(f > 0);
@@ -140,6 +174,7 @@ pub(crate) mod sealed {
140 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT)); 174 regs.cr1().modify(|r| r.set_urs(vals::Urs::ANYEVENT));
141 } 175 }
142 176
177 /// Get timer frequency.
143 fn get_frequency(&self) -> Hertz { 178 fn get_frequency(&self) -> Hertz {
144 let timer_f = Self::frequency(); 179 let timer_f = Self::frequency();
145 180
@@ -151,141 +186,177 @@ pub(crate) mod sealed {
151 } 186 }
152 } 187 }
153 188
189 /// Advanced control timer instance.
154 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance { 190 pub trait AdvancedControlInstance: GeneralPurpose16bitInstance {
191 /// Get access to the advanced timer registers.
155 fn regs_advanced() -> crate::pac::timer::TimAdv; 192 fn regs_advanced() -> crate::pac::timer::TimAdv;
156 } 193 }
157 194
195 /// Capture/Compare 16-bit timer instance.
158 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance { 196 pub trait CaptureCompare16bitInstance: GeneralPurpose16bitInstance {
197 /// Set input capture filter.
159 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) {
160 let raw_channel = channel.raw(); 199 let raw_channel = channel.index();
161 Self::regs_gp16() 200 Self::regs_gp16()
162 .ccmr_input(raw_channel / 2) 201 .ccmr_input(raw_channel / 2)
163 .modify(|r| r.set_icf(raw_channel % 2, icf)); 202 .modify(|r| r.set_icf(raw_channel % 2, icf));
164 } 203 }
165 204
205 /// Clear input interrupt.
166 fn clear_input_interrupt(&mut self, channel: Channel) { 206 fn clear_input_interrupt(&mut self, channel: Channel) {
167 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));
168 } 208 }
169 209
210 /// Enable input interrupt.
170 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) { 211 fn enable_input_interrupt(&mut self, channel: Channel, enable: bool) {
171 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));
172 } 213 }
214
215 /// Set input capture prescaler.
173 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) { 216 fn set_input_capture_prescaler(&mut self, channel: Channel, factor: u8) {
174 let raw_channel = channel.raw(); 217 let raw_channel = channel.index();
175 Self::regs_gp16() 218 Self::regs_gp16()
176 .ccmr_input(raw_channel / 2) 219 .ccmr_input(raw_channel / 2)
177 .modify(|r| r.set_icpsc(raw_channel % 2, factor)); 220 .modify(|r| r.set_icpsc(raw_channel % 2, factor));
178 } 221 }
179 222
223 /// Set input TI selection.
180 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) { 224 fn set_input_ti_selection(&mut self, channel: Channel, tisel: InputTISelection) {
181 let raw_channel = channel.raw(); 225 let raw_channel = channel.index();
182 Self::regs_gp16() 226 Self::regs_gp16()
183 .ccmr_input(raw_channel / 2) 227 .ccmr_input(raw_channel / 2)
184 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into())); 228 .modify(|r| r.set_ccs(raw_channel % 2, tisel.into()));
185 } 229 }
230
231 /// Set input capture mode.
186 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) { 232 fn set_input_capture_mode(&mut self, channel: Channel, mode: InputCaptureMode) {
187 Self::regs_gp16().ccer().modify(|r| match mode { 233 Self::regs_gp16().ccer().modify(|r| match mode {
188 InputCaptureMode::Rising => { 234 InputCaptureMode::Rising => {
189 r.set_ccnp(channel.raw(), false); 235 r.set_ccnp(channel.index(), false);
190 r.set_ccp(channel.raw(), false); 236 r.set_ccp(channel.index(), false);
191 } 237 }
192 InputCaptureMode::Falling => { 238 InputCaptureMode::Falling => {
193 r.set_ccnp(channel.raw(), false); 239 r.set_ccnp(channel.index(), false);
194 r.set_ccp(channel.raw(), true); 240 r.set_ccp(channel.index(), true);
195 } 241 }
196 InputCaptureMode::BothEdges => { 242 InputCaptureMode::BothEdges => {
197 r.set_ccnp(channel.raw(), true); 243 r.set_ccnp(channel.index(), true);
198 r.set_ccp(channel.raw(), true); 244 r.set_ccp(channel.index(), true);
199 } 245 }
200 }); 246 });
201 } 247 }
248
249 /// Enable timer outputs.
202 fn enable_outputs(&mut self); 250 fn enable_outputs(&mut self);
203 251
252 /// Set output compare mode.
204 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) { 253 fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode) {
205 let r = Self::regs_gp16(); 254 let r = Self::regs_gp16();
206 let raw_channel: usize = channel.raw(); 255 let raw_channel: usize = channel.index();
207 r.ccmr_output(raw_channel / 2) 256 r.ccmr_output(raw_channel / 2)
208 .modify(|w| w.set_ocm(raw_channel % 2, mode.into())); 257 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
209 } 258 }
210 259
260 /// Set output polarity.
211 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 261 fn set_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
212 Self::regs_gp16() 262 Self::regs_gp16()
213 .ccer() 263 .ccer()
214 .modify(|w| w.set_ccp(channel.raw(), polarity.into())); 264 .modify(|w| w.set_ccp(channel.index(), polarity.into()));
215 } 265 }
216 266
267 /// Enable/disable a channel.
217 fn enable_channel(&mut self, channel: Channel, enable: bool) { 268 fn enable_channel(&mut self, channel: Channel, enable: bool) {
218 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));
219 } 270 }
220 271
272 /// Set compare value for a channel.
221 fn set_compare_value(&mut self, channel: Channel, value: u16) { 273 fn set_compare_value(&mut self, channel: Channel, value: u16) {
222 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));
223 } 275 }
224 276
277 /// Get capture value for a channel.
225 fn get_capture_value(&mut self, channel: Channel) -> u16 { 278 fn get_capture_value(&mut self, channel: Channel) -> u16 {
226 Self::regs_gp16().ccr(channel.raw()).read().ccr() 279 Self::regs_gp16().ccr(channel.index()).read().ccr()
227 } 280 }
228 281
282 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
229 fn get_max_compare_value(&self) -> u16 { 283 fn get_max_compare_value(&self) -> u16 {
230 Self::regs_gp16().arr().read().arr() 284 Self::regs_gp16().arr().read().arr()
231 } 285 }
232 286
287 /// Get compare value for a channel.
233 fn get_compare_value(&self, channel: Channel) -> u16 { 288 fn get_compare_value(&self, channel: Channel) -> u16 {
234 Self::regs_gp16().ccr(channel.raw()).read().ccr() 289 Self::regs_gp16().ccr(channel.index()).read().ccr()
235 } 290 }
236 } 291 }
237 292
293 /// Capture/Compare 16-bit timer instance with complementary pin support.
238 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance { 294 pub trait ComplementaryCaptureCompare16bitInstance: CaptureCompare16bitInstance + AdvancedControlInstance {
295 /// Set complementary output polarity.
239 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 296 fn set_complementary_output_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
240 Self::regs_advanced() 297 Self::regs_advanced()
241 .ccer() 298 .ccer()
242 .modify(|w| w.set_ccnp(channel.raw(), polarity.into())); 299 .modify(|w| w.set_ccnp(channel.index(), polarity.into()));
243 } 300 }
244 301
302 /// Set clock divider for the dead time.
245 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) { 303 fn set_dead_time_clock_division(&mut self, value: vals::Ckd) {
246 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value)); 304 Self::regs_advanced().cr1().modify(|w| w.set_ckd(value));
247 } 305 }
248 306
307 /// Set dead time, as a fraction of the max duty value.
249 fn set_dead_time_value(&mut self, value: u8) { 308 fn set_dead_time_value(&mut self, value: u8) {
250 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value)); 309 Self::regs_advanced().bdtr().modify(|w| w.set_dtg(value));
251 } 310 }
252 311
312 /// Enable/disable a complementary channel.
253 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) { 313 fn enable_complementary_channel(&mut self, channel: Channel, enable: bool) {
254 Self::regs_advanced() 314 Self::regs_advanced()
255 .ccer() 315 .ccer()
256 .modify(|w| w.set_ccne(channel.raw(), enable)); 316 .modify(|w| w.set_ccne(channel.index(), enable));
257 } 317 }
258 } 318 }
259 319
320 /// Capture/Compare 32-bit timer instance.
260 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance { 321 pub trait CaptureCompare32bitInstance: GeneralPurpose32bitInstance + CaptureCompare16bitInstance {
322 /// Set comapre value for a channel.
261 fn set_compare_value(&mut self, channel: Channel, value: u32) { 323 fn set_compare_value(&mut self, channel: Channel, value: u32) {
262 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));
263 } 325 }
264 326
327 /// Get capture value for a channel.
265 fn get_capture_value(&mut self, channel: Channel) -> u32 { 328 fn get_capture_value(&mut self, channel: Channel) -> u32 {
266 Self::regs_gp32().ccr(channel.raw()).read().ccr() 329 Self::regs_gp32().ccr(channel.index()).read().ccr()
267 } 330 }
268 331
332 /// Get max compare value. This depends on the timer frequency and the clock frequency from RCC.
269 fn get_max_compare_value(&self) -> u32 { 333 fn get_max_compare_value(&self) -> u32 {
270 Self::regs_gp32().arr().read().arr() 334 Self::regs_gp32().arr().read().arr()
271 } 335 }
272 336
337 /// Get compare value for a channel.
273 fn get_compare_value(&self, channel: Channel) -> u32 { 338 fn get_compare_value(&self, channel: Channel) -> u32 {
274 Self::regs_gp32().ccr(channel.raw()).read().ccr() 339 Self::regs_gp32().ccr(channel.index()).read().ccr()
275 } 340 }
276 } 341 }
277} 342}
278 343
344/// Timer channel.
279#[derive(Clone, Copy)] 345#[derive(Clone, Copy)]
280pub enum Channel { 346pub enum Channel {
347 /// Channel 1.
281 Ch1, 348 Ch1,
349 /// Channel 2.
282 Ch2, 350 Ch2,
351 /// Channel 3.
283 Ch3, 352 Ch3,
353 /// Channel 4.
284 Ch4, 354 Ch4,
285} 355}
286 356
287impl Channel { 357impl Channel {
288 pub fn raw(&self) -> usize { 358 /// Get the channel index (0..3)
359 pub fn index(&self) -> usize {
289 match self { 360 match self {
290 Channel::Ch1 => 0, 361 Channel::Ch1 => 0,
291 Channel::Ch2 => 1, 362 Channel::Ch2 => 1,
@@ -295,17 +366,25 @@ impl Channel {
295 } 366 }
296} 367}
297 368
369/// Input capture mode.
298#[derive(Clone, Copy)] 370#[derive(Clone, Copy)]
299pub enum InputCaptureMode { 371pub enum InputCaptureMode {
372 /// Rising edge only.
300 Rising, 373 Rising,
374 /// Falling edge only.
301 Falling, 375 Falling,
376 /// Both rising or falling edges.
302 BothEdges, 377 BothEdges,
303} 378}
304 379
380/// Input TI selection.
305#[derive(Clone, Copy)] 381#[derive(Clone, Copy)]
306pub enum InputTISelection { 382pub enum InputTISelection {
383 /// Normal
307 Normal, 384 Normal,
385 /// Alternate
308 Alternate, 386 Alternate,
387 /// TRC
309 TRC, 388 TRC,
310} 389}
311 390
@@ -319,6 +398,7 @@ impl From<InputTISelection> for stm32_metapac::timer::vals::CcmrInputCcs {
319 } 398 }
320} 399}
321 400
401/// Timer counting mode.
322#[repr(u8)] 402#[repr(u8)]
323#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 403#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
324pub enum CountingMode { 404pub enum CountingMode {
@@ -345,6 +425,7 @@ pub enum CountingMode {
345} 425}
346 426
347impl CountingMode { 427impl CountingMode {
428 /// Return whether this mode is edge-aligned (up or down).
348 pub fn is_edge_aligned(&self) -> bool { 429 pub fn is_edge_aligned(&self) -> bool {
349 match self { 430 match self {
350 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true, 431 CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
@@ -352,6 +433,7 @@ impl CountingMode {
352 } 433 }
353 } 434 }
354 435
436 /// Return whether this mode is center-aligned.
355 pub fn is_center_aligned(&self) -> bool { 437 pub fn is_center_aligned(&self) -> bool {
356 match self { 438 match self {
357 CountingMode::CenterAlignedDownInterrupts 439 CountingMode::CenterAlignedDownInterrupts
@@ -386,16 +468,34 @@ impl From<(vals::Cms, vals::Dir)> for CountingMode {
386 } 468 }
387} 469}
388 470
471/// Output compare mode.
389#[derive(Clone, Copy)] 472#[derive(Clone, Copy)]
390pub 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).
391 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).
392 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).
393 InactiveOnMatch, 483 InactiveOnMatch,
484 /// Toggle - OCxREF toggles when TIMx_CNT=TIMx_CCRx.
394 Toggle, 485 Toggle,
486 /// Force inactive level - OCxREF is forced low.
395 ForceInactive, 487 ForceInactive,
488 /// Force active level - OCxREF is forced high.
396 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).
397 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.
398 PwmMode2, 497 PwmMode2,
498 // TODO: there's more modes here depending on the chip family.
399} 499}
400 500
401impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm { 501impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
@@ -413,9 +513,12 @@ impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
413 } 513 }
414} 514}
415 515
516/// Timer output pin polarity.
416#[derive(Clone, Copy)] 517#[derive(Clone, Copy)]
417pub enum OutputPolarity { 518pub enum OutputPolarity {
519 /// Active high (higher duty value makes the pin spend more time high).
418 ActiveHigh, 520 ActiveHigh,
521 /// Active low (higher duty value makes the pin spend more time low).
419 ActiveLow, 522 ActiveLow,
420} 523}
421 524
@@ -428,24 +531,31 @@ impl From<OutputPolarity> for bool {
428 } 531 }
429} 532}
430 533
534/// Basic 16-bit timer instance.
431pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {} 535pub trait Basic16bitInstance: sealed::Basic16bitInstance + 'static {}
432 536
537/// Gneral-purpose 16-bit timer instance.
433pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {} 538pub trait GeneralPurpose16bitInstance: sealed::GeneralPurpose16bitInstance + 'static {}
434 539
540/// Gneral-purpose 32-bit timer instance.
435pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {} 541pub trait GeneralPurpose32bitInstance: sealed::GeneralPurpose32bitInstance + 'static {}
436 542
543/// Advanced control timer instance.
437pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {} 544pub trait AdvancedControlInstance: sealed::AdvancedControlInstance + 'static {}
438 545
546/// Capture/Compare 16-bit timer instance.
439pub trait CaptureCompare16bitInstance: 547pub trait CaptureCompare16bitInstance:
440 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static 548 sealed::CaptureCompare16bitInstance + GeneralPurpose16bitInstance + 'static
441{ 549{
442} 550}
443 551
552/// Capture/Compare 16-bit timer instance with complementary pin support.
444pub trait ComplementaryCaptureCompare16bitInstance: 553pub trait ComplementaryCaptureCompare16bitInstance:
445 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static 554 sealed::ComplementaryCaptureCompare16bitInstance + AdvancedControlInstance + 'static
446{ 555{
447} 556}
448 557
558/// Capture/Compare 32-bit timer instance.
449pub trait CaptureCompare32bitInstance: 559pub trait CaptureCompare32bitInstance:
450 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static 560 sealed::CaptureCompare32bitInstance + CaptureCompare16bitInstance + GeneralPurpose32bitInstance + 'static
451{ 561{
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index 9f9379c20..59efb72ba 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -9,23 +9,30 @@ use crate::gpio::sealed::AFType;
9use crate::gpio::AnyPin; 9use crate::gpio::AnyPin;
10use crate::Peripheral; 10use crate::Peripheral;
11 11
12/// Counting direction
12pub enum Direction { 13pub enum Direction {
14 /// Counting up.
13 Upcounting, 15 Upcounting,
16 /// Counting down.
14 Downcounting, 17 Downcounting,
15} 18}
16 19
17pub struct Ch1; 20/// Channel 1 marker type.
18pub struct Ch2; 21pub enum Ch1 {}
22/// Channel 2 marker type.
23pub enum Ch2 {}
19 24
20pub struct QeiPin<'d, Perip, Channel> { 25/// Wrapper for using a pin with QEI.
26pub struct QeiPin<'d, T, Channel> {
21 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
22 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, Channel)>,
23} 29}
24 30
25macro_rules! channel_impl { 31macro_rules! channel_impl {
26 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
27 impl<'d, Perip: CaptureCompare16bitInstance> QeiPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> QeiPin<'d, T, $channel> {
28 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 {
29 into_ref!(pin); 36 into_ref!(pin);
30 critical_section::with(|_| { 37 critical_section::with(|_| {
31 pin.set_low(); 38 pin.set_low();
@@ -45,11 +52,13 @@ macro_rules! channel_impl {
45channel_impl!(new_ch1, Ch1, Channel1Pin); 52channel_impl!(new_ch1, Ch1, Channel1Pin);
46channel_impl!(new_ch2, Ch2, Channel2Pin); 53channel_impl!(new_ch2, Ch2, Channel2Pin);
47 54
55/// Quadrature decoder driver.
48pub struct Qei<'d, T> { 56pub struct Qei<'d, T> {
49 _inner: PeripheralRef<'d, T>, 57 _inner: PeripheralRef<'d, T>,
50} 58}
51 59
52impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> { 60impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
61 /// Create a new quadrature decoder driver.
53 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 {
54 Self::new_inner(tim) 63 Self::new_inner(tim)
55 } 64 }
@@ -84,6 +93,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
84 Self { _inner: tim } 93 Self { _inner: tim }
85 } 94 }
86 95
96 /// Get direction.
87 pub fn read_direction(&self) -> Direction { 97 pub fn read_direction(&self) -> Direction {
88 match T::regs_gp16().cr1().read().dir() { 98 match T::regs_gp16().cr1().read().dir() {
89 vals::Dir::DOWN => Direction::Downcounting, 99 vals::Dir::DOWN => Direction::Downcounting,
@@ -91,6 +101,7 @@ impl<'d, T: CaptureCompare16bitInstance> Qei<'d, T> {
91 } 101 }
92 } 102 }
93 103
104 /// Get count.
94 pub fn count(&self) -> u16 { 105 pub fn count(&self) -> u16 {
95 T::regs_gp16().cnt().read().cnt() 106 T::regs_gp16().cnt().read().cnt()
96 } 107 }
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index 234bbaff0..e6072aa15 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -11,20 +11,28 @@ use crate::gpio::{AnyPin, OutputType};
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::Peripheral; 12use crate::Peripheral;
13 13
14pub struct Ch1; 14/// Channel 1 marker type.
15pub struct Ch2; 15pub enum Ch1 {}
16pub struct Ch3; 16/// Channel 2 marker type.
17pub struct Ch4; 17pub enum Ch2 {}
18 18/// Channel 3 marker type.
19pub 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> {
20 _pin: PeripheralRef<'d, AnyPin>, 27 _pin: PeripheralRef<'d, AnyPin>,
21 phantom: PhantomData<(Perip, Channel)>, 28 phantom: PhantomData<(T, C)>,
22} 29}
23 30
24macro_rules! channel_impl { 31macro_rules! channel_impl {
25 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 32 ($new_chx:ident, $channel:ident, $pin_trait:ident) => {
26 impl<'d, Perip: CaptureCompare16bitInstance> PwmPin<'d, Perip, $channel> { 33 impl<'d, T: CaptureCompare16bitInstance> PwmPin<'d, T, $channel> {
27 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 {
28 into_ref!(pin); 36 into_ref!(pin);
29 critical_section::with(|_| { 37 critical_section::with(|_| {
30 pin.set_low(); 38 pin.set_low();
@@ -46,11 +54,13 @@ channel_impl!(new_ch2, Ch2, Channel2Pin);
46channel_impl!(new_ch3, Ch3, Channel3Pin); 54channel_impl!(new_ch3, Ch3, Channel3Pin);
47channel_impl!(new_ch4, Ch4, Channel4Pin); 55channel_impl!(new_ch4, Ch4, Channel4Pin);
48 56
57/// Simple PWM driver.
49pub struct SimplePwm<'d, T> { 58pub struct SimplePwm<'d, T> {
50 inner: PeripheralRef<'d, T>, 59 inner: PeripheralRef<'d, T>,
51} 60}
52 61
53impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> { 62impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
63 /// Create a new simple PWM driver.
54 pub fn new( 64 pub fn new(
55 tim: impl Peripheral<P = T> + 'd, 65 tim: impl Peripheral<P = T> + 'd,
56 _ch1: Option<PwmPin<'d, T, Ch1>>, 66 _ch1: Option<PwmPin<'d, T, Ch1>>,
@@ -71,7 +81,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
71 let mut this = Self { inner: tim }; 81 let mut this = Self { inner: tim };
72 82
73 this.inner.set_counting_mode(counting_mode); 83 this.inner.set_counting_mode(counting_mode);
74 this.set_freq(freq); 84 this.set_frequency(freq);
75 this.inner.start(); 85 this.inner.start();
76 86
77 this.inner.enable_outputs(); 87 this.inner.enable_outputs();
@@ -87,15 +97,21 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
87 this 97 this
88 } 98 }
89 99
100 /// Enable the given channel.
90 pub fn enable(&mut self, channel: Channel) { 101 pub fn enable(&mut self, channel: Channel) {
91 self.inner.enable_channel(channel, true); 102 self.inner.enable_channel(channel, true);
92 } 103 }
93 104
105 /// Disable the given channel.
94 pub fn disable(&mut self, channel: Channel) { 106 pub fn disable(&mut self, channel: Channel) {
95 self.inner.enable_channel(channel, false); 107 self.inner.enable_channel(channel, false);
96 } 108 }
97 109
98 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) {
99 let multiplier = if self.inner.get_counting_mode().is_center_aligned() { 115 let multiplier = if self.inner.get_counting_mode().is_center_aligned() {
100 2u8 116 2u8
101 } else { 117 } else {
@@ -104,15 +120,22 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
104 self.inner.set_frequency(freq * multiplier); 120 self.inner.set_frequency(freq * multiplier);
105 } 121 }
106 122
123 /// Get max duty value.
124 ///
125 /// This value depends on the configured frequency and the timer's clock rate from RCC.
107 pub fn get_max_duty(&self) -> u16 { 126 pub fn get_max_duty(&self) -> u16 {
108 self.inner.get_max_compare_value() + 1 127 self.inner.get_max_compare_value() + 1
109 } 128 }
110 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.
111 pub fn set_duty(&mut self, channel: Channel, duty: u16) { 133 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
112 assert!(duty <= self.get_max_duty()); 134 assert!(duty <= self.get_max_duty());
113 self.inner.set_compare_value(channel, duty) 135 self.inner.set_compare_value(channel, duty)
114 } 136 }
115 137
138 /// Set the output polarity for a given channel.
116 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) { 139 pub fn set_polarity(&mut self, channel: Channel, polarity: OutputPolarity) {
117 self.inner.set_output_polarity(channel, polarity); 140 self.inner.set_output_polarity(channel, polarity);
118 } 141 }
diff --git a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
index 52cc665c7..39f5d3421 100644
--- a/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
+++ b/examples/stm32f4/src/bin/ws2812_pwm_dma.rs
@@ -110,7 +110,7 @@ async fn main(_spawner: Spawner) {
110 &mut dp.DMA1_CH2, 110 &mut dp.DMA1_CH2,
111 5, 111 5,
112 color_list[color_list_index], 112 color_list[color_list_index],
113 pac::TIM3.ccr(pwm_channel.raw()).as_ptr() as *mut _, 113 pac::TIM3.ccr(pwm_channel.index()).as_ptr() as *mut _,
114 dma_transfer_option, 114 dma_transfer_option,
115 ) 115 )
116 .await; 116 .await;
diff --git a/examples/stm32h7/src/bin/low_level_timer_api.rs b/examples/stm32h7/src/bin/low_level_timer_api.rs
index e0be495d1..394ed3281 100644
--- a/examples/stm32h7/src/bin/low_level_timer_api.rs
+++ b/examples/stm32h7/src/bin/low_level_timer_api.rs
@@ -85,7 +85,7 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
85 85
86 let mut this = Self { inner: tim }; 86 let mut this = Self { inner: tim };
87 87
88 this.set_freq(freq); 88 this.set_frequency(freq);
89 this.inner.start(); 89 this.inner.start();
90 90
91 let r = T::regs_gp32(); 91 let r = T::regs_gp32();
@@ -102,14 +102,14 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
102 } 102 }
103 103
104 pub fn enable(&mut self, channel: Channel) { 104 pub fn enable(&mut self, channel: Channel) {
105 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), true)); 105 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), true));
106 } 106 }
107 107
108 pub fn disable(&mut self, channel: Channel) { 108 pub fn disable(&mut self, channel: Channel) {
109 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), false)); 109 T::regs_gp32().ccer().modify(|w| w.set_cce(channel.index(), false));
110 } 110 }
111 111
112 pub fn set_freq(&mut self, freq: Hertz) { 112 pub fn set_frequency(&mut self, freq: Hertz) {
113 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq); 113 <T as embassy_stm32::timer::low_level::GeneralPurpose32bitInstance>::set_frequency(&mut self.inner, freq);
114 } 114 }
115 115
@@ -119,6 +119,6 @@ impl<'d, T: CaptureCompare32bitInstance> SimplePwm32<'d, T> {
119 119
120 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 120 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
121 defmt::assert!(duty < self.get_max_duty()); 121 defmt::assert!(duty < self.get_max_duty());
122 T::regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(duty)) 122 T::regs_gp32().ccr(channel.index()).modify(|w| w.set_ccr(duty))
123 } 123 }
124} 124}