1use core::marker::PhantomData;
3
4use crate::rcc::*;
5use crate::stm32::*;
6use crate::time::Hertz;
7use crate::timer::pins::TimerPin;
8use crate::timer::*;
9
10pub enum OutputCompareMode {
11 Frozen = 0,
12 MatchPos = 1,
13 MatchNeg = 2,
14 MatchToggle = 3,
15 ForceLow = 4,
16 ForceHigh = 5,
17 PwmMode1 = 6,
18 PmwMode2 = 7,
19 OpmMode1 = 8,
20 OomMode2 = 9,
21 CombinedMode1 = 12,
22 CombinedMode2 = 13,
23 AsyncMode1 = 14,
24 AsyncMode2 = 15,
25}
26
27pub struct Pwm<TIM> {
28 clk: Hertz,
29 tim: TIM,
30}
31
32pub struct PwmPin<TIM, CH> {
33 tim: PhantomData<TIM>,
34 channel: PhantomData<CH>,
35}
36
37enum ClockSource {
38 ApbTim,
39 #[allow(dead_code)]
40 Pllq,
41}
42
43pub trait PwmExt: Sized {
44 fn pwm(self, freq: Hertz, rcc: &mut Rcc) -> Pwm<Self>;
45}
46
47pub trait PwmQExt: Sized {
48 fn pwm_q(self, freq: Hertz, rcc: &mut Rcc) -> Pwm<Self>;
51}
52
53pub trait PwmPinMode {
54 fn set_compare_mode(&mut self, mode: OutputCompareMode);
55}
56
57impl<TIM> Pwm<TIM> {
58 pub fn bind_pin<PIN>(&self, pin: PIN) -> PwmPin<TIM, PIN::Channel>
59 where
60 PIN: TimerPin<TIM>,
61 {
62 pin.setup();
63 PwmPin {
64 tim: PhantomData,
65 channel: PhantomData,
66 }
67 }
68}
69
70macro_rules! pwm {
71 ($($TIMX:ident: ($timX:ident, $arr:ident $(,$arr_h:ident)*),)+) => {
72 $(
73 impl PwmExt for $TIMX {
74 fn pwm(self, freq: Hertz, rcc: &mut Rcc) -> Pwm<Self> {
75 $timX(self, freq, rcc, ClockSource::ApbTim)
76 }
77 }
78
79 fn $timX(tim: $TIMX, freq: Hertz, rcc: &mut Rcc, clock_source: ClockSource) -> Pwm<$TIMX> {
80 $TIMX::enable(rcc);
81 $TIMX::reset(rcc);
82
83 let clk = match clock_source {
84 ClockSource::ApbTim => {
85 rcc.ccipr.modify(|_, w| w.tim1sel().clear_bit());
86 rcc.clocks.apb_tim_clk
87 }
88 ClockSource::Pllq => {
89 rcc.ccipr.modify(|_, w| w.tim1sel().set_bit());
90 rcc.clocks.pll_clk.q.unwrap()
91 }
92 };
93
94 let mut pwm = Pwm::<$TIMX> {
95 clk,
96 tim,
97 };
98 pwm.set_freq(freq);
99 pwm
100 }
101
102 impl Pwm<$TIMX> {
103 pub fn set_freq(&mut self, freq: Hertz) {
107 let ratio = self.clk / freq;
108 let psc = (ratio - 1) / 0xffff;
109 let arr = ratio / (psc + 1) - 1;
110
111 unsafe {
112 self.tim.psc.write(|w| w.psc().bits(psc as u16));
113 self.tim.arr.write(|w| w.$arr().bits(arr as u16));
114 $(
115 self.tim.arr.modify(|_, w| w.$arr_h().bits((arr >> 16) as u16));
116 )*
117 self.tim.cr1.write(|w| w.cen().set_bit())
118 }
119 }
120 pub fn listen(&mut self) {
122 self.tim.dier.write(|w| w.uie().set_bit());
123 }
124
125 pub fn unlisten(&mut self) {
127 self.tim.dier.write(|w| w.uie().clear_bit());
128 }
129 pub fn clear_irq(&mut self) {
131 self.tim.sr.modify(|_, w| w.uif().clear_bit());
132 }
133
134 pub fn reset(&mut self) {
136 self.tim.cnt.reset();
137 }
138
139 pub fn freq(&self) -> Hertz {
141 Hertz::from_raw(self.clk.raw()
142 / (self.tim.psc.read().bits() + 1)
143 / (self.tim.arr.read().bits() + 1))
144 }
145 }
146 )+
147 }
148}
149
150#[allow(unused_macros)]
151macro_rules! pwm_q {
152 ($($TIMX:ident: $timX:ident,)+) => {
153 $(
154 impl PwmQExt for $TIMX {
155 fn pwm_q(self, freq: Hertz, rcc: &mut Rcc) -> Pwm<Self> {
156 $timX(self, freq, rcc, ClockSource::Pllq)
157 }
158 }
159 )+
160 }
161}
162
163#[cfg(any(feature = "stm32g0x1", feature = "stm32g070"))]
164macro_rules! pwm_hal {
165 ($($TIMX:ident:
166 ($CH:ty, $ccxe:ident, $ccmrx_output:ident, $ocxpe:ident, $ocxm:ident, $ccrx:ident, $ccrx_l:ident, $ccrx_h:ident),)+
167 ) => {
168 $(
169 impl hal::PwmPin for PwmPin<$TIMX, $CH> {
170 type Duty = u32;
171
172 fn disable(&mut self) {
173 unsafe {
174 (*$TIMX::ptr()).ccer.modify(|_, w| w.$ccxe().clear_bit());
175 }
176 }
177
178 fn enable(&mut self) {
179 unsafe {
180 let tim = &*$TIMX::ptr();
181 tim.$ccmrx_output().modify(|_, w| w.$ocxpe().set_bit().$ocxm().bits(6));
182 tim.ccer.modify(|_, w| w.$ccxe().set_bit());
183 }
184 }
185
186 fn get_duty(&self) -> u32 {
187 unsafe { (*$TIMX::ptr()).$ccrx.read().bits() }
188 }
189
190 fn get_max_duty(&self) -> u32 {
191 unsafe { (*$TIMX::ptr()).arr.read().bits() }
192 }
193
194 fn set_duty(&mut self, duty: u32) {
195 unsafe { (*$TIMX::ptr()).$ccrx.write(|w| w.bits(duty)) }
196 }
197 }
198 )+
199 };
200}
201
202macro_rules! pwm_advanced_hal {
203 ($($TIMX:ident: (
204 $CH:ty,
205 $ccxe:ident $(: $ccxne:ident)*,
206 $ccmrx_output:ident,
207 $ocxpe:ident,
208 $ocxm:ident,
209 $ccrx:ident
210 $(, $moe:ident)*
211 ) ,)+
212 ) => {
213 $(
214 impl hal::PwmPin for PwmPin<$TIMX, $CH> {
215 type Duty = u16;
216
217 fn disable(&mut self) {
218 unsafe {
219 (*$TIMX::ptr()).ccer.modify(|_, w| w.$ccxe().clear_bit());
220 }
221 }
222
223 fn enable(&mut self) {
224 unsafe {
225 let tim = &*$TIMX::ptr();
226 tim.$ccmrx_output().modify(|_, w| w.$ocxpe().set_bit().$ocxm().bits(6));
227 tim.ccer.modify(|_, w| w.$ccxe().set_bit());
228 $(
229 tim.ccer.modify(|_, w| w.$ccxne().bit(true));
230 )*
231 $(
232 tim.bdtr.modify(|_, w| w.$moe().set_bit());
233 )*
234 }
235 }
236
237 fn get_duty(&self) -> u16 {
238 unsafe { (*$TIMX::ptr()).$ccrx.read().$ccrx().bits() }
239 }
240
241 fn get_max_duty(&self) -> u16 {
242 unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
243 }
244
245 fn set_duty(&mut self, duty: u16) {
246 unsafe { (*$TIMX::ptr()).$ccrx.write(|w| w.$ccrx().bits(duty)) }
247 }
248 }
249
250 impl PwmPinMode for PwmPin<$TIMX, $CH>{
251 fn set_compare_mode(&mut self, mode: OutputCompareMode) {
252 unsafe {
253 let tim = &*$TIMX::ptr();
254 tim.$ccmrx_output().modify(|_, w| w.$ocxm().bits(mode as u8));
255 }
256 }
257 }
258 )+
259 };
260}
261
262pwm_advanced_hal! {
263 TIM1: (Channel1, cc1e: cc1ne, ccmr1_output, oc1pe, oc1m, ccr1, moe),
264 TIM1: (Channel2, cc2e: cc2ne, ccmr1_output, oc2pe, oc2m, ccr2, moe),
265 TIM1: (Channel3, cc3e: cc3ne, ccmr2_output, oc3pe, oc3m, ccr3, moe),
266 TIM1: (Channel4, cc4e, ccmr2_output, oc4pe, oc4m, ccr4, moe),
267 TIM14: (Channel1, cc1e, ccmr1_output, oc1pe, oc1m, ccr1),
268 TIM16: (Channel1, cc1e: cc1ne, ccmr1_output, oc1pe, oc1m, ccr1, moe),
269 TIM17: (Channel1, cc1e: cc1ne, ccmr1_output, oc1pe, oc1m, ccr1, moe),
270}
271
272#[cfg(any(feature = "stm32g070"))]
273pwm_advanced_hal! {
274 TIM15: (Channel1, cc1e: cc1ne, ccmr1_output, oc1pe, oc1m1, ccr1, moe),
275}
276
277#[cfg(any(feature = "stm32g071", feature = "stm32g081"))]
278pwm_advanced_hal! {
279 TIM15: (Channel1, cc1e: cc1ne, ccmr1_output, oc1pe, oc1m, ccr1, moe),
280}
281
282#[cfg(feature = "stm32g0x1")]
283pwm_hal! {
284 TIM2: (Channel1, cc1e, ccmr1_output, oc1pe, oc1m, ccr1, ccr1_l, ccr1_h),
285 TIM2: (Channel2, cc2e, ccmr1_output, oc2pe, oc2m, ccr2, ccr2_l, ccr2_h),
286 TIM2: (Channel3, cc3e, ccmr2_output, oc3pe, oc3m, ccr3, ccr3_l, ccr3_h),
287 TIM2: (Channel4, cc4e, ccmr2_output, oc4pe, oc4m, ccr4, ccr4_l, ccr4_h),
288 TIM3: (Channel1, cc1e, ccmr1_output, oc1pe, oc1m, ccr1, ccr1_l, ccr1_h),
289 TIM3: (Channel2, cc2e, ccmr1_output, oc2pe, oc2m, ccr2, ccr2_l, ccr2_h),
290 TIM3: (Channel3, cc3e, ccmr2_output, oc3pe, oc3m, ccr3, ccr3_l, ccr3_h),
291 TIM3: (Channel4, cc4e, ccmr2_output, oc4pe, oc4m, ccr4, ccr4_l, ccr4_h),
292}
293
294#[cfg(feature = "stm32g070")]
295pwm_hal! {
296 TIM3: (Channel1, cc1e, ccmr1_output, oc1pe, oc1m, ccr1, ccr1_l, ccr1_h),
297 TIM3: (Channel2, cc2e, ccmr1_output, oc2pe, oc2m, ccr2, ccr2_l, ccr2_h),
298 TIM3: (Channel3, cc3e, ccmr2_output, oc3pe, oc3m, ccr3, ccr3_l, ccr3_h),
299 TIM3: (Channel4, cc4e, ccmr2_output, oc4pe, oc4m, ccr4, ccr4_l, ccr4_h),
300}
301
302pwm! {
303 TIM1: (tim1, arr),
304 TIM3: (tim3, arr_l, arr_h),
305 TIM14: (tim14, arr),
306 TIM16: (tim16, arr),
307 TIM17: (tim17, arr),
308}
309
310#[cfg(feature = "stm32g0x1")]
311pwm! {
312 TIM2: (tim2, arr_l, arr_h),
313}
314
315#[cfg(any(feature = "stm32g070", feature = "stm32g071", feature = "stm32g081"))]
316pwm! {
317 TIM15: (tim15, arr),
318}
319
320#[cfg(feature = "stm32g0x1")]
321pwm_q! {
322 TIM1: tim1,
323}
324
325#[cfg(any(feature = "stm32g071", feature = "stm32g081"))]
326pwm_q! {
327 TIM15: tim15,
328}