Skip to content

Commit 2268f0f

Browse files
committed
TIM1 PWM complementary channels
1 parent 8f410db commit 2268f0f

File tree

2 files changed

+303
-1
lines changed

2 files changed

+303
-1
lines changed

src/pwm.rs

Lines changed: 294 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,28 @@ use embedded_hal as hal;
88

99
pub trait Pins<TIM, P> {
1010
const C1: bool = false;
11+
const C1N: bool = false;
1112
const C2: bool = false;
13+
const C2N: bool = false;
1214
const C3: bool = false;
15+
const C3N: bool = false;
1316
const C4: bool = false;
1417
type Channels;
1518
}
1619
use crate::timers::PinC1;
20+
use crate::timers::PinC1N;
1721
use crate::timers::PinC2;
22+
use crate::timers::PinC2N;
1823
use crate::timers::PinC3;
24+
use crate::timers::PinC3N;
1925
use crate::timers::PinC4;
2026

2127
pub struct C1;
28+
pub struct C1N;
2229
pub struct C2;
30+
pub struct C2N;
2331
pub struct C3;
32+
pub struct C3N;
2433
pub struct C4;
2534

2635
pub struct PwmChannels<TIM, CHANNELS> {
@@ -45,6 +54,9 @@ macro_rules! pins_impl {
4554

4655
pins_impl!(
4756
(P1, P2, P3, P4), (PinC1, PinC2, PinC3, PinC4), (C1, C2, C3, C4);
57+
(P1, P1N, P2, P2N), (PinC1, PinC1N, PinC2, PinC2N), (C1, C1N, C2, C2N);
58+
(P2, P2N, P3, P3N), (PinC2, PinC2N, PinC3, PinC3N), (C2, C2N, C3, C3N);
59+
(P1, P1N, P3, P3N), (PinC1, PinC1N, PinC3, PinC3N), (C1, C1N, C3, C3N);
4860
(P2, P3, P4), (PinC2, PinC3, PinC4), (C2, C3, C4);
4961
(P1, P3, P4), (PinC1, PinC3, PinC4), (C1, C3, C4);
5062
(P1, P2, P4), (PinC1, PinC2, PinC4), (C1, C2, C4);
@@ -55,6 +67,9 @@ pins_impl!(
5567
(P1, P4), (PinC1, PinC4), (C1, C4);
5668
(P1, P3), (PinC1, PinC3), (C1, C3);
5769
(P1, P2), (PinC1, PinC2), (C1, C2);
70+
(P1, P1N), (PinC1, PinC1N), (C1, C1N);
71+
(P2, P2N), (PinC2, PinC2N), (C2, C2N);
72+
(P3, P3N), (PinC3, PinC3N), (C3, C3N);
5873
(P1), (PinC1), (C1);
5974
(P2), (PinC2), (C2);
6075
(P3), (PinC3), (C3);
@@ -291,6 +306,282 @@ macro_rules! pwm_4_channels {
291306
};
292307
}
293308

309+
// Timer with four output channels three with complements 16 Bit Timer
310+
macro_rules! pwm_4_channels_with_3_complementary_outputs {
311+
($($TIMX:ident: ($timX:ident, $timXen:ident, $timXrst:ident, $apbenr:ident, $apbrstr:ident),)+) => {
312+
$(
313+
pub fn $timX<P, PINS, T>(tim: $TIMX, _pins: PINS, rcc: &mut Rcc, freq: T) -> PINS::Channels
314+
where
315+
PINS: Pins<$TIMX, P>,
316+
T: Into<Hertz>,
317+
{
318+
// enable and reset peripheral to a clean slate state
319+
rcc.regs.$apbenr.modify(|_, w| w.$timXen().set_bit());
320+
rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().set_bit());
321+
rcc.regs.$apbrstr.modify(|_, w| w.$timXrst().clear_bit());
322+
323+
if PINS::C1N | PINS::C1N | PINS::C1N {
324+
tim.bdtr.modify(|_, w| w.ossr().set_bit());
325+
}
326+
if PINS::C1 {
327+
tim.ccmr1_output()
328+
.modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1() );
329+
}
330+
if PINS::C2 {
331+
tim.ccmr1_output()
332+
.modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1() );
333+
}
334+
if PINS::C3 {
335+
tim.ccmr2_output()
336+
.modify(|_, w| w.oc3pe().set_bit().oc3m().pwm_mode1() );
337+
}
338+
if PINS::C4 {
339+
tim.ccmr2_output()
340+
.modify(|_, w| w.oc4pe().set_bit().oc4m().pwm_mode1() );
341+
}
342+
343+
// If pclk is prescaled from hclk, the frequency fed into the timers is doubled
344+
let tclk = if rcc.clocks.hclk().0 == rcc.clocks.pclk().0 {
345+
rcc.clocks.pclk().0
346+
} else {
347+
rcc.clocks.pclk().0 * 2
348+
};
349+
let ticks = tclk / freq.into().0;
350+
351+
let psc = u16((ticks - 1) / (1 << 16)).unwrap();
352+
tim.psc.write(|w| w.psc().bits(psc) );
353+
let arr = u16(ticks / u32(psc + 1)).unwrap();
354+
tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
355+
356+
// enable auto-reload preload
357+
tim.cr1.modify(|_, w| w.arpe().set_bit());
358+
359+
// Trigger update event to load the registers
360+
tim.cr1.modify(|_, w| w.urs().set_bit());
361+
tim.egr.write(|w| w.ug().set_bit());
362+
tim.cr1.modify(|_, w| w.urs().clear_bit());
363+
364+
brk!($TIMX, tim);
365+
tim.cr1.write(|w|
366+
w.cms()
367+
.bits(0b00)
368+
.dir()
369+
.clear_bit()
370+
.opm()
371+
.clear_bit()
372+
.cen()
373+
.set_bit()
374+
);
375+
//NOTE(unsafe) `PINS::Channels` is a ZST
376+
unsafe { MaybeUninit::uninit().assume_init() }
377+
}
378+
379+
impl hal::PwmPin for PwmChannels<$TIMX, C1> {
380+
type Duty = u16;
381+
382+
//NOTE(unsafe) atomic write with no side effects
383+
fn disable(&mut self) {
384+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc1e().clear_bit()) };
385+
}
386+
387+
//NOTE(unsafe) atomic write with no side effects
388+
fn enable(&mut self) {
389+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc1e().set_bit()) };
390+
}
391+
392+
//NOTE(unsafe) atomic read with no side effects
393+
fn get_duty(&self) -> u16 {
394+
unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 }
395+
}
396+
397+
//NOTE(unsafe) atomic read with no side effects
398+
fn get_max_duty(&self) -> u16 {
399+
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }
400+
}
401+
402+
//NOTE(unsafe) atomic write with no side effects
403+
fn set_duty(&mut self, duty: u16) {
404+
unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) }
405+
}
406+
}
407+
408+
impl hal::PwmPin for PwmChannels<$TIMX, C1N> {
409+
type Duty = u16;
410+
411+
//NOTE(unsafe) atomic write with no side effects
412+
fn disable(&mut self) {
413+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc1ne().clear_bit()) };
414+
}
415+
416+
//NOTE(unsafe) atomic write with no side effects
417+
fn enable(&mut self) {
418+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc1ne().set_bit()) };
419+
}
420+
421+
//NOTE(unsafe) atomic read with no side effects
422+
fn get_duty(&self) -> u16 {
423+
unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() as u16 }
424+
}
425+
426+
//NOTE(unsafe) atomic read with no side effects
427+
fn get_max_duty(&self) -> u16 {
428+
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }
429+
}
430+
431+
//NOTE(unsafe) atomic write with no side effects
432+
fn set_duty(&mut self, duty: u16) {
433+
unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty.into())) }
434+
}
435+
}
436+
437+
impl hal::PwmPin for PwmChannels<$TIMX, C2> {
438+
type Duty = u16;
439+
440+
//NOTE(unsafe) atomic write with no side effects
441+
fn disable(&mut self) {
442+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc2e().clear_bit()) };
443+
}
444+
445+
//NOTE(unsafe) atomic write with no side effects
446+
fn enable(&mut self) {
447+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc2e().set_bit()) };
448+
}
449+
450+
//NOTE(unsafe) atomic read with no side effects
451+
fn get_duty(&self) -> u16 {
452+
unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() as u16 }
453+
}
454+
455+
//NOTE(unsafe) atomic read with no side effects
456+
fn get_max_duty(&self) -> u16 {
457+
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }
458+
}
459+
460+
//NOTE(unsafe) atomic write with no side effects
461+
fn set_duty(&mut self, duty: u16) {
462+
unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty.into())) }
463+
}
464+
}
465+
466+
impl hal::PwmPin for PwmChannels<$TIMX, C2N> {
467+
type Duty = u16;
468+
469+
//NOTE(unsafe) atomic write with no side effects
470+
fn disable(&mut self) {
471+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc2ne().clear_bit()) };
472+
}
473+
474+
//NOTE(unsafe) atomic write with no side effects
475+
fn enable(&mut self) {
476+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc2ne().set_bit()) };
477+
}
478+
479+
//NOTE(unsafe) atomic read with no side effects
480+
fn get_duty(&self) -> u16 {
481+
unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() as u16 }
482+
}
483+
484+
//NOTE(unsafe) atomic read with no side effects
485+
fn get_max_duty(&self) -> u16 {
486+
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }
487+
}
488+
489+
//NOTE(unsafe) atomic write with no side effects
490+
fn set_duty(&mut self, duty: u16) {
491+
unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty.into())) }
492+
}
493+
}
494+
495+
impl hal::PwmPin for PwmChannels<$TIMX, C3> {
496+
type Duty = u16;
497+
498+
//NOTE(unsafe) atomic write with no side effects
499+
fn disable(&mut self) {
500+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc3e().clear_bit()) };
501+
}
502+
503+
//NOTE(unsafe) atomic write with no side effects
504+
fn enable(&mut self) {
505+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc3e().set_bit()) };
506+
}
507+
508+
//NOTE(unsafe) atomic read with no side effects
509+
fn get_duty(&self) -> u16 {
510+
unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() as u16 }
511+
}
512+
513+
//NOTE(unsafe) atomic read with no side effects
514+
fn get_max_duty(&self) -> u16 {
515+
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }
516+
}
517+
518+
//NOTE(unsafe) atomic write with no side effects
519+
fn set_duty(&mut self, duty: u16) {
520+
unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty.into())) }
521+
}
522+
}
523+
524+
impl hal::PwmPin for PwmChannels<$TIMX, C3N> {
525+
type Duty = u16;
526+
527+
//NOTE(unsafe) atomic write with no side effects
528+
fn disable(&mut self) {
529+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc3ne().clear_bit()) };
530+
}
531+
532+
//NOTE(unsafe) atomic write with no side effects
533+
fn enable(&mut self) {
534+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc3ne().set_bit()) };
535+
}
536+
537+
//NOTE(unsafe) atomic read with no side effects
538+
fn get_duty(&self) -> u16 {
539+
unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() as u16 }
540+
}
541+
542+
//NOTE(unsafe) atomic read with no side effects
543+
fn get_max_duty(&self) -> u16 {
544+
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }
545+
}
546+
547+
//NOTE(unsafe) atomic write with no side effects
548+
fn set_duty(&mut self, duty: u16) {
549+
unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty.into())) }
550+
}
551+
}
552+
553+
impl hal::PwmPin for PwmChannels<$TIMX, C4> {
554+
type Duty = u16;
555+
556+
//NOTE(unsafe) atomic write with no side effects
557+
fn disable(&mut self) {
558+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc4e().clear_bit()) };
559+
}
560+
561+
//NOTE(unsafe) atomic write with no side effects
562+
fn enable(&mut self) {
563+
unsafe { (*($TIMX::ptr())).ccer.modify(|_, w| w.cc4e().set_bit()) };
564+
}
565+
566+
//NOTE(unsafe) atomic read with no side effects
567+
fn get_duty(&self) -> u16 {
568+
unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() as u16 }
569+
}
570+
571+
//NOTE(unsafe) atomic read with no side effects
572+
fn get_max_duty(&self) -> u16 {
573+
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() as u16 }
574+
}
575+
576+
//NOTE(unsafe) atomic write with no side effects
577+
fn set_duty(&mut self, duty: u16) {
578+
unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty.into())) }
579+
}
580+
}
581+
)+
582+
};
583+
}
584+
294585
// General purpose timer with two output channels
295586
#[cfg(any(
296587
feature = "stm32f030x8",
@@ -583,10 +874,12 @@ macro_rules! pwm_1_channel_with_complementary_outputs {
583874
use crate::pac::*;
584875

585876
pwm_4_channels!(
586-
TIM1: (tim1, tim1en, tim1rst, apb2enr, apb2rstr),
587877
TIM3: (tim3, tim3en, tim3rst, apb1enr, apb1rstr),
588878
);
589879

880+
pwm_4_channels_with_3_complementary_outputs!(
881+
TIM1: (tim1, tim1en, tim1rst, apb2enr, apb2rstr),
882+
);
590883
pwm_1_channel!(TIM14: (tim14, tim14en, tim14rst, apb1enr, apb1rstr),);
591884

592885
pwm_1_channel_with_complementary_outputs!(

src/timers.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,11 @@ use crate::gpio::{gpioa::*, gpiob::*, Alternate};
285285

286286
// Output channels marker traits
287287
pub trait PinC1<TIM> {}
288+
pub trait PinC1N<TIM> {}
288289
pub trait PinC2<TIM> {}
290+
pub trait PinC2N<TIM> {}
289291
pub trait PinC3<TIM> {}
292+
pub trait PinC3N<TIM> {}
290293
pub trait PinC4<TIM> {}
291294

292295
macro_rules! channel_impl {
@@ -299,8 +302,14 @@ macro_rules! channel_impl {
299302

300303
channel_impl!(
301304
TIM1, PinC1, PA8, Alternate<AF2>;
305+
TIM1, PinC1N, PA7, Alternate<AF2>;
306+
TIM1, PinC1N, PB13, Alternate<AF2>;
302307
TIM1, PinC2, PA9, Alternate<AF2>;
308+
TIM1, PinC2N, PB0, Alternate<AF2>;
309+
TIM1, PinC2N, PB14, Alternate<AF2>;
303310
TIM1, PinC3, PA10, Alternate<AF2>;
311+
TIM1, PinC3N, PB1, Alternate<AF2>;
312+
TIM1, PinC3N, PB15, Alternate<AF2>;
304313
TIM1, PinC4, PA11, Alternate<AF2>;
305314

306315
TIM3, PinC1, PA6, Alternate<AF1>;

0 commit comments

Comments
 (0)