aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatous Hybl <[email protected]>2021-12-08 17:37:46 +0100
committerMatous Hybl <[email protected]>2022-01-13 16:05:54 +0100
commit16d09f074a845abc4e03010de9a3e4804807a57e (patch)
tree392343a2e4da3ff0b944a5dd65755f071d469570
parenta1f7a94c6924a5344ed29b60e11be673ca04bfcb (diff)
Add simple PWM, add PWM pin definitions also accessible from low-level API.
-rw-r--r--embassy-stm32/src/pwm/mod.rs354
-rw-r--r--embassy-stm32/src/pwm/pins.rs138
-rw-r--r--embassy-stm32/src/pwm/simple_pwm.rs80
3 files changed, 428 insertions, 144 deletions
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs
index 8357b6cdc..b62a14668 100644
--- a/embassy-stm32/src/pwm/mod.rs
+++ b/embassy-stm32/src/pwm/mod.rs
@@ -1,21 +1,17 @@
1use crate::gpio; 1#[cfg(feature = "unstable-pac")]
2use crate::rcc::RccPeripheral; 2#[macro_use]
3use crate::time::Hertz; 3pub mod pins;
4use core::marker::PhantomData; 4
5use embassy::util::Unborrow; 5#[cfg(not(feature = "unstable-pac"))]
6use embassy_hal_common::unborrow; 6#[macro_use]
7use stm32_metapac::timer::vals::Ocm; 7pub(crate) mod pins;
8
9pub struct Pwm<'d, T: Instance> {
10 phantom: PhantomData<&'d mut T>,
11}
12 8
13// TIM2 9pub mod simple_pwm;
14 10
15pub struct Ch1 {} 11#[cfg(feature = "unstable-pac")]
16pub struct Ch2 {} 12pub mod low_level {
17pub struct Ch3 {} 13 pub use super::sealed::*;
18pub struct Ch4 {} 14}
19 15
20#[derive(Clone, Copy)] 16#[derive(Clone, Copy)]
21pub enum Channel { 17pub enum Channel {
@@ -25,171 +21,241 @@ pub enum Channel {
25 Ch4, 21 Ch4,
26} 22}
27 23
28impl<'d, T: Instance> Pwm<'d, T> { 24impl Channel {
29 pub fn new<F: Into<Hertz>>( 25 pub fn raw(&self) -> usize {
30 _tim: impl Unborrow<Target = T> + 'd, 26 match self {
31 ch1: impl Unborrow<Target = impl PwmPin<T, Ch1>> + 'd, 27 Channel::Ch1 => 0,
32 ch2: impl Unborrow<Target = impl PwmPin<T, Ch2>> + 'd, 28 Channel::Ch2 => 1,
33 ch3: impl Unborrow<Target = impl PwmPin<T, Ch3>> + 'd, 29 Channel::Ch3 => 2,
34 ch4: impl Unborrow<Target = impl PwmPin<T, Ch4>> + 'd, 30 Channel::Ch4 => 3,
35 freq: F,
36 ) -> Self {
37 unborrow!(ch1, ch2, ch3, ch4);
38
39 T::enable();
40 T::reset();
41 let r = T::regs();
42
43 let mut this = Pwm {
44 phantom: PhantomData,
45 };
46 unsafe {
47 ch1.configure();
48 ch2.configure();
49 ch3.configure();
50 ch4.configure();
51 }
52
53 unsafe {
54 use stm32_metapac::timer::vals::Dir;
55 this.set_freq(freq);
56 r.cr1().write(|w| {
57 w.set_cen(true);
58 w.set_dir(Dir::UP)
59 });
60
61 this.set_ocm(Channel::Ch1, Ocm::PWMMODE1);
62 this.set_ocm(Channel::Ch2, Ocm::PWMMODE1);
63 this.set_ocm(Channel::Ch3, Ocm::PWMMODE1);
64 this.set_ocm(Channel::Ch4, Ocm::PWMMODE1);
65 } 31 }
66 this
67 } 32 }
33}
68 34
69 unsafe fn set_ocm(&mut self, channel: Channel, mode: Ocm) { 35#[derive(Clone, Copy)]
70 let r = T::regs(); 36pub enum OutputCompareMode {
71 match channel { 37 Frozen,
72 Channel::Ch1 => r.ccmr_output(0).modify(|w| w.set_ocm(0, mode)), 38 ActiveOnMatch,
73 Channel::Ch2 => r.ccmr_output(0).modify(|w| w.set_ocm(1, mode)), 39 InactiveOnMatch,
74 Channel::Ch3 => r.ccmr_output(1).modify(|w| w.set_ocm(0, mode)), 40 Toggle,
75 Channel::Ch4 => r.ccmr_output(1).modify(|w| w.set_ocm(1, mode)), 41 ForceInactive,
76 } 42 ForceActive,
77 } 43 PwmMode1,
44 PwmMode2,
45}
78 46
79 unsafe fn set_enable(&mut self, channel: Channel, enable: bool) { 47impl From<OutputCompareMode> for stm32_metapac::timer::vals::Ocm {
80 let r = T::regs(); 48 fn from(mode: OutputCompareMode) -> Self {
81 match channel { 49 match mode {
82 Channel::Ch1 => r.ccer().modify(|w| w.set_cce(0, enable)), 50 OutputCompareMode::Frozen => stm32_metapac::timer::vals::Ocm::FROZEN,
83 Channel::Ch2 => r.ccer().modify(|w| w.set_cce(1, enable)), 51 OutputCompareMode::ActiveOnMatch => stm32_metapac::timer::vals::Ocm::ACTIVEONMATCH,
84 Channel::Ch3 => r.ccer().modify(|w| w.set_cce(2, enable)), 52 OutputCompareMode::InactiveOnMatch => stm32_metapac::timer::vals::Ocm::INACTIVEONMATCH,
85 Channel::Ch4 => r.ccer().modify(|w| w.set_cce(3, enable)), 53 OutputCompareMode::Toggle => stm32_metapac::timer::vals::Ocm::TOGGLE,
54 OutputCompareMode::ForceInactive => stm32_metapac::timer::vals::Ocm::FORCEINACTIVE,
55 OutputCompareMode::ForceActive => stm32_metapac::timer::vals::Ocm::FORCEACTIVE,
56 OutputCompareMode::PwmMode1 => stm32_metapac::timer::vals::Ocm::PWMMODE1,
57 OutputCompareMode::PwmMode2 => stm32_metapac::timer::vals::Ocm::PWMMODE2,
86 } 58 }
87 } 59 }
60}
88 61
89 pub fn enable(&mut self, channel: Channel) { 62pub(crate) mod sealed {
90 unsafe { self.set_enable(channel, true) } 63 use super::*;
91 }
92 64
93 pub fn disable(&mut self, channel: Channel) { 65 pub trait CaptureCompareCapable16bitInstance:
94 unsafe { self.set_enable(channel, false) } 66 crate::timer::sealed::GeneralPurpose16bitInstance
95 } 67 {
68 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
96 69
97 pub fn set_freq<F: Into<Hertz>>(&mut self, freq: F) { 70 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool);
98 use core::convert::TryInto;
99 let clk = T::frequency();
100 let r = T::regs();
101 let freq: Hertz = freq.into();
102 let ticks: u32 = clk.0 / freq.0;
103 let psc: u16 = (ticks / (1 << 16)).try_into().unwrap();
104 let arr: u16 = (ticks / (u32::from(psc) + 1)).try_into().unwrap();
105 unsafe {
106 r.psc().write(|w| w.set_psc(psc));
107 r.arr().write(|w| w.set_arr(arr));
108 }
109 }
110 71
111 pub fn get_max_duty(&self) -> u32 { 72 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16);
112 let r = T::regs();
113 unsafe { r.arr().read().arr() as u32 }
114 }
115 73
116 pub fn set_duty(&mut self, channel: Channel, duty: u32) { 74 unsafe fn get_max_compare_value(&self) -> u16;
117 use core::convert::TryInto;
118 assert!(duty < self.get_max_duty());
119 let duty: u16 = duty.try_into().unwrap();
120 let r = T::regs();
121 unsafe {
122 match channel {
123 Channel::Ch1 => r.ccr(0).modify(|w| w.set_ccr(duty)),
124 Channel::Ch2 => r.ccr(1).modify(|w| w.set_ccr(duty)),
125 Channel::Ch3 => r.ccr(2).modify(|w| w.set_ccr(duty)),
126 Channel::Ch4 => r.ccr(3).modify(|w| w.set_ccr(duty)),
127 }
128 }
129 } 75 }
130}
131 76
132pub(crate) mod sealed { 77 pub trait CaptureCompareCapable32bitInstance:
133 pub trait Instance { 78 crate::timer::sealed::GeneralPurpose32bitInstance
134 fn regs() -> crate::pac::timer::TimGp16; 79 {
80 unsafe fn set_output_compare_mode(&mut self, channel: Channel, mode: OutputCompareMode);
81
82 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool);
83
84 unsafe fn set_compare_value(&mut self, channel: Channel, value: u32);
85
86 unsafe fn get_max_compare_value(&self) -> u32;
135 } 87 }
136} 88}
137 89
138pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {} 90pub trait CaptureCompareCapable16bitInstance:
91 sealed::CaptureCompareCapable16bitInstance + crate::timer::GeneralPurpose16bitInstance + 'static
92{
93}
94pub trait CaptureCompareCapable32bitInstance:
95 sealed::CaptureCompareCapable32bitInstance + crate::timer::GeneralPurpose32bitInstance + 'static
96{
97}
139 98
140#[allow(unused)] 99#[allow(unused)]
141macro_rules! impl_timer { 100macro_rules! impl_compare_capable_16bit {
142 ($inst:ident) => { 101 ($inst:ident) => {
143 impl crate::pwm::sealed::Instance for crate::peripherals::$inst { 102 impl crate::pwm::sealed::CaptureCompareCapable16bitInstance for crate::peripherals::$inst {
144 fn regs() -> crate::pac::timer::TimGp16 { 103 unsafe fn set_output_compare_mode(
145 crate::pac::timer::TimGp16(crate::pac::$inst.0) 104 &mut self,
105 channel: crate::pwm::Channel,
106 mode: OutputCompareMode,
107 ) {
108 use crate::timer::sealed::GeneralPurpose16bitInstance;
109 let r = self.regs_gp16();
110 let raw_channel: usize = channel.raw();
111 r.ccmr_output(raw_channel / 2)
112 .modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
146 } 113 }
147 }
148 114
149 impl crate::pwm::Instance for crate::peripherals::$inst {} 115 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
116 use crate::timer::sealed::GeneralPurpose16bitInstance;
117 self.regs_gp16()
118 .ccer()
119 .modify(|w| w.set_cce(channel.raw(), enable));
120 }
121
122 unsafe fn set_compare_value(&mut self, channel: Channel, value: u16) {
123 use crate::timer::sealed::GeneralPurpose16bitInstance;
124 self.regs_gp16()
125 .ccr(channel.raw())
126 .modify(|w| w.set_ccr(value));
127 }
128
129 unsafe fn get_max_compare_value(&self) -> u16 {
130 use crate::timer::sealed::GeneralPurpose16bitInstance;
131 self.regs_gp16().arr().read().arr()
132 }
133 }
150 }; 134 };
151} 135}
152 136
153pub trait PwmPin<Timer, Channel>: gpio::OptionalPin { 137crate::pac::interrupts! {
154 unsafe fn configure(&mut self); 138 ($inst:ident, timer, TIM_GP16, UP, $irq:ident) => {
155} 139 impl_compare_capable_16bit!($inst);
156 140
157impl<Timer, Channel> PwmPin<Timer, Channel> for gpio::NoPin { 141 impl CaptureCompareCapable16bitInstance for crate::peripherals::$inst {
158 unsafe fn configure(&mut self) {}
159}
160 142
161#[allow(unused)] 143 }
162macro_rules! impl_pwm_pin { 144 };
163 ($timer:ident, $channel:ident, $pin:ident, $af:expr) => { 145
164 impl crate::pwm::PwmPin<crate::peripherals::$timer, crate::pwm::$channel> 146 ($inst:ident, timer, TIM_GP32, UP, $irq:ident) => {
165 for crate::peripherals::$pin 147 impl_compare_capable_16bit!($inst);
166 { 148 impl crate::pwm::sealed::CaptureCompareCapable32bitInstance for crate::peripherals::$inst {
167 unsafe fn configure(&mut self) { 149 unsafe fn set_output_compare_mode(
168 use crate::gpio::sealed::{AFType, Pin}; 150 &mut self,
169 use crate::gpio::Speed; 151 channel: crate::pwm::Channel,
170 self.set_low(); 152 mode: OutputCompareMode,
171 self.set_speed(Speed::VeryHigh); 153 ) {
172 self.set_as_af($af, AFType::OutputPushPull); 154 use crate::timer::sealed::GeneralPurpose32bitInstance;
155 let raw_channel = channel.raw();
156 self.regs_gp32().ccmr_output(raw_channel / 2).modify(|w| w.set_ocm(raw_channel % 2, mode.into()));
173 } 157 }
158
159 unsafe fn enable_channel(&mut self, channel: Channel, enable: bool) {
160 use crate::timer::sealed::GeneralPurpose32bitInstance;
161 self.regs_gp32().ccer().modify(|w| w.set_cce(channel.raw(), enable));
162 }
163
164 unsafe fn set_compare_value(&mut self, channel: Channel, value: u32) {
165 use crate::timer::sealed::GeneralPurpose32bitInstance;
166 self.regs_gp32().ccr(channel.raw()).modify(|w| w.set_ccr(value));
167 }
168
169 unsafe fn get_max_compare_value(&self) -> u32 {
170 use crate::timer::sealed::GeneralPurpose32bitInstance;
171 self.regs_gp32().arr().read().arr() as u32
172 }
173 }
174 impl CaptureCompareCapable16bitInstance for crate::peripherals::$inst {
175
176 }
177 impl CaptureCompareCapable32bitInstance for crate::peripherals::$inst {
178
179 }
180 };
181
182 ($inst:ident, timer, TIM_ADV, UP, $irq:ident) => {
183 impl_compare_capable_16bit!($inst);
184 impl CaptureCompareCapable16bitInstance for crate::peripherals::$inst {
185
174 } 186 }
175 }; 187 };
176} 188}
177 189
190#[allow(unused)]
191macro_rules! impl_pwm_nopin {
192 ($inst:ident) => {
193 impl_no_pin!($inst, Channel1Pin);
194 impl_no_pin!($inst, Channel1ComplementaryPin);
195 impl_no_pin!($inst, Channel2Pin);
196 impl_no_pin!($inst, Channel2ComplementaryPin);
197 impl_no_pin!($inst, Channel3Pin);
198 impl_no_pin!($inst, Channel3ComplementaryPin);
199 impl_no_pin!($inst, Channel4Pin);
200 impl_no_pin!($inst, Channel4ComplementaryPin);
201 impl_no_pin!($inst, ExternalTriggerPin);
202 impl_no_pin!($inst, BreakInputPin);
203 impl_no_pin!($inst, BreakInputComparator1Pin);
204 impl_no_pin!($inst, BreakInputComparator2Pin);
205 impl_no_pin!($inst, BreakInput2Pin);
206 impl_no_pin!($inst, BreakInput2Comparator1Pin);
207 impl_no_pin!($inst, BreakInput2Comparator2Pin);
208 };
209}
210
178crate::pac::peripherals!( 211crate::pac::peripherals!(
179 (timer, $inst:ident) => { impl_timer!($inst); }; 212 (timer, $inst:ident) => { impl_pwm_nopin!($inst); };
180); 213);
181 214
182crate::pac::peripheral_pins!( 215crate::pac::peripheral_pins!(
183 ($inst:ident, timer,TIM_GP16, $pin:ident, CH1, $af:expr) => { 216 ($inst:ident, timer, $block:ident, $pin:ident, CH1, $af:expr) => {
184 impl_pwm_pin!($inst, Ch1, $pin, $af); 217 impl_pin!($inst, Channel1Pin, $pin, $af);
218 };
219 ($inst:ident, timer, $block:ident, $pin:ident, CH1N, $af:expr) => {
220 impl_pin!($inst, Channel1ComplementaryPin, $pin, $af);
221 };
222 ($inst:ident, timer, $block:ident, $pin:ident, CH2, $af:expr) => {
223 impl_pin!($inst, Channel2Pin, $pin, $af);
224 };
225 ($inst:ident, timer, $block:ident, $pin:ident, CH2N, $af:expr) => {
226 impl_pin!($inst, Channel2ComplementaryPin, $pin, $af);
227 };
228 ($inst:ident, timer, $block:ident, $pin:ident, CH3, $af:expr) => {
229 impl_pin!($inst, Channel3Pin, $pin, $af);
230 };
231 ($inst:ident, timer, $block:ident, $pin:ident, CH3N, $af:expr) => {
232 impl_pin!($inst, Channel3ComplementaryPin, $pin, $af);
233 };
234 ($inst:ident, timer, $block:ident, $pin:ident, CH4, $af:expr) => {
235 impl_pin!($inst, Channel4Pin, $pin, $af);
236 };
237 ($inst:ident, timer, $block:ident, $pin:ident, CH4N, $af:expr) => {
238 impl_pin!($inst, Channel4ComplementaryPin, $pin, $af);
239 };
240 ($inst:ident, timer, $block:ident, $pin:ident, ETR, $af:expr) => {
241 impl_pin!($inst, ExternalTriggerPin, $pin, $af);
242 };
243 ($inst:ident, timer, $block:ident, $pin:ident, BKIN, $af:expr) => {
244 impl_pin!($inst, BreakInputPin, $pin, $af);
245 };
246 ($inst:ident, timer, $block:ident, $pin:ident, BKIN_COMP1, $af:expr) => {
247 impl_pin!($inst, BreakInputComparator1Pin, $pin, $af);
248 };
249 ($inst:ident, timer, $block:ident, $pin:ident, BKIN_COMP2, $af:expr) => {
250 impl_pin!($inst, BreakInputComparator2Pin, $pin, $af);
185 }; 251 };
186 ($inst:ident, timer,TIM_GP16, $pin:ident, CH2, $af:expr) => { 252 ($inst:ident, timer, $block:ident, $pin:ident, BKIN2, $af:expr) => {
187 impl_pwm_pin!($inst, Ch2, $pin, $af); 253 impl_pin!($inst, BreakInput2Pin, $pin, $af);
188 }; 254 };
189 ($inst:ident, timer,TIM_GP16, $pin:ident, CH3, $af:expr) => { 255 ($inst:ident, timer, $block:ident, $pin:ident, BKIN2_COMP1, $af:expr) => {
190 impl_pwm_pin!($inst, Ch3, $pin, $af); 256 impl_pin!($inst, BreakInput2Comparator1Pin, $pin, $af);
191 }; 257 };
192 ($inst:ident, timer,TIM_GP16, $pin:ident, CH4, $af:expr) => { 258 ($inst:ident, timer, $block:ident, $pin:ident, BKIN2_COMP2, $af:expr) => {
193 impl_pwm_pin!($inst, Ch4, $pin, $af); 259 impl_pin!($inst, BreakInput2Comparator2Pin, $pin, $af);
194 }; 260 };
195); 261);
diff --git a/embassy-stm32/src/pwm/pins.rs b/embassy-stm32/src/pwm/pins.rs
new file mode 100644
index 000000000..77ba1f6d5
--- /dev/null
+++ b/embassy-stm32/src/pwm/pins.rs
@@ -0,0 +1,138 @@
1use crate::gpio::OptionalPin;
2
3#[cfg(feature = "unstable-pac")]
4pub mod low_level {
5 pub use super::sealed::*;
6}
7
8pub(crate) mod sealed {
9 use crate::gpio::sealed::OptionalPin;
10
11 pub trait Channel1Pin<Timer>: OptionalPin {
12 unsafe fn configure(&mut self);
13 }
14 pub trait Channel1ComplementaryPin<Timer>: OptionalPin {
15 unsafe fn configure(&mut self);
16 }
17
18 pub trait Channel2Pin<Timer>: OptionalPin {
19 unsafe fn configure(&mut self);
20 }
21 pub trait Channel2ComplementaryPin<Timer>: OptionalPin {
22 unsafe fn configure(&mut self);
23 }
24
25 pub trait Channel3Pin<Timer>: OptionalPin {
26 unsafe fn configure(&mut self);
27 }
28 pub trait Channel3ComplementaryPin<Timer>: OptionalPin {
29 unsafe fn configure(&mut self);
30 }
31
32 pub trait Channel4Pin<Timer>: OptionalPin {
33 unsafe fn configure(&mut self);
34 }
35 pub trait Channel4ComplementaryPin<Timer>: OptionalPin {
36 unsafe fn configure(&mut self);
37 }
38
39 pub trait ExternalTriggerPin<Timer>: OptionalPin {
40 unsafe fn configure(&mut self);
41 }
42
43 pub trait BreakInputPin<Timer>: OptionalPin {
44 unsafe fn configure(&mut self);
45 }
46 pub trait BreakInputComparator1Pin<Timer>: OptionalPin {
47 unsafe fn configure(&mut self);
48 }
49 pub trait BreakInputComparator2Pin<Timer>: OptionalPin {
50 unsafe fn configure(&mut self);
51 }
52
53 pub trait BreakInput2Pin<Timer>: OptionalPin {
54 unsafe fn configure(&mut self);
55 }
56 pub trait BreakInput2Comparator1Pin<Timer>: OptionalPin {
57 unsafe fn configure(&mut self);
58 }
59 pub trait BreakInput2Comparator2Pin<Timer>: OptionalPin {
60 unsafe fn configure(&mut self);
61 }
62}
63pub trait Channel1Pin<Timer>: sealed::Channel1Pin<Timer> + OptionalPin + 'static {}
64pub trait Channel1ComplementaryPin<Timer>:
65 sealed::Channel1ComplementaryPin<Timer> + OptionalPin + 'static
66{
67}
68
69pub trait Channel2Pin<Timer>: sealed::Channel2Pin<Timer> + 'static {}
70pub trait Channel2ComplementaryPin<Timer>:
71 sealed::Channel2ComplementaryPin<Timer> + OptionalPin + 'static
72{
73}
74
75pub trait Channel3Pin<Timer>: sealed::Channel3Pin<Timer> + 'static {}
76pub trait Channel3ComplementaryPin<Timer>:
77 sealed::Channel3ComplementaryPin<Timer> + OptionalPin + 'static
78{
79}
80
81pub trait Channel4Pin<Timer>: sealed::Channel4Pin<Timer> + 'static {}
82pub trait Channel4ComplementaryPin<Timer>:
83 sealed::Channel4ComplementaryPin<Timer> + OptionalPin + 'static
84{
85}
86
87pub trait ExternalTriggerPin<Timer>:
88 sealed::ExternalTriggerPin<Timer> + OptionalPin + 'static
89{
90}
91
92pub trait BreakInputPin<Timer>: sealed::BreakInputPin<Timer> + OptionalPin + 'static {}
93pub trait BreakInputComparator1Pin<Timer>:
94 sealed::BreakInputComparator1Pin<Timer> + OptionalPin + 'static
95{
96}
97pub trait BreakInputComparator2Pin<Timer>:
98 sealed::BreakInputComparator2Pin<Timer> + OptionalPin + 'static
99{
100}
101
102pub trait BreakInput2Pin<Timer>: sealed::BreakInput2Pin<Timer> + OptionalPin + 'static {}
103pub trait BreakInput2Comparator1Pin<Timer>:
104 sealed::BreakInput2Comparator1Pin<Timer> + OptionalPin + 'static
105{
106}
107pub trait BreakInput2Comparator2Pin<Timer>:
108 sealed::BreakInput2Comparator2Pin<Timer> + OptionalPin + 'static
109{
110}
111
112macro_rules! impl_no_pin {
113 ($timer:ident, $signal:ident) => {
114 impl crate::pwm::pins::sealed::$signal<crate::peripherals::$timer> for crate::gpio::NoPin {
115 unsafe fn configure(&mut self) {}
116 }
117 impl crate::pwm::pins::$signal<crate::peripherals::$timer> for crate::gpio::NoPin {}
118 };
119}
120
121#[allow(unused)]
122macro_rules! impl_pin {
123 ($timer:ident, $signal:ident, $pin:ident, $af:expr) => {
124 impl crate::pwm::pins::sealed::$signal<crate::peripherals::$timer>
125 for crate::peripherals::$pin
126 {
127 unsafe fn configure(&mut self) {
128 use crate::gpio::sealed::{AFType, Pin};
129 use crate::gpio::Speed;
130 self.set_low();
131 self.set_speed(Speed::VeryHigh);
132 self.set_as_af($af, AFType::OutputPushPull);
133 }
134 }
135
136 impl crate::pwm::pins::$signal<crate::peripherals::$timer> for crate::peripherals::$pin {}
137 };
138}
diff --git a/embassy-stm32/src/pwm/simple_pwm.rs b/embassy-stm32/src/pwm/simple_pwm.rs
new file mode 100644
index 000000000..3dc46e6e8
--- /dev/null
+++ b/embassy-stm32/src/pwm/simple_pwm.rs
@@ -0,0 +1,80 @@
1use crate::{
2 pwm::{pins::*, CaptureCompareCapable16bitInstance, Channel, OutputCompareMode},
3 time::Hertz,
4};
5use core::marker::PhantomData;
6use embassy::util::Unborrow;
7use embassy_hal_common::unborrow;
8
9pub struct SimplePwm<'d, T> {
10 phantom: PhantomData<&'d mut T>,
11 inner: T,
12}
13
14impl<'d, T: CaptureCompareCapable16bitInstance> SimplePwm<'d, T> {
15 pub fn new<F: Into<Hertz>>(
16 tim: impl Unborrow<Target = T> + 'd,
17 ch1: impl Unborrow<Target = impl Channel1Pin<T>> + 'd,
18 ch2: impl Unborrow<Target = impl Channel2Pin<T>> + 'd,
19 ch3: impl Unborrow<Target = impl Channel3Pin<T>> + 'd,
20 ch4: impl Unborrow<Target = impl Channel4Pin<T>> + 'd,
21 freq: F,
22 ) -> Self {
23 unborrow!(tim, ch1, ch2, ch3, ch4);
24
25 T::enable();
26 <T as crate::rcc::sealed::RccPeripheral>::reset();
27
28 unsafe {
29 ch1.configure();
30 ch2.configure();
31 ch3.configure();
32 ch4.configure();
33 }
34
35 let mut this = Self {
36 inner: tim,
37 phantom: PhantomData,
38 };
39
40 this.inner.set_frequency(freq);
41 this.inner.start();
42
43 unsafe {
44 this.inner
45 .set_output_compare_mode(Channel::Ch1, OutputCompareMode::PwmMode1);
46 this.inner
47 .set_output_compare_mode(Channel::Ch2, OutputCompareMode::PwmMode1);
48 this.inner
49 .set_output_compare_mode(Channel::Ch3, OutputCompareMode::PwmMode1);
50 this.inner
51 .set_output_compare_mode(Channel::Ch4, OutputCompareMode::PwmMode1);
52 }
53 this
54 }
55
56 pub fn enable(&mut self, channel: Channel) {
57 unsafe {
58 self.inner.enable_channel(channel, true);
59 }
60 }
61
62 pub fn disable(&mut self, channel: Channel) {
63 unsafe {
64 self.inner.enable_channel(channel, false);
65 }
66 }
67
68 pub fn set_freq<F: Into<Hertz>>(&mut self, freq: F) {
69 self.inner.set_frequency(freq);
70 }
71
72 pub fn get_max_duty(&self) -> u16 {
73 unsafe { self.inner.get_max_compare_value() }
74 }
75
76 pub fn set_duty(&mut self, channel: Channel, duty: u16) {
77 assert!(duty < self.get_max_duty());
78 unsafe { self.inner.set_compare_value(channel, duty) }
79 }
80}