aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/timer
diff options
context:
space:
mode:
authorFabian Wolter <[email protected]>2025-07-21 07:57:49 +0200
committerDario Nieuwenhuis <[email protected]>2025-09-05 21:15:46 +0200
commita6562c4f033432e40970aafe82f33c5138adf84e (patch)
treeb0f9e6e624af1708ffe1b865a3db205979fe5200 /embassy-stm32/src/timer
parent0407f7ebe8fabeb81b8a77811ec5dda0fee0b44b (diff)
Add STM32F1 AFIO remap
Diffstat (limited to 'embassy-stm32/src/timer')
-rw-r--r--embassy-stm32/src/timer/complementary_pwm.rs34
-rw-r--r--embassy-stm32/src/timer/input_capture.rs21
-rw-r--r--embassy-stm32/src/timer/mod.rs31
-rw-r--r--embassy-stm32/src/timer/one_pulse.rs10
-rw-r--r--embassy-stm32/src/timer/pwm_input.rs4
-rw-r--r--embassy-stm32/src/timer/qei.rs12
-rw-r--r--embassy-stm32/src/timer/simple_pwm.rs23
7 files changed, 103 insertions, 32 deletions
diff --git a/embassy-stm32/src/timer/complementary_pwm.rs b/embassy-stm32/src/timer/complementary_pwm.rs
index 68cdec302..08404cdd6 100644
--- a/embassy-stm32/src/timer/complementary_pwm.rs
+++ b/embassy-stm32/src/timer/complementary_pwm.rs
@@ -17,7 +17,8 @@ use crate::Peri;
17/// 17///
18/// This wraps a pin to make it usable with PWM. 18/// This wraps a pin to make it usable with PWM.
19pub struct ComplementaryPwmPin<'d, T, C> { 19pub struct ComplementaryPwmPin<'d, T, C> {
20 _pin: Peri<'d, AnyPin>, 20 #[allow(unused)]
21 pin: Peri<'d, AnyPin>,
21 phantom: PhantomData<(T, C)>, 22 phantom: PhantomData<(T, C)>,
22} 23}
23 24
@@ -32,7 +33,7 @@ impl<'d, T: AdvancedInstance4Channel, C: TimerChannel> ComplementaryPwmPin<'d, T
32 ); 33 );
33 }); 34 });
34 ComplementaryPwmPin { 35 ComplementaryPwmPin {
35 _pin: pin.into(), 36 pin: pin.into(),
36 phantom: PhantomData, 37 phantom: PhantomData,
37 } 38 }
38 } 39 }
@@ -54,20 +55,31 @@ pub enum IdlePolarity {
54 55
55impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> { 56impl<'d, T: AdvancedInstance4Channel> ComplementaryPwm<'d, T> {
56 /// Create a new complementary PWM driver. 57 /// Create a new complementary PWM driver.
57 #[allow(clippy::too_many_arguments)] 58 #[allow(clippy::too_many_arguments, unused)]
58 pub fn new( 59 pub fn new(
59 tim: Peri<'d, T>, 60 tim: Peri<'d, T>,
60 _ch1: Option<PwmPin<'d, T, Ch1>>, 61 ch1: Option<PwmPin<'d, T, Ch1>>,
61 _ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>, 62 ch1n: Option<ComplementaryPwmPin<'d, T, Ch1>>,
62 _ch2: Option<PwmPin<'d, T, Ch2>>, 63 ch2: Option<PwmPin<'d, T, Ch2>>,
63 _ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>, 64 ch2n: Option<ComplementaryPwmPin<'d, T, Ch2>>,
64 _ch3: Option<PwmPin<'d, T, Ch3>>, 65 ch3: Option<PwmPin<'d, T, Ch3>>,
65 _ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>, 66 ch3n: Option<ComplementaryPwmPin<'d, T, Ch3>>,
66 _ch4: Option<PwmPin<'d, T, Ch4>>, 67 ch4: Option<PwmPin<'d, T, Ch4>>,
67 _ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>, 68 ch4n: Option<ComplementaryPwmPin<'d, T, Ch4>>,
68 freq: Hertz, 69 freq: Hertz,
69 counting_mode: CountingMode, 70 counting_mode: CountingMode,
70 ) -> Self { 71 ) -> Self {
72 #[cfg(afio)]
73 super::set_afio::<T>(&[
74 ch1.map(|p| p.pin),
75 ch1n.map(|p| p.pin),
76 ch2.map(|p| p.pin),
77 ch2n.map(|p| p.pin),
78 ch3.map(|p| p.pin),
79 ch3n.map(|p| p.pin),
80 ch4.map(|p| p.pin),
81 ch4n.map(|p| p.pin),
82 ]);
71 Self::new_inner(tim, freq, counting_mode) 83 Self::new_inner(tim, freq, counting_mode)
72 } 84 }
73 85
diff --git a/embassy-stm32/src/timer/input_capture.rs b/embassy-stm32/src/timer/input_capture.rs
index dda33e7f1..b717e6eac 100644
--- a/embassy-stm32/src/timer/input_capture.rs
+++ b/embassy-stm32/src/timer/input_capture.rs
@@ -18,7 +18,8 @@ use crate::Peri;
18/// 18///
19/// This wraps a pin to make it usable with capture. 19/// This wraps a pin to make it usable with capture.
20pub struct CapturePin<'d, T, C> { 20pub struct CapturePin<'d, T, C> {
21 _pin: Peri<'d, AnyPin>, 21 #[allow(unused)]
22 pin: Peri<'d, AnyPin>,
22 phantom: PhantomData<(T, C)>, 23 phantom: PhantomData<(T, C)>,
23} 24}
24impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> { 25impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> {
@@ -26,7 +27,7 @@ impl<'d, T: GeneralInstance4Channel, C: TimerChannel> CapturePin<'d, T, C> {
26 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self { 27 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>, pull: Pull) -> Self {
27 pin.set_as_af(pin.af_num(), AfType::input(pull)); 28 pin.set_as_af(pin.af_num(), AfType::input(pull));
28 CapturePin { 29 CapturePin {
29 _pin: pin.into(), 30 pin: pin.into(),
30 phantom: PhantomData, 31 phantom: PhantomData,
31 } 32 }
32 } 33 }
@@ -39,16 +40,24 @@ pub struct InputCapture<'d, T: GeneralInstance4Channel> {
39 40
40impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> { 41impl<'d, T: GeneralInstance4Channel> InputCapture<'d, T> {
41 /// Create a new input capture driver. 42 /// Create a new input capture driver.
43 #[allow(unused)]
42 pub fn new( 44 pub fn new(
43 tim: Peri<'d, T>, 45 tim: Peri<'d, T>,
44 _ch1: Option<CapturePin<'d, T, Ch1>>, 46 ch1: Option<CapturePin<'d, T, Ch1>>,
45 _ch2: Option<CapturePin<'d, T, Ch2>>, 47 ch2: Option<CapturePin<'d, T, Ch2>>,
46 _ch3: Option<CapturePin<'d, T, Ch3>>, 48 ch3: Option<CapturePin<'d, T, Ch3>>,
47 _ch4: Option<CapturePin<'d, T, Ch4>>, 49 ch4: Option<CapturePin<'d, T, Ch4>>,
48 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, 50 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
49 freq: Hertz, 51 freq: Hertz,
50 counting_mode: CountingMode, 52 counting_mode: CountingMode,
51 ) -> Self { 53 ) -> Self {
54 #[cfg(afio)]
55 super::set_afio::<T>(&[
56 ch1.map(|p| p.pin),
57 ch2.map(|p| p.pin),
58 ch3.map(|p| p.pin),
59 ch4.map(|p| p.pin),
60 ]);
52 Self::new_inner(tim, freq, counting_mode) 61 Self::new_inner(tim, freq, counting_mode)
53 } 62 }
54 63
diff --git a/embassy-stm32/src/timer/mod.rs b/embassy-stm32/src/timer/mod.rs
index 7062f5f4c..38f4a1a51 100644
--- a/embassy-stm32/src/timer/mod.rs
+++ b/embassy-stm32/src/timer/mod.rs
@@ -14,6 +14,8 @@ pub mod pwm_input;
14pub mod qei; 14pub mod qei;
15pub mod simple_pwm; 15pub mod simple_pwm;
16 16
17#[cfg(afio)]
18use crate::gpio::SealedPin;
17use crate::interrupt; 19use crate::interrupt;
18use crate::rcc::RccPeripheral; 20use crate::rcc::RccPeripheral;
19 21
@@ -155,9 +157,15 @@ trait SealedInstance: RccPeripheral + PeripheralType {
155 fn state() -> &'static State; 157 fn state() -> &'static State;
156} 158}
157 159
160#[allow(unused)]
161pub(crate) trait Afio {
162 fn afio_mappings() -> &'static [AfioMapping];
163 fn set_afio(value: u8);
164}
165
158/// Core timer instance. 166/// Core timer instance.
159#[allow(private_bounds)] 167#[allow(private_bounds)]
160pub trait CoreInstance: SealedInstance + 'static { 168pub trait CoreInstance: SealedInstance + Afio + 'static {
161 /// Update Interrupt for this timer. 169 /// Update Interrupt for this timer.
162 type UpdateInterrupt: interrupt::typelevel::Interrupt; 170 type UpdateInterrupt: interrupt::typelevel::Interrupt;
163 171
@@ -450,3 +458,24 @@ impl<T: GeneralInstance1Channel> interrupt::typelevel::Handler<T::CaptureCompare
450 } 458 }
451 } 459 }
452} 460}
461
462#[allow(unused)]
463pub(crate) struct AfioMapping {
464 pub(crate) value: u8,
465 pub(crate) pins: &'static [u8],
466}
467
468#[cfg(afio)]
469fn set_afio<'d, T: Afio>(pins: &[Option<embassy_hal_internal::Peri<'d, crate::gpio::AnyPin>>]) {
470 let mapping = T::afio_mappings()
471 .iter()
472 .find(|m| {
473 pins.iter()
474 .flatten()
475 .map(|p| (*p).pin_port())
476 .all(|p| m.pins.contains(&p))
477 })
478 .expect("Should be called with a combination of timer pins supported by the hardware");
479
480 T::set_afio(mapping.value);
481}
diff --git a/embassy-stm32/src/timer/one_pulse.rs b/embassy-stm32/src/timer/one_pulse.rs
index 498d9c082..0267749e1 100644
--- a/embassy-stm32/src/timer/one_pulse.rs
+++ b/embassy-stm32/src/timer/one_pulse.rs
@@ -42,7 +42,8 @@ impl From<ExternalTriggerPolarity> for Etp {
42/// 42///
43/// This wraps a pin to make it usable as a timer trigger. 43/// This wraps a pin to make it usable as a timer trigger.
44pub struct TriggerPin<'d, T, C> { 44pub struct TriggerPin<'d, T, C> {
45 _pin: Peri<'d, AnyPin>, 45 #[allow(unused)]
46 pin: Peri<'d, AnyPin>,
46 phantom: PhantomData<(T, C)>, 47 phantom: PhantomData<(T, C)>,
47} 48}
48 49
@@ -113,7 +114,7 @@ impl<'d, T: GeneralInstance4Channel, C: TriggerSource> TriggerPin<'d, T, C> {
113 pub fn new(pin: Peri<'d, impl TimerTriggerPin<T, C>>, pull: Pull) -> Self { 114 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 pin.set_as_af(pin.af_num(), AfType::input(pull));
115 TriggerPin { 116 TriggerPin {
116 _pin: pin.into(), 117 pin: pin.into(),
117 phantom: PhantomData, 118 phantom: PhantomData,
118 } 119 }
119 } 120 }
@@ -131,14 +132,17 @@ impl<'d, T: GeneralInstance4Channel> OnePulse<'d, T> {
131 /// 132 ///
132 /// The pulse is triggered by a channel 1 input pin on both rising and 133 /// The pulse is triggered by a channel 1 input pin on both rising and
133 /// falling edges. Channel 1 will unusable as an output. 134 /// falling edges. Channel 1 will unusable as an output.
135 #[allow(unused)]
134 pub fn new_ch1_edge_detect( 136 pub fn new_ch1_edge_detect(
135 tim: Peri<'d, T>, 137 tim: Peri<'d, T>,
136 _pin: TriggerPin<'d, T, Ch1>, 138 pin: TriggerPin<'d, T, Ch1>,
137 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd, 139 _irq: impl Binding<T::CaptureCompareInterrupt, CaptureCompareInterruptHandler<T>> + 'd,
138 freq: Hertz, 140 freq: Hertz,
139 pulse_end: u32, 141 pulse_end: u32,
140 counting_mode: CountingMode, 142 counting_mode: CountingMode,
141 ) -> Self { 143 ) -> Self {
144 #[cfg(afio)]
145 super::set_afio::<T>(&[Some(pin.pin)]);
142 let mut this = Self { inner: Timer::new(tim) }; 146 let mut this = Self { inner: Timer::new(tim) };
143 147
144 this.inner.set_trigger_source(Ts::TI1F_ED); 148 this.inner.set_trigger_source(Ts::TI1F_ED);
diff --git a/embassy-stm32/src/timer/pwm_input.rs b/embassy-stm32/src/timer/pwm_input.rs
index 1e55f2919..c537e5268 100644
--- a/embassy-stm32/src/timer/pwm_input.rs
+++ b/embassy-stm32/src/timer/pwm_input.rs
@@ -20,6 +20,8 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
20 /// Create a new PWM input driver. 20 /// Create a new PWM input driver.
21 pub fn new_ch1(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch1>>, 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 {
22 pin.set_as_af(pin.af_num(), AfType::input(pull)); 22 pin.set_as_af(pin.af_num(), AfType::input(pull));
23 #[cfg(afio)]
24 super::set_afio::<T>(&[Some(pin.into())]);
23 25
24 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2) 26 Self::new_inner(tim, freq, Channel::Ch1, Channel::Ch2)
25 } 27 }
@@ -27,6 +29,8 @@ impl<'d, T: GeneralInstance4Channel> PwmInput<'d, T> {
27 /// Create a new PWM input driver. 29 /// Create a new PWM input driver.
28 pub fn new_ch2(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2>>, pull: Pull, freq: Hertz) -> Self { 30 pub fn new_ch2(tim: Peri<'d, T>, pin: Peri<'d, impl TimerPin<T, Ch2>>, pull: Pull, freq: Hertz) -> Self {
29 pin.set_as_af(pin.af_num(), AfType::input(pull)); 31 pin.set_as_af(pin.af_num(), AfType::input(pull));
32 #[cfg(afio)]
33 super::set_afio::<T>(&[Some(pin.into())]);
30 34
31 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1) 35 Self::new_inner(tim, freq, Channel::Ch2, Channel::Ch1)
32 } 36 }
diff --git a/embassy-stm32/src/timer/qei.rs b/embassy-stm32/src/timer/qei.rs
index eabe1b22a..4e5a309ac 100644
--- a/embassy-stm32/src/timer/qei.rs
+++ b/embassy-stm32/src/timer/qei.rs
@@ -21,19 +21,20 @@ pub enum Direction {
21 21
22/// Wrapper for using a pin with QEI. 22/// Wrapper for using a pin with QEI.
23pub struct QeiPin<'d, T, Channel> { 23pub struct QeiPin<'d, T, Channel> {
24 _pin: Peri<'d, AnyPin>, 24 #[allow(unused)]
25 pin: Peri<'d, AnyPin>,
25 phantom: PhantomData<(T, Channel)>, 26 phantom: PhantomData<(T, Channel)>,
26} 27}
27 28
28impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> { 29impl<'d, T: GeneralInstance4Channel, C: QeiChannel> QeiPin<'d, T, C> {
29 /// Create a new QEI pin instance. 30 /// Create a new QEI pin instance.
30 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>) -> Self { 31 pub fn new(pin: Peri<'d, impl TimerPin<T, C>>) -> Self {
31 critical_section::with(|_| { 32 critical_section::with(|_| {
32 pin.set_low(); 33 pin.set_low();
33 pin.set_as_af(pin.af_num(), AfType::input(Pull::None)); 34 pin.set_as_af(pin.af_num(), AfType::input(Pull::None));
34 }); 35 });
35 QeiPin { 36 QeiPin {
36 _pin: pin.into(), 37 pin: pin.into(),
37 phantom: PhantomData, 38 phantom: PhantomData,
38 } 39 }
39 } 40 }
@@ -58,7 +59,10 @@ pub struct Qei<'d, T: GeneralInstance4Channel> {
58 59
59impl<'d, T: GeneralInstance4Channel> Qei<'d, T> { 60impl<'d, T: GeneralInstance4Channel> Qei<'d, T> {
60 /// Create a new quadrature decoder driver. 61 /// Create a new quadrature decoder driver.
61 pub fn new(tim: Peri<'d, T>, _ch1: QeiPin<'d, T, Ch1>, _ch2: QeiPin<'d, T, Ch2>) -> Self { 62 #[allow(unused)]
63 pub fn new(tim: Peri<'d, T>, ch1: QeiPin<'d, T, Ch1>, ch2: QeiPin<'d, T, Ch2>) -> Self {
64 #[cfg(afio)]
65 super::set_afio::<T>(&[Some(ch1.pin), Some(ch2.pin)]);
62 Self::new_inner(tim) 66 Self::new_inner(tim)
63 } 67 }
64 68
diff --git a/embassy-stm32/src/timer/simple_pwm.rs b/embassy-stm32/src/timer/simple_pwm.rs
index c04b1ab97..df86859fe 100644
--- a/embassy-stm32/src/timer/simple_pwm.rs
+++ b/embassy-stm32/src/timer/simple_pwm.rs
@@ -15,7 +15,8 @@ use crate::Peri;
15/// 15///
16/// This wraps a pin to make it usable with PWM. 16/// This wraps a pin to make it usable with PWM.
17pub struct PwmPin<'d, T, C> { 17pub struct PwmPin<'d, T, C> {
18 _pin: Peri<'d, AnyPin>, 18 #[allow(unused)]
19 pub(crate) pin: Peri<'d, AnyPin>,
19 phantom: PhantomData<(T, C)>, 20 phantom: PhantomData<(T, C)>,
20} 21}
21 22
@@ -42,7 +43,7 @@ impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> {
42 pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh)); 43 pin.set_as_af(pin.af_num(), AfType::output(output_type, Speed::VeryHigh));
43 }); 44 });
44 PwmPin { 45 PwmPin {
45 _pin: pin.into(), 46 pin: pin.into(),
46 phantom: PhantomData, 47 phantom: PhantomData,
47 } 48 }
48 } 49 }
@@ -60,7 +61,7 @@ impl<'d, T: GeneralInstance4Channel, C: TimerChannel> PwmPin<'d, T, C> {
60 ); 61 );
61 }); 62 });
62 PwmPin { 63 PwmPin {
63 _pin: pin.into(), 64 pin: pin.into(),
64 phantom: PhantomData, 65 phantom: PhantomData,
65 } 66 }
66 } 67 }
@@ -178,15 +179,23 @@ pub struct SimplePwm<'d, T: GeneralInstance4Channel> {
178 179
179impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> { 180impl<'d, T: GeneralInstance4Channel> SimplePwm<'d, T> {
180 /// Create a new simple PWM driver. 181 /// Create a new simple PWM driver.
182 #[allow(unused)]
181 pub fn new( 183 pub fn new(
182 tim: Peri<'d, T>, 184 tim: Peri<'d, T>,
183 _ch1: Option<PwmPin<'d, T, Ch1>>, 185 ch1: Option<PwmPin<'d, T, Ch1>>,
184 _ch2: Option<PwmPin<'d, T, Ch2>>, 186 ch2: Option<PwmPin<'d, T, Ch2>>,
185 _ch3: Option<PwmPin<'d, T, Ch3>>, 187 ch3: Option<PwmPin<'d, T, Ch3>>,
186 _ch4: Option<PwmPin<'d, T, Ch4>>, 188 ch4: Option<PwmPin<'d, T, Ch4>>,
187 freq: Hertz, 189 freq: Hertz,
188 counting_mode: CountingMode, 190 counting_mode: CountingMode,
189 ) -> Self { 191 ) -> Self {
192 #[cfg(afio)]
193 super::set_afio::<T>(&[
194 ch1.map(|p| p.pin),
195 ch2.map(|p| p.pin),
196 ch3.map(|p| p.pin),
197 ch4.map(|p| p.pin),
198 ]);
190 Self::new_inner(tim, freq, counting_mode) 199 Self::new_inner(tim, freq, counting_mode)
191 } 200 }
192 201