use core::marker::PhantomData; use core::mem; use cast::{u16, u32}; use hal; use stm32::{TIM2, TIM3, TIM4}; use afio::MAPR; use bb; use gpio::gpioa::{PA0, PA1, PA2, PA3, PA6, PA7}; use gpio::gpiob::{PB0, PB1, PB6, PB7, PB8, PB9}; use gpio::{Alternate, PushPull}; use rcc::{APB1, Clocks}; use time::Hertz; pub trait Pins { const REMAP: u8; const C1: bool; const C2: bool; const C3: bool; const C4: bool; type Channels; } impl Pins for ( PA0>, PA1>, PA2>, PA3>, ) { const REMAP: u8 = 0b00; const C1: bool = true; const C2: bool = true; const C3: bool = true; const C4: bool = true; type Channels = (Pwm, Pwm, Pwm, Pwm); } impl Pins for PA0> { const REMAP: u8 = 0b00; const C1: bool = true; const C2: bool = false; const C3: bool = false; const C4: bool = false; type Channels = Pwm; } impl Pins for ( PA6>, PA7>, PB0>, PB1>, ) { const REMAP: u8 = 0b00; const C1: bool = true; const C2: bool = true; const C3: bool = true; const C4: bool = true; type Channels = (Pwm, Pwm, Pwm, Pwm); } impl Pins for (PB0>, PB1>) { const REMAP: u8 = 0b00; const C1: bool = false; const C2: bool = false; const C3: bool = true; const C4: bool = true; type Channels = (Pwm, Pwm); } impl Pins for ( PB6>, PB7>, PB8>, PB9>, ) { const REMAP: u8 = 0b0; const C1: bool = true; const C2: bool = true; const C3: bool = true; const C4: bool = true; type Channels = (Pwm, Pwm, Pwm, Pwm); } pub trait PwmExt: Sized { fn pwm( self, PINS, mapr: &mut MAPR, frequency: T, clocks: Clocks, apb: &mut APB1, ) -> PINS::Channels where PINS: Pins, T: Into; } impl PwmExt for TIM2 { fn pwm( self, _pins: PINS, mapr: &mut MAPR, freq: T, clocks: Clocks, apb: &mut APB1, ) -> PINS::Channels where PINS: Pins, T: Into, { mapr.mapr() .modify(|_, w| unsafe { w.tim2_remap().bits(PINS::REMAP) }); tim2(self, _pins, freq.into(), clocks, apb) } } impl PwmExt for TIM3 { fn pwm( self, _pins: PINS, mapr: &mut MAPR, freq: T, clocks: Clocks, apb: &mut APB1, ) -> PINS::Channels where PINS: Pins, T: Into, { mapr.mapr() .modify(|_, w| unsafe { w.tim3_remap().bits(PINS::REMAP) }); tim3(self, _pins, freq.into(), clocks, apb) } } impl PwmExt for TIM4 { fn pwm( self, _pins: PINS, mapr: &mut MAPR, freq: T, clocks: Clocks, apb: &mut APB1, ) -> PINS::Channels where PINS: Pins, T: Into, { mapr.mapr() .modify(|_, w| w.tim4_remap().bit(PINS::REMAP == 1)); tim4(self, _pins, freq.into(), clocks, apb) } } pub struct Pwm { _channel: PhantomData, _tim: PhantomData, } pub struct C1; pub struct C2; pub struct C3; pub struct C4; macro_rules! hal { ($($TIMX:ident: ($timX:ident, $timXen:ident, $timXrst:ident),)+) => { $( fn $timX( tim: $TIMX, _pins: PINS, freq: Hertz, clocks: Clocks, apb: &mut APB1, ) -> PINS::Channels where PINS: Pins<$TIMX>, { apb.enr().modify(|_, w| w.$timXen().set_bit()); apb.rstr().modify(|_, w| w.$timXrst().set_bit()); apb.rstr().modify(|_, w| w.$timXrst().clear_bit()); if PINS::C1 { tim.ccmr1_output .modify(|_, w| w.oc1pe().set_bit().oc1m().bits(6)); } if PINS::C2 { tim.ccmr1_output .modify(|_, w| w.oc2pe().set_bit().oc2m().bits(6)); } if PINS::C3 { tim.ccmr2_output .modify(|_, w| w.oc3pe().set_bit().oc3m().bits(6)); } if PINS::C4 { tim.ccmr2_output .modify(|_, w| w.oc4pe().set_bit().oc4m().bits(6)); } let clk = clocks.pclk1().0 * if clocks.ppre1() == 1 { 1 } else { 2 }; let freq = freq.0; let ticks = clk / freq; let psc = u16(ticks / (1 << 16)).unwrap(); tim.psc.write(|w| w.psc().bits(psc)); let arr = u16(ticks / u32(psc + 1)).unwrap(); tim.arr.write(|w| w.arr().bits(arr)); tim.cr1.write(|w| unsafe { w.cms() .bits(0b00) .dir() .clear_bit() .opm() .clear_bit() .cen() .set_bit() }); unsafe { mem::uninitialized() } } impl hal::PwmPin for Pwm<$TIMX, C1> { type Duty = u16; fn disable(&mut self) { unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) } } fn enable(&mut self) { unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) } } fn get_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).ccr1.read().ccr1().bits() } } fn get_max_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } } fn set_duty(&mut self, duty: u16) { unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr1().bits(duty)) } } } impl hal::PwmPin for Pwm<$TIMX, C2> { type Duty = u16; fn disable(&mut self) { unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) } } fn enable(&mut self) { unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) } } fn get_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).ccr2.read().ccr2().bits() } } fn get_max_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } } fn set_duty(&mut self, duty: u16) { unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr2().bits(duty)) } } } impl hal::PwmPin for Pwm<$TIMX, C3> { type Duty = u16; fn disable(&mut self) { unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) } } fn enable(&mut self) { unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) } } fn get_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).ccr3.read().ccr3().bits() } } fn get_max_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } } fn set_duty(&mut self, duty: u16) { unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr3().bits(duty)) } } } impl hal::PwmPin for Pwm<$TIMX, C4> { type Duty = u16; fn disable(&mut self) { unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) } } fn enable(&mut self) { unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) } } fn get_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).ccr4.read().ccr4().bits() } } fn get_max_duty(&self) -> u16 { unsafe { (*$TIMX::ptr()).arr.read().arr().bits() } } fn set_duty(&mut self, duty: u16) { unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr4().bits(duty)) } } } )+ } } hal! { TIM2: (tim2, tim2en, tim2rst), TIM3: (tim3, tim3en, tim3rst), TIM4: (tim4, tim4en, tim4rst), }