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.rs58
-rw-r--r--embassy-stm32/src/timer/input_capture.rs32
-rw-r--r--embassy-stm32/src/timer/mod.rs99
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs102
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs11
-rw-r--r--embassy-stm32/src/timer/qei.rs42
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs241
7 files changed, 334 insertions, 251 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 8eec6c0c7..b00cc18ad 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -5,14 +5,12 @@ use core::marker::PhantomData;
5use stm32_metapac::timer::vals::Ckd; 5use stm32_metapac::timer::vals::Ckd;
6 6
7use super::low_level::{CountingMode, OutputPolarity, Timer}; 7use super::low_level::{CountingMode, OutputPolarity, Timer};
8use super::simple_pwm::{Ch1, Ch2, Ch3, Ch4, PwmPin}; 8use super::simple_pwm::PwmPin;
9use super::{ 9use super::{AdvancedInstance4Channel, Ch1, Ch2, Ch3, Ch4, Channel, TimerComplementaryPin};
10 AdvancedInstance4Channel, Channel, Channel1ComplementaryPin, Channel2ComplementaryPin, Channel3ComplementaryPin,
11 Channel4ComplementaryPin,
12};
13use crate::gpio::{AnyPin, OutputType}; 10use crate::gpio::{AnyPin, OutputType};
14use crate::time::Hertz; 11use crate::time::Hertz;
15use crate::timer::low_level::OutputCompareMode; 12use crate::timer::low_level::OutputCompareMode;
13use crate::timer::TimerChannel;
16use crate::Peri; 14use crate::Peri;
17 15
18/// Complementary PWM pin wrapper. 16/// Complementary PWM pin wrapper.
@@ -23,32 +21,23 @@ pub struct ComplementaryPwmPin<'d, T, C> {
23 phantom: PhantomData<(T, C)>, 21 phantom: PhantomData<(T, C)>,
24} 22}
25 23
26macro_rules! complementary_channel_impl { 24impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T, C> {
27 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 25 /// Create a new complementary PWM pin instance.
28 impl<'d, T: AdvancedInstance4Channel> ComplementaryPwmPin<'d, T, $channel> { 26 pub fn new(pin: Peri<'d, impl TimerComplementaryPin<T, C>>, output_type: OutputType) -> Self {
29 #[doc = concat!("Create a new ", stringify!($channel), " complementary PWM pin instance.")] 27 critical_section::with(|_| {
30 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, output_type: OutputType) -> Self { 28 pin.set_low();
31 critical_section::with(|_| { 29 pin.set_as_af(
32 pin.set_low(); 30 pin.af_num(),
33 pin.set_as_af( 31 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh),
34 pin.af_num(), 32 );
35 crate::gpio::AfType::output(output_type, crate::gpio::Speed::VeryHigh), 33 });
36 ); 34 ComplementaryPwmPin {
37 }); 35 _pin: pin.into(),
38 ComplementaryPwmPin { 36 phantom: PhantomData,
39 _pin: pin.into(),
40 phantom: PhantomData,
41 }
42 }
43 } 37 }
44 }; 38 }
45} 39}
46 40
47complementary_channel_impl!(new_ch1, Ch1, Channel1ComplementaryPin);
48complementary_channel_impl!(new_ch2, Ch2, Channel2ComplementaryPin);
49complementary_channel_impl!(new_ch3, Ch3, Channel3ComplementaryPin);
50complementary_channel_impl!(new_ch4, Ch4, Channel4ComplementaryPin);
51
52/// PWM driver with support for standard and complementary outputs. 41/// PWM driver with support for standard and complementary outputs.
53pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> { 42pub struct ComplementaryPwm<'d, T: AdvancedInstance4Channel> {
54 inner: Timer<'d, T>, 43 inner: Timer<'d, T>,
@@ -88,6 +77,7 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
88 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1); 77 this.inner.set_output_compare_mode(channel, OutputCompareMode::PwmMode1);
89 this.inner.set_output_compare_preload(channel, true); 78 this.inner.set_output_compare_preload(channel, true);
90 }); 79 });
80 this.inner.set_autoreload_preload(true);
91 81
92 this 82 this
93 } 83 }
@@ -121,7 +111,11 @@ impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
121 /// 111 ///
122 /// This value depends on the configured frequency and the timer's clock rate from RCC. 112 /// This value depends on the configured frequency and the timer's clock rate from RCC.
123 pub fn get_max_duty(&self) -> u16 { 113 pub fn get_max_duty(&self) -> u16 {
124 self.inner.get_max_compare_value() as u16 + 1 114 if self.inner.get_counting_mode().is_center_aligned() {
115 self.inner.get_max_compare_value() as u16
116 } else {
117 self.inner.get_max_compare_value() as u16 + 1
118 }
125 } 119 }
126 120
127 /// Set the duty for a given channel. 121 /// Set the duty for a given channel.
@@ -171,7 +165,11 @@ impl<'d, T: AdvancedInstance4Channel> embedded_hal_02::Pwm for ComplementaryPwm<
171 } 165 }
172 166
173 fn get_max_duty(&self) -> Self::Duty { 167 fn get_max_duty(&self) -> Self::Duty {
174 self.inner.get_max_compare_value() as u16 + 1 168 if self.inner.get_counting_mode().is_center_aligned() {
169 self.inner.get_max_compare_value() as u16
170 } else {
171 self.inner.get_max_compare_value() as u16 + 1
172 }
175 } 173 }
176 174
177 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { 175 fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index ec8b1ddf1..dda33e7f1 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -6,14 +6,12 @@ use core::pin::Pin;
6use core::task::{Context, Poll}; 6use core::task::{Context, Poll};
7 7
8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer}; 8use super::low_level::{CountingMode, FilterValue, InputCaptureMode, InputTISelection, Timer};
9use super::{ 9use super::{CaptureCompareInterruptHandler, Channel, GeneralInstance4Channel, TimerPin};
10 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin,
11 GeneralInstance4Channel,
12};
13pub use super::{Ch1, Ch2, Ch3, Ch4}; 10pub use super::{Ch1, Ch2, Ch3, Ch4};
14use crate::gpio::{AfType, AnyPin, Pull}; 11use crate::gpio::{AfType, AnyPin, Pull};
15use crate::interrupt::typelevel::{Binding, Interrupt}; 12use crate::interrupt::typelevel::{Binding, Interrupt};
16use crate::time::Hertz; 13use crate::time::Hertz;
14use crate::timer::TimerChannel;
17use crate::Peri; 15use crate::Peri;
18 16
19/// Capture pin wrapper. 17/// Capture pin wrapper.
@@ -23,27 +21,17 @@ pub struct CapturePin<'d, T, C> {
23 _pin: Peri<'d, AnyPin>, 21 _pin: Peri<'d, AnyPin>,
24 phantom: PhantomData<(T, C)>, 22 phantom: PhantomData<(T, C)>,
25} 23}
26 24impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> {
27macro_rules! channel_impl { 25 /// Create a new capture pin instance.
28 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 26 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self {
29 impl<'d, T: GeneralInstance4Channel> CapturePin<'d, T, $channel> { 27 pin.set_as_af(pin.af_num(), AfType::input(pull));
30 #[doc = concat!("Create a new ", stringify!($channel), " capture pin instance.")] 28 CapturePin {
31 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, pull: Pull) -> Self { 29 _pin: pin.into(),
32 pin.set_as_af(pin.af_num(), AfType::input(pull)); 30 phantom: PhantomData,
33 CapturePin {
34 _pin: pin.into(),
35 phantom: PhantomData,
36 }
37 }
38 } 31 }
39 }; 32 }
40} 33}
41 34
42channel_impl!(new_ch1, Ch1, Channel1Pin);
43channel_impl!(new_ch2, Ch2, Channel2Pin);
44channel_impl!(new_ch3, Ch3, Channel3Pin);
45channel_impl!(new_ch4, Ch4, Channel4Pin);
46
47/// Input capture driver. 35/// Input capture driver.
48pub struct InputCapture<'d, T: GeneralInstance4Channel> { 36pub struct InputCapture<'d, T: GeneralInstance4Channel> {
49 inner: Timer<'d, T>, 37 inner: Timer<'d, T>,
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index b29382fc8..7062f5f4c 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -51,6 +51,80 @@ pub enum Ch3 {}
51/// Channel 4 marker type. 51/// Channel 4 marker type.
52pub enum Ch4 {} 52pub enum Ch4 {}
53 53
54/// Timer channel trait.
55#[allow(private_bounds)]
56pub trait TimerChannel: SealedTimerChannel {
57 /// The runtime channel.
58 const CHANNEL: Channel;
59}
60
61trait SealedTimerChannel {}
62
63impl TimerChannel for Ch1 {
64 const CHANNEL: Channel = Channel::Ch1;
65}
66
67impl TimerChannel for Ch2 {
68 const CHANNEL: Channel = Channel::Ch2;
69}
70
71impl TimerChannel for Ch3 {
72 const CHANNEL: Channel = Channel::Ch3;
73}
74
75impl TimerChannel for Ch4 {
76 const CHANNEL: Channel = Channel::Ch4;
77}
78
79impl SealedTimerChannel for Ch1 {}
80impl SealedTimerChannel for Ch2 {}
81impl SealedTimerChannel for Ch3 {}
82impl SealedTimerChannel for Ch4 {}
83
84/// Timer break input.
85#[derive(Clone, Copy)]
86pub enum BkIn {
87 /// Break input 1.
88 BkIn1,
89 /// Break input 2.
90 BkIn2,
91}
92
93impl BkIn {
94 /// Get the channel index (0..3)
95 pub fn index(&self) -> usize {
96 match self {
97 BkIn::BkIn1 => 0,
98 BkIn::BkIn2 => 1,
99 }
100 }
101}
102
103/// Break input 1 marker type.
104pub enum BkIn1 {}
105/// Break input 2 marker type.
106pub enum BkIn2 {}
107
108/// Timer channel trait.
109#[allow(private_bounds)]
110pub trait BreakInput: SealedBreakInput {
111 /// The runtim timer channel.
112 const INPUT: BkIn;
113}
114
115trait SealedBreakInput {}
116
117impl BreakInput for BkIn1 {
118 const INPUT: BkIn = BkIn::BkIn1;
119}
120
121impl BreakInput for BkIn2 {
122 const INPUT: BkIn = BkIn::BkIn2;
123}
124
125impl SealedBreakInput for BkIn1 {}
126impl SealedBreakInput for BkIn2 {}
127
54/// Amount of bits of a timer. 128/// Amount of bits of a timer.
55#[derive(Clone, Copy, PartialEq, Eq, Debug)] 129#[derive(Clone, Copy, PartialEq, Eq, Debug)]
56#[cfg_attr(feature = "defmt", derive(defmt::Format))] 130#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -149,33 +223,20 @@ pub trait AdvancedInstance2Channel: BasicInstance + GeneralInstance2Channel + Ad
149/// Advanced 16-bit timer with 4 channels instance. 223/// Advanced 16-bit timer with 4 channels instance.
150pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {} 224pub trait AdvancedInstance4Channel: AdvancedInstance2Channel + GeneralInstance4Channel {}
151 225
152pin_trait!(Channel1Pin, GeneralInstance4Channel); 226pin_trait!(TimerPin, GeneralInstance4Channel, TimerChannel);
153pin_trait!(Channel2Pin, GeneralInstance4Channel);
154pin_trait!(Channel3Pin, GeneralInstance4Channel);
155pin_trait!(Channel4Pin, GeneralInstance4Channel);
156pin_trait!(ExternalTriggerPin, GeneralInstance4Channel); 227pin_trait!(ExternalTriggerPin, GeneralInstance4Channel);
157 228
158pin_trait!(Channel1ComplementaryPin, AdvancedInstance4Channel); 229pin_trait!(TimerComplementaryPin, AdvancedInstance4Channel, TimerChannel);
159pin_trait!(Channel2ComplementaryPin, AdvancedInstance4Channel);
160pin_trait!(Channel3ComplementaryPin, AdvancedInstance4Channel);
161pin_trait!(Channel4ComplementaryPin, AdvancedInstance4Channel);
162
163pin_trait!(BreakInputPin, AdvancedInstance4Channel);
164pin_trait!(BreakInput2Pin, AdvancedInstance4Channel);
165 230
166pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel); 231pin_trait!(BreakInputPin, AdvancedInstance4Channel, BreakInput);
167pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel);
168 232
169pin_trait!(BreakInput2Comparator1Pin, AdvancedInstance4Channel); 233pin_trait!(BreakInputComparator1Pin, AdvancedInstance4Channel, BreakInput);
170pin_trait!(BreakInput2Comparator2Pin, AdvancedInstance4Channel); 234pin_trait!(BreakInputComparator2Pin, AdvancedInstance4Channel, BreakInput);
171 235
172// Update Event trigger DMA for every timer 236// Update Event trigger DMA for every timer
173dma_trait!(UpDma, BasicInstance); 237dma_trait!(UpDma, BasicInstance);
174 238
175dma_trait!(Ch1Dma, GeneralInstance4Channel); 239dma_trait!(Dma, GeneralInstance4Channel, TimerChannel);
176dma_trait!(Ch2Dma, GeneralInstance4Channel);
177dma_trait!(Ch3Dma, GeneralInstance4Channel);
178dma_trait!(Ch4Dma, GeneralInstance4Channel);
179 240
180#[allow(unused)] 241#[allow(unused)]
181macro_rules! impl_core_timer { 242macro_rules! impl_core_timer {
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
index 933165ef9..498d9c082 100644
--- a/embassy-stm32/src/timer/one_pulse.rs
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -7,11 +7,9 @@ use core::pin::Pin;
7use core::task::{Context, Poll}; 7use core::task::{Context, Poll};
8 8
9use super::low_level::{ 9use super::low_level::{
10 CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource, 10 CountingMode, FilterValue, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource as Ts,
11};
12use super::{
13 CaptureCompareInterruptHandler, Channel, Channel1Pin, Channel2Pin, ExternalTriggerPin, GeneralInstance4Channel,
14}; 11};
12use super::{CaptureCompareInterruptHandler, Channel, ExternalTriggerPin, GeneralInstance4Channel, TimerPin};
15pub use super::{Ch1, Ch2}; 13pub use super::{Ch1, Ch2};
16use crate::gpio::{AfType, AnyPin, Pull}; 14use crate::gpio::{AfType, AnyPin, Pull};
17use crate::interrupt::typelevel::{Binding, Interrupt}; 15use crate::interrupt::typelevel::{Binding, Interrupt};
@@ -48,24 +46,78 @@ pub struct TriggerPin<'d, T, C> {
48 phantom: PhantomData<(T, C)>, 46 phantom: PhantomData<(T, C)>,
49} 47}
50 48
51macro_rules! channel_impl { 49trait SealedTriggerSource {}
52 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 50
53 impl<'d, T: GeneralInstance4Channel> TriggerPin<'d, T, $channel> { 51/// Marker trait for a trigger source.
54 #[doc = concat!("Create a new ", stringify!($channel), " trigger pin instance.")] 52#[expect(private_bounds)]
55 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, pull: Pull) -> Self { 53pub trait TriggerSource: SealedTriggerSource {}
56 pin.set_as_af(pin.af_num(), AfType::input(pull)); 54
57 TriggerPin { 55impl TriggerSource for Ch1 {}
58 _pin: pin.into(), 56impl TriggerSource for Ch2 {}
59 phantom: PhantomData, 57impl TriggerSource for Ext {}
60 } 58
61 } 59impl SealedTriggerSource for Ch1 {}
62 } 60impl SealedTriggerSource for Ch2 {}
63 }; 61impl SealedTriggerSource for Ext {}
62
63trait SealedTimerTriggerPin<T, S>: crate::gpio::Pin {}
64
65/// Marker trait for a trigger pin.
66#[expect(private_bounds)]
67// TODO: find better naming scheme than prefixing all pin traits with "Timer".
68// The trait name cannot conflict with the corresponding type's name.
69// Applies to other timer submodules as well.
70pub trait TimerTriggerPin<T, S>: SealedTimerTriggerPin<T, S> {
71 /// Get the AF number needed to use this pin as a trigger source.
72 fn af_num(&self) -> u8;
73}
74
75impl<T, P, C> TimerTriggerPin<T, C> for P
76where
77 T: GeneralInstance4Channel,
78 P: TimerPin<T, C>,
79 C: super::TimerChannel + TriggerSource,
80{
81 fn af_num(&self) -> u8 {
82 TimerPin::af_num(self)
83 }
84}
85
86impl<T, P> TimerTriggerPin<T, Ext> for P
87where
88 T: GeneralInstance4Channel,
89 P: ExternalTriggerPin<T>,
90{
91 fn af_num(&self) -> u8 {
92 ExternalTriggerPin::af_num(self)
93 }
94}
95
96impl<T, P, C> SealedTimerTriggerPin<T, C> for P
97where
98 T: GeneralInstance4Channel,
99 P: TimerPin<T, C>,
100 C: super::TimerChannel + TriggerSource,
101{
64} 102}
65 103
66channel_impl!(new_ch1, Ch1, Channel1Pin); 104impl<T, P> SealedTimerTriggerPin<T, Ext> for P
67channel_impl!(new_ch2, Ch2, Channel2Pin); 105where
68channel_impl!(new_ext, Ext, ExternalTriggerPin); 106 T: GeneralInstance4Channel,
107 P: ExternalTriggerPin<T>,
108{
109}
110
111impl<'d, T: GeneralInstance4Channel, C: TriggerSource> TriggerPin<'d, T, C> {
112 /// "Create a new Ch1 trigger pin instance.
113 pub fn new(pin: Peri<'d, impl TimerTriggerPin<T, C>>, pull: Pull) -> Self {
114 pin.set_as_af(pin.af_num(), AfType::input(pull));
115 TriggerPin {
116 _pin: pin.into(),
117 phantom: PhantomData,
118 }
119 }
120}
69 121
70/// One pulse driver. 122/// One pulse driver.
71/// 123///
@@ -89,7 +141,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
89 ) -> Self { 141 ) -> Self {
90 let mut this = Self { inner: Timer::new(tim) }; 142 let mut this = Self { inner: Timer::new(tim) };
91 143
92 this.inner.set_trigger_source(TriggerSource::TI1F_ED); 144 this.inner.set_trigger_source(Ts::TI1F_ED);
93 this.inner 145 this.inner
94 .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); 146 .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
95 this.inner 147 this.inner
@@ -114,7 +166,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
114 ) -> Self { 166 ) -> Self {
115 let mut this = Self { inner: Timer::new(tim) }; 167 let mut this = Self { inner: Timer::new(tim) };
116 168
117 this.inner.set_trigger_source(TriggerSource::TI1FP1); 169 this.inner.set_trigger_source(Ts::TI1FP1);
118 this.inner 170 this.inner
119 .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal); 171 .set_input_ti_selection(Channel::Ch1, InputTISelection::Normal);
120 this.inner 172 this.inner
@@ -131,7 +183,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
131 /// as an output. 183 /// as an output.
132 pub fn new_ch2( 184 pub fn new_ch2(
133 tim: Peri<'d, T>, 185 tim: Peri<'d, T>,
134 _pin: TriggerPin<'d, T, Ch1>, 186 _pin: TriggerPin<'d, T, Ch2>,
135 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, 187 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
136 freq: Hertz, 188 freq: Hertz,
137 pulse_end: u32, 189 pulse_end: u32,
@@ -140,7 +192,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
140 ) -> Self { 192 ) -> Self {
141 let mut this = Self { inner: Timer::new(tim) }; 193 let mut this = Self { inner: Timer::new(tim) };
142 194
143 this.inner.set_trigger_source(TriggerSource::TI2FP2); 195 this.inner.set_trigger_source(Ts::TI2FP2);
144 this.inner 196 this.inner
145 .set_input_ti_selection(Channel::Ch2, InputTISelection::Normal); 197 .set_input_ti_selection(Channel::Ch2, InputTISelection::Normal);
146 this.inner 198 this.inner
@@ -172,7 +224,7 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
172 // No filtering 224 // No filtering
173 r.set_etf(FilterValue::NO_FILTER); 225 r.set_etf(FilterValue::NO_FILTER);
174 }); 226 });
175 this.inner.set_trigger_source(TriggerSource::ETRF); 227 this.inner.set_trigger_source(Ts::ETRF);
176 this.new_inner(freq, pulse_end, counting_mode); 228 this.new_inner(freq, pulse_end, counting_mode);
177 229
178 this 230 this
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index 98b798634..1e55f2919 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -1,12 +1,16 @@
1//! PWM Input driver. 1//! PWM Input driver.
2 2
3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource}; 3use super::low_level::{CountingMode, InputCaptureMode, InputTISelection, SlaveMode, Timer, TriggerSource};
4use super::{Channel, Channel1Pin, Channel2Pin, GeneralInstance4Channel}; 4use super::{Ch1, Ch2, Channel, GeneralInstance4Channel, TimerPin};
5use crate::gpio::{AfType, Pull}; 5use crate::gpio::{AfType, Pull};
6use crate::time::Hertz; 6use crate::time::Hertz;
7use crate::Peri; 7use crate::Peri;
8 8
9/// PWM Input driver. 9/// PWM Input driver.
10///
11/// Only works with CH1 or CH2
12/// Note: Not all timer peripherals are supported
13/// Double check your chips reference manual
10pub struct PwmInput<'d, T: GeneralInstance4Channel> { 14pub struct PwmInput<'d, T: GeneralInstance4Channel> {
11 channel: Channel, 15 channel: Channel,
12 inner: Timer<'d, T>, 16 inner: Timer<'d, T>,
@@ -14,14 +18,14 @@ pub struct PwmInput<'d, T: GeneralInstance4Channel> {
14 18
15impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> { 19impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
16 /// Create a new PWM input driver. 20 /// Create a new PWM input driver.
17 pub fn new(tim: Peri<'d, T>, pin: Peri<'d, impl Channel1Pin<T>>, pull: Pull, freq: Hertz) -> Self { 21 pub fn new_ch1(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch1>>, pull: Pull, freq: Hertz) -> Self {
18 pin.set_as_af(pin.af_num(), AfType::input(pull)); 22 pin.set_as_af(pin.af_num(), AfType::input(pull));
19 23
20 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) 24 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
21 } 25 }
22 26
23 /// Create a new PWM input driver. 27 /// Create a new PWM input driver.
24 pub fn new_alt(tim: Peri<'d, T>, pin: Peri<'d, impl Channel2Pin<T>>, pull: Pull, freq: Hertz) -> Self { 28 pub fn new_ch2(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2>>, pull: Pull, freq: Hertz) -> Self {
25 pin.set_as_af(pin.af_num(), AfType::input(pull)); 29 pin.set_as_af(pin.af_num(), AfType::input(pull));
26 30
27 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) 31 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
@@ -37,6 +41,7 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
37 41
38 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6 42 // Configuration steps from ST RM0390 (STM32F446) chapter 17.3.6
39 // or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode 43 // or ST RM0008 (STM32F103) chapter 15.3.6 Input capture mode
44 // or ST RM0440 (STM32G4) chapter 30.4.8 PWM input mode
40 inner.set_input_ti_selection(ch1, InputTISelection::Normal); 45 inner.set_input_ti_selection(ch1, InputTISelection::Normal);
41 inner.set_input_capture_mode(ch1, InputCaptureMode::Rising); 46 inner.set_input_capture_mode(ch1, InputCaptureMode::Rising);
42 47
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index f3c81667c..eabe1b22a 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -6,8 +6,9 @@ use stm32_metapac::timer::vals;
6 6
7use super::low_level::Timer; 7use super::low_level::Timer;
8pub use super::{Ch1, Ch2}; 8pub use super::{Ch1, Ch2};
9use super::{Channel1Pin, Channel2Pin, GeneralInstance4Channel}; 9use super::{GeneralInstance4Channel, TimerPin};
10use crate::gpio::{AfType, AnyPin, Pull}; 10use crate::gpio::{AfType, AnyPin, Pull};
11use crate::timer::TimerChannel;
11use crate::Peri; 12use crate::Peri;
12 13
13/// Counting direction 14/// Counting direction
@@ -24,26 +25,31 @@ pub struct QeiPin<'d, T, Channel> {
24 phantom: PhantomData<(T, Channel)>, 25 phantom: PhantomData<(T, Channel)>,
25} 26}
26 27
27macro_rules! channel_impl { 28impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> {
28 ($new_chx:ident, $channel:ident, $pin_trait:ident) => { 29 /// Create a new QEI pin instance.
29 impl<'d, T: GeneralInstance4Channel> QeiPin<'d, T, $channel> { 30 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>) -> Self {
30 #[doc = concat!("Create a new ", stringify!($channel), " QEI pin instance.")] 31 critical_section::with(|_| {
31 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>) -> Self { 32 pin.set_low();
32 critical_section::with(|_| { 33 pin.set_as_af(pin.af_num(), AfType::input(Pull::None));
33 pin.set_low(); 34 });
34 pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); 35 QeiPin {
35 }); 36 _pin: pin.into(),
36 QeiPin { 37 phantom: PhantomData,
37 _pin: pin.into(),
38 phantom: PhantomData,
39 }
40 }
41 } 38 }
42 }; 39 }
43} 40}
44 41
45channel_impl!(new_ch1, Ch1, Channel1Pin); 42trait SealedQeiChannel: TimerChannel {}
46channel_impl!(new_ch2, Ch2, Channel2Pin); 43
44/// Marker trait for a timer channel eligible for use with QEI.
45#[expect(private_bounds)]
46pub trait QeiChannel: SealedQeiChannel {}
47
48impl QeiChannel for Ch1 {}
49impl QeiChannel for Ch2 {}
50
51impl SealedQeiChannel for Ch1 {}
52impl SealedQeiChannel for Ch2 {}
47 53
48/// Quadrature decoder driver. 54/// Quadrature decoder driver.
49pub struct Qei<'d, T: GeneralInstance4Channel> { 55pub struct Qei<'d, T: GeneralInstance4Channel> {
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index f7f433154..c04b1ab97 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -4,22 +4,13 @@ use core::marker::PhantomData;
4use core::mem::ManuallyDrop; 4use core::mem::ManuallyDrop;
5 5
6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer}; 6use super::low_level::{CountingMode, OutputCompareMode, OutputPolarity, Timer};
7use super::{Channel, Channel1Pin, Channel2Pin, Channel3Pin, Channel4Pin, GeneralInstance4Channel, TimerBits}; 7use super::{Ch1, Ch2, Ch3, Ch4, Channel, GeneralInstance4Channel, TimerBits, TimerChannel, TimerPin};
8#[cfg(gpio_v2)] 8#[cfg(gpio_v2)]
9use crate::gpio::Pull; 9use crate::gpio::Pull;
10use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 10use crate::gpio::{AfType, AnyPin, OutputType, Speed};
11use crate::time::Hertz; 11use crate::time::Hertz;
12use crate::Peri; 12use crate::Peri;
13 13
14/// Channel 1 marker type.
15pub enum Ch1 {}
16/// Channel 2 marker type.
17pub enum Ch2 {}
18/// Channel 3 marker type.
19pub enum Ch3 {}
20/// Channel 4 marker type.
21pub enum Ch4 {}
22
23/// PWM pin wrapper. 14/// PWM pin wrapper.
24/// 15///
25/// This wraps a pin to make it usable with PWM. 16/// This wraps a pin to make it usable with PWM.
@@ -43,46 +34,37 @@ pub struct PwmPinConfig {
43 pub pull: Pull, 34 pub pull: Pull,
44} 35}
45 36
46macro_rules! channel_impl { 37impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> {
47 ($new_chx:ident, $new_chx_with_config:ident, $channel:ident, $pin_trait:ident) => { 38 /// Create a new PWM pin instance.
48 impl<'d, T: GeneralInstance4Channel> PwmPin<'d, T, $channel> { 39 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, output_type: OutputType) -> Self {
49 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance.")] 40 critical_section::with(|_| {
50 pub fn $new_chx(pin: Peri<'d, impl $pin_trait<T>>, output_type: OutputType) -> Self { 41 pin.set_low();
51 critical_section::with(|_| { 42 pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh));
52 pin.set_low(); 43 });
53 pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); 44 PwmPin {
54 }); 45 _pin: pin.into(),
55 PwmPin { 46 phantom: PhantomData,
56 _pin: pin.into(),
57 phantom: PhantomData,
58 }
59 }
60
61 #[doc = concat!("Create a new ", stringify!($channel), " PWM pin instance with config.")]
62 pub fn $new_chx_with_config(pin: Peri<'d, impl $pin_trait<T>>, pin_config: PwmPinConfig) -> Self {
63 critical_section::with(|_| {
64 pin.set_low();
65 pin.set_as_af(
66 pin.af_num(),
67 #[cfg(gpio_v1)]
68 AfType::output(pin_config.output_type, pin_config.speed),
69 #[cfg(gpio_v2)]
70 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
71 );
72 });
73 PwmPin {
74 _pin: pin.into(),
75 phantom: PhantomData,
76 }
77 }
78 } 47 }
79 }; 48 }
80}
81 49
82channel_impl!(new_ch1, new_ch1_with_config, Ch1, Channel1Pin); 50 /// Create a new PWM pin instance with config.
83channel_impl!(new_ch2, new_ch2_with_config, Ch2, Channel2Pin); 51 pub fn new_with_config(pin: Peri<'d, impl TimerPin<T, C>>, pin_config: PwmPinConfig) -> Self {
84channel_impl!(new_ch3, new_ch3_with_config, Ch3, Channel3Pin); 52 critical_section::with(|_| {
85channel_impl!(new_ch4, new_ch4_with_config, Ch4, Channel4Pin); 53 pin.set_low();
54 pin.set_as_af(
55 pin.af_num(),
56 #[cfg(gpio_v1)]
57 AfType::output(pin_config.output_type, pin_config.speed),
58 #[cfg(gpio_v2)]
59 AfType::output_pull(pin_config.output_type, pin_config.speed, pin_config.pull),
60 );
61 });
62 PwmPin {
63 _pin: pin.into(),
64 phantom: PhantomData,
65 }
66 }
67}
86 68
87/// A single channel of a pwm, obtained from [`SimplePwm::split`], 69/// A single channel of a pwm, obtained from [`SimplePwm::split`],
88/// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc. 70/// [`SimplePwm::channel`], [`SimplePwm::ch1`], etc.
@@ -466,107 +448,98 @@ impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
466 } 448 }
467} 449}
468 450
469macro_rules! impl_waveform_chx { 451impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
470 ($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => { 452 /// Generate a sequence of PWM waveform
471 impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { 453 pub async fn waveform<C: TimerChannel>(&mut self, dma: Peri<'_, impl super::Dma<T, C>>, duty: &[u16]) {
472 /// Generate a sequence of PWM waveform 454 use crate::pac::timer::vals::Ccds;
473 pub async fn $fn_name(&mut self, dma: Peri<'_, impl super::$dma_ch<T>>, duty: &[u16]) { 455
474 use crate::pac::timer::vals::Ccds; 456 #[allow(clippy::let_unit_value)] // eg. stm32f334
457 let req = dma.request();
475 458
476 #[allow(clippy::let_unit_value)] // eg. stm32f334 459 let cc_channel = C::CHANNEL;
477 let req = dma.request();
478 460
479 let cc_channel = Channel::$cc_ch; 461 let original_duty_state = self.channel(cc_channel).current_duty_cycle();
462 let original_enable_state = self.channel(cc_channel).is_enabled();
463 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE;
464 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
480 465
481 let original_duty_state = self.channel(cc_channel).current_duty_cycle(); 466 // redirect CC DMA request onto Update Event
482 let original_enable_state = self.channel(cc_channel).is_enabled(); 467 if !original_cc_dma_on_update {
483 let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ON_UPDATE; 468 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE)
484 let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel); 469 }
485 470
486 // redirect CC DMA request onto Update Event 471 if !original_cc_dma_enabled {
487 if !original_cc_dma_on_update { 472 self.inner.set_cc_dma_enable_state(cc_channel, true);
488 self.inner.set_cc_dma_selection(Ccds::ON_UPDATE) 473 }
489 }
490 474
491 if !original_cc_dma_enabled { 475 if !original_enable_state {
492 self.inner.set_cc_dma_enable_state(cc_channel, true); 476 self.channel(cc_channel).enable();
493 } 477 }
494 478
495 if !original_enable_state { 479 unsafe {
496 self.channel(cc_channel).enable(); 480 #[cfg(not(any(bdma, gpdma)))]
497 } 481 use crate::dma::{Burst, FifoThreshold};
482 use crate::dma::{Transfer, TransferOptions};
498 483
499 unsafe { 484 let dma_transfer_option = TransferOptions {
485 #[cfg(not(any(bdma, gpdma)))]
486 fifo_threshold: Some(FifoThreshold::Full),
487 #[cfg(not(any(bdma, gpdma)))]
488 mburst: Burst::Incr8,
489 ..Default::default()
490 };
491
492 match self.inner.bits() {
493 TimerBits::Bits16 => {
494 Transfer::new_write(
495 dma,
496 req,
497 duty,
498 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
499 dma_transfer_option,
500 )
501 .await
502 }
503 #[cfg(not(any(stm32l0)))]
504 TimerBits::Bits32 => {
500 #[cfg(not(any(bdma, gpdma)))] 505 #[cfg(not(any(bdma, gpdma)))]
501 use crate::dma::{Burst, FifoThreshold}; 506 panic!("unsupported timer bits");
502 use crate::dma::{Transfer, TransferOptions}; 507
503 508 #[cfg(any(bdma, gpdma))]
504 let dma_transfer_option = TransferOptions { 509 Transfer::new_write(
505 #[cfg(not(any(bdma, gpdma)))] 510 dma,
506 fifo_threshold: Some(FifoThreshold::Full), 511 req,
507 #[cfg(not(any(bdma, gpdma)))] 512 duty,
508 mburst: Burst::Incr8, 513 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
509 ..Default::default() 514 dma_transfer_option,
510 }; 515 )
511 516 .await
512 match self.inner.bits() {
513 TimerBits::Bits16 => {
514 Transfer::new_write(
515 dma,
516 req,
517 duty,
518 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u16,
519 dma_transfer_option,
520 )
521 .await
522 }
523 #[cfg(not(any(stm32l0)))]
524 TimerBits::Bits32 => {
525 #[cfg(not(any(bdma, gpdma)))]
526 panic!("unsupported timer bits");
527
528 #[cfg(any(bdma, gpdma))]
529 Transfer::new_write(
530 dma,
531 req,
532 duty,
533 self.inner.regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut u32,
534 dma_transfer_option,
535 )
536 .await
537 }
538 };
539 };
540
541 // restore output compare state
542 if !original_enable_state {
543 self.channel(cc_channel).disable();
544 } 517 }
518 };
519 };
520
521 // restore output compare state
522 if !original_enable_state {
523 self.channel(cc_channel).disable();
524 }
545 525
546 self.channel(cc_channel).set_duty_cycle(original_duty_state); 526 self.channel(cc_channel).set_duty_cycle(original_duty_state);
547 527
548 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off, 528 // Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
549 // this can almost always trigger a DMA FIFO error. 529 // this can almost always trigger a DMA FIFO error.
550 // 530 //
551 // optional TODO: 531 // optional TODO:
552 // clean FEIF after disable UDE 532 // clean FEIF after disable UDE
553 if !original_cc_dma_enabled { 533 if !original_cc_dma_enabled {
554 self.inner.set_cc_dma_enable_state(cc_channel, false); 534 self.inner.set_cc_dma_enable_state(cc_channel, false);
555 } 535 }
556 536
557 if !original_cc_dma_on_update { 537 if !original_cc_dma_on_update {
558 self.inner.set_cc_dma_selection(Ccds::ON_COMPARE) 538 self.inner.set_cc_dma_selection(Ccds::ON_COMPARE)
559 }
560 }
561 } 539 }
562 }; 540 }
563} 541}
564 542
565impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1);
566impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
567impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
568impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
569
570impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> { 543impl<'d, T: GeneralInstance4Channel> embedded_hal_1::pwm::ErrorType for SimplePwmChannel<'d, T> {
571 type Error = core::convert::Infallible; 544 type Error = core::convert::Infallible;
572} 545}