use crate::gpio::{
Alternate2, ChangeSelectBits, Output, Pin,
Pin0, Pin1, Pin2, Pin3, Pin4, Pin7, P5, P4
};
use crate::hw_traits::timerb::{CCRn, Outmod};
use crate::timer::{CapCmpTimer3, CapCmpTimer7};
use core::marker::PhantomData;
use embedded_hal::PwmPin;
use msp430fr247x as pac;
pub use crate::timer::{
CapCmp, TimerConfig, TimerDiv, TimerExDiv, TimerPeriph, CCR0, CCR1, CCR2, CCR3, CCR4, CCR5,
CCR6,
};
#[doc(hidden)]
pub enum Alt {
Alt1,
Alt2,
}
pub trait PwmPeriph<C>: CapCmp<C> + CapCmp<CCR0> {
type Gpio: ChangeSelectBits;
#[doc(hidden)]
const ALT: Alt;
#[doc(hidden)]
fn to_alt(pin: &mut Self::Gpio) {
match Self::ALT {
Alt::Alt1 => pin.set_sel0(),
Alt::Alt2 => pin.set_sel1(),
}
}
#[doc(hidden)]
fn to_gpio(pin: &mut Self::Gpio) {
match Self::ALT {
Alt::Alt1 => pin.clear_sel0(),
Alt::Alt2 => pin.clear_sel1(),
}
}
}
impl PwmPeriph<CCR1> for pac::TB0 {
type Gpio = Pin<P4, Pin7, Alternate2<Output>>;
const ALT: Alt = Alt::Alt2;
}
impl PwmPeriph<CCR2> for pac::TB0 {
type Gpio = Pin<P5, Pin0, Alternate2<Output>>;
const ALT: Alt = Alt::Alt2;
}
impl PwmPeriph<CCR3> for pac::TB0 {
type Gpio = Pin<P5, Pin1, Alternate2<Output>>;
const ALT: Alt = Alt::Alt2;
}
impl PwmPeriph<CCR4> for pac::TB0 {
type Gpio = Pin<P5, Pin2, Alternate2<Output>>;
const ALT: Alt = Alt::Alt2;
}
impl PwmPeriph<CCR5> for pac::TB0 {
type Gpio = Pin<P4, Pin3, Alternate2<Output>>;
const ALT: Alt = Alt::Alt2;
}
impl PwmPeriph<CCR6> for pac::TB0 {
type Gpio = Pin<P4, Pin4, Alternate2<Output>>;
const ALT: Alt = Alt::Alt2;
}
fn setup_pwm<T: TimerPeriph>(timer: &T, config: TimerConfig<T>, period: u16) {
config.write_regs(timer);
CCRn::<CCR0>::set_ccrn(timer, period);
CCRn::<CCR0>::config_outmod(timer, Outmod::Toggle);
}
pub struct PwmParts3<T: CapCmpTimer3> {
pub pwm1: PwmUninit<T, CCR1>,
pub pwm2: PwmUninit<T, CCR2>,
}
impl<T: CapCmpTimer3> PwmParts3<T> {
pub fn new(timer: T, config: TimerConfig<T>, period: u16) -> Self {
setup_pwm(&timer, config, period);
CCRn::<CCR1>::config_outmod(&timer, Outmod::ResetSet);
CCRn::<CCR2>::config_outmod(&timer, Outmod::ResetSet);
timer.upmode();
Self {
pwm1: PwmUninit::new(),
pwm2: PwmUninit::new(),
}
}
}
pub struct PwmParts7<T: CapCmpTimer7> {
pub pwm1: PwmUninit<T, CCR1>,
pub pwm2: PwmUninit<T, CCR2>,
pub pwm3: PwmUninit<T, CCR3>,
pub pwm4: PwmUninit<T, CCR4>,
pub pwm5: PwmUninit<T, CCR5>,
pub pwm6: PwmUninit<T, CCR6>,
}
impl<T: CapCmpTimer7> PwmParts7<T> {
pub fn new(timer: T, config: TimerConfig<T>, period: u16) -> Self {
setup_pwm(&timer, config, period);
CCRn::<CCR1>::config_outmod(&timer, Outmod::ResetSet);
CCRn::<CCR2>::config_outmod(&timer, Outmod::ResetSet);
CCRn::<CCR3>::config_outmod(&timer, Outmod::ResetSet);
CCRn::<CCR4>::config_outmod(&timer, Outmod::ResetSet);
CCRn::<CCR5>::config_outmod(&timer, Outmod::ResetSet);
CCRn::<CCR6>::config_outmod(&timer, Outmod::ResetSet);
timer.upmode();
Self {
pwm1: PwmUninit::new(),
pwm2: PwmUninit::new(),
pwm3: PwmUninit::new(),
pwm4: PwmUninit::new(),
pwm5: PwmUninit::new(),
pwm6: PwmUninit::new(),
}
}
}
pub struct PwmUninit<T, C>(PhantomData<T>, PhantomData<C>);
impl<T: PwmPeriph<C>, C> PwmUninit<T, C> {
pub fn init(self, pin: T::Gpio) -> Pwm<T, C> {
Pwm {
_timer: PhantomData,
_ccrn: PhantomData,
pin,
}
}
}
impl<T, C> PwmUninit<T, C> {
fn new() -> Self {
Self(PhantomData, PhantomData)
}
}
pub struct Pwm<T: PwmPeriph<C>, C> {
_timer: PhantomData<T>,
_ccrn: PhantomData<C>,
pin: T::Gpio,
}
impl<T: PwmPeriph<C>, C> PwmPin for Pwm<T, C> {
type Duty = u16;
#[inline]
fn set_duty(&mut self, duty: Self::Duty) {
let timer = unsafe { T::steal() };
CCRn::<C>::set_ccrn(&timer, duty);
}
#[inline]
fn get_duty(&self) -> Self::Duty {
let timer = unsafe { T::steal() };
CCRn::<C>::get_ccrn(&timer)
}
#[inline]
fn get_max_duty(&self) -> Self::Duty {
let timer = unsafe { T::steal() };
CCRn::<CCR0>::get_ccrn(&timer)
}
#[inline]
fn disable(&mut self) {
T::to_gpio(&mut self.pin);
}
#[inline]
fn enable(&mut self) {
T::to_alt(&mut self.pin);
}
}