use crate::pac::{OCMP1, OCMP2, OCMP3, OCMP4, OCMP5};
use crate::pac::{TMR2, TMR3};
use core::convert::Infallible;
use embedded_hal::pwm::{ErrorType, SetDutyCycle};
use embedded_hal_0_2::PwmPin;
use core::marker::PhantomData;
pub struct TimebaseUninit;
pub struct Timebase16even;
pub struct Timebase16odd;
pub struct Timebase32;
pub enum OcConfig {
Off,
RisingSlope(u32),
FallingSlope(u32),
Toggle(u32),
SinglePulse(u32, u32),
ContinuousPulses(u32, u32),
}
impl OcConfig {
const fn ocm_bits(&self) -> u8 {
match self {
Self::Off => 0b000,
Self::RisingSlope(_) => 0b001,
Self::FallingSlope(_) => 0b010,
Self::Toggle(_) => 0b011,
Self::SinglePulse(_, _) => 0b100,
Self::ContinuousPulses(_, _) => 0b101,
}
}
}
pub struct Oc<OCMP, TIMEBASE> {
ocmp: OCMP,
_timebase: PhantomData<TIMEBASE>,
}
macro_rules! oc_impl {
($constructor: ident, $ocmp: ty) => {
impl Oc<$ocmp, TimebaseUninit> {
pub fn $constructor(ocmp: $ocmp, stop_in_idle_mode: bool) -> Self {
ocmp.cont
.write(|w| w.on().clear_bit().sidl().bit(stop_in_idle_mode));
Self {
ocmp,
_timebase: PhantomData,
}
}
}
impl<TIMEBASE> Oc<$ocmp, TIMEBASE> {
pub fn timebase16even(self) -> Oc<$ocmp, Timebase16even> {
self.ocmp
.cont
.modify(|_, w| w.octsel().bit(false).oc32().bit(false));
Oc {
ocmp: self.ocmp,
_timebase: PhantomData,
}
}
pub fn timebase16odd(self) -> Oc<$ocmp, Timebase16odd> {
self.ocmp
.cont
.modify(|_, w| w.octsel().bit(true).oc32().bit(false));
self.ocmp.contset.write(|w| w.on().set_bit());
Oc {
ocmp: self.ocmp,
_timebase: PhantomData,
}
}
pub fn timebase32(self) -> Oc<$ocmp, Timebase32> {
self.ocmp
.cont
.modify(|_, w| w.octsel().bit(false).oc32().bit(true));
self.ocmp.contset.write(|w| w.on().set_bit());
Oc {
ocmp: self.ocmp,
_timebase: PhantomData,
}
}
pub fn free(self) -> $ocmp {
self.ocmp.cont.write(|w| w.on().clear_bit());
self.ocmp
}
#[inline(never)] pub fn turn_off(&mut self) {
self.ocmp.contclr.write(|w| w.on().set_bit());
}
}
impl Oc<$ocmp, Timebase16even> {
pub fn turn_on(&mut self, config: OcConfig) {
self.ocmp
.cont
.modify(|_, w| unsafe { w.ocm().bits(config.ocm_bits()) });
let (r, rs) = match config {
OcConfig::RisingSlope(r) | OcConfig::FallingSlope(r) | OcConfig::Toggle(r) => {
(r, 0)
}
OcConfig::SinglePulse(r, rs) | OcConfig::ContinuousPulses(r, rs) => (r, rs),
OcConfig::Off => (0, 0),
};
self.ocmp.r.write(|w| unsafe { w.r().bits(r) });
self.ocmp.rs.write(|w| unsafe { w.rs().bits(rs) });
self.ocmp.contset.write(|w| w.on().set_bit());
}
}
impl Oc<$ocmp, Timebase16odd> {
pub fn turn_on(&mut self, config: OcConfig) {
self.ocmp
.cont
.modify(|_, w| unsafe { w.ocm().bits(config.ocm_bits()) });
let (r, rs) = match config {
OcConfig::RisingSlope(r) | OcConfig::FallingSlope(r) | OcConfig::Toggle(r) => {
(r, 0)
}
OcConfig::SinglePulse(r, rs) | OcConfig::ContinuousPulses(r, rs) => (r, rs),
OcConfig::Off => (0, 0),
};
self.ocmp.r.write(|w| unsafe { w.r().bits(r) });
self.ocmp.rs.write(|w| unsafe { w.rs().bits(rs) });
self.ocmp.contset.write(|w| w.on().set_bit());
}
}
impl Oc<$ocmp, Timebase32> {
pub fn turn_on(&mut self, config: OcConfig) {
self.ocmp
.cont
.modify(|_, w| unsafe { w.ocm().bits(config.ocm_bits()) });
let (r, rs) = match config {
OcConfig::RisingSlope(r) | OcConfig::FallingSlope(r) | OcConfig::Toggle(r) => {
(r, 0)
}
OcConfig::SinglePulse(r, rs) | OcConfig::ContinuousPulses(r, rs) => (r, rs),
OcConfig::Off => (0, 0),
};
self.ocmp.r.write(|w| unsafe { w.r().bits(r) });
self.ocmp.rs.write(|w| unsafe { w.rs().bits(rs) });
self.ocmp.contset.write(|w| w.on().set_bit());
}
}
};
}
oc_impl!(oc1, OCMP1);
oc_impl!(oc2, OCMP2);
oc_impl!(oc3, OCMP3);
oc_impl!(oc4, OCMP4);
oc_impl!(oc5, OCMP5);
pub struct Pwm<OCMP, TIMEBASE> {
ocmp: OCMP,
_timebase: PhantomData<TIMEBASE>,
}
macro_rules! pwm_impl {
($constructor: ident, $ocmp: ty, $timer_even: ty, $timer_odd: ty) => {
impl Pwm<$ocmp, TimebaseUninit> {
pub fn $constructor(
ocmp: $ocmp,
enable_fault_pin: bool,
stop_in_idle_mode: bool,
) -> Self {
let ocm = match enable_fault_pin {
false => 0b110,
true => 0b111,
};
ocmp.cont
.write(|w| unsafe { w.sidl().bit(stop_in_idle_mode).ocm().bits(ocm) });
Pwm {
ocmp,
_timebase: PhantomData,
}
}
}
impl<TIMEBASE> Pwm<$ocmp, TIMEBASE> {
pub fn timebase16even(self) -> Pwm<$ocmp, Timebase16even> {
self.ocmp
.cont
.modify(|_, w| w.octsel().bit(false).oc32().bit(false).on().bit(true));
Pwm {
ocmp: self.ocmp,
_timebase: PhantomData,
}
}
pub fn timebase16odd(self) -> Pwm<$ocmp, Timebase16odd> {
self.ocmp
.cont
.modify(|_, w| w.octsel().bit(true).oc32().bit(false).on().bit(true));
self.ocmp.contset.write(|w| w.on().set_bit());
Pwm {
ocmp: self.ocmp,
_timebase: PhantomData,
}
}
pub fn timebase32(self) -> Pwm<$ocmp, Timebase32> {
self.ocmp
.cont
.modify(|_, w| w.octsel().bit(false).oc32().bit(true).on().bit(true));
self.ocmp.contset.write(|w| w.on().set_bit());
Pwm {
ocmp: self.ocmp,
_timebase: PhantomData,
}
}
pub fn fault(&self) -> bool {
self.ocmp.cont.read().ocflt().bit()
}
pub fn on(&mut self) {
self.ocmp.contset.write(|w| w.on().set_bit());
}
pub fn off(&mut self) {
self.ocmp.contclr.write(|w| w.on().set_bit());
}
pub fn free(self) -> $ocmp {
self.ocmp.cont.write(|w| w.on().clear_bit());
self.ocmp
}
}
impl PwmPin for Pwm<$ocmp, Timebase16even> {
type Duty = u32;
fn enable(&mut self) {
self.ocmp.contset.write(|w| w.on().set_bit());
}
fn disable(&mut self) {
self.ocmp.contclr.write(|w| w.on().set_bit());
}
fn get_duty(&self) -> Self::Duty {
self.ocmp.rs.read().rs().bits() as Self::Duty
}
fn set_duty(&mut self, duty: Self::Duty) {
self.ocmp.rs.write(|w| unsafe { w.rs().bits(duty) });
}
fn get_max_duty(&self) -> Self::Duty {
unsafe { (*<$timer_even>::ptr()).pr.read().pr().bits() + 1 }
}
}
impl PwmPin for Pwm<$ocmp, Timebase16odd> {
type Duty = u32;
fn enable(&mut self) {
self.ocmp.contset.write(|w| w.on().set_bit());
}
fn disable(&mut self) {
self.ocmp.contclr.write(|w| w.on().set_bit());
}
fn get_duty(&self) -> Self::Duty {
self.ocmp.rs.read().rs().bits() as Self::Duty
}
fn set_duty(&mut self, duty: Self::Duty) {
self.ocmp.rs.write(|w| unsafe { w.rs().bits(duty) });
}
fn get_max_duty(&self) -> Self::Duty {
unsafe { (*<$timer_odd>::ptr()).pr.read().pr().bits() + 1 }
}
}
impl PwmPin for Pwm<$ocmp, Timebase32> {
type Duty = u32;
fn enable(&mut self) {
self.ocmp.contset.write(|w| w.on().set_bit());
}
fn disable(&mut self) {
self.ocmp.contclr.write(|w| w.on().set_bit());
}
fn get_duty(&self) -> Self::Duty {
self.ocmp.rs.read().rs().bits() as Self::Duty
}
fn set_duty(&mut self, duty: Self::Duty) {
self.ocmp.rs.write(|w| unsafe { w.rs().bits(duty) });
}
fn get_max_duty(&self) -> Self::Duty {
let pr = unsafe { (*<$timer_even>::ptr()).pr.read().pr().bits() };
pr.saturating_add(1)
}
}
impl<TIMEBASE> ErrorType for Pwm<$ocmp, TIMEBASE> {
type Error = Infallible;
}
impl SetDutyCycle for Pwm<$ocmp, Timebase16even> {
fn max_duty_cycle(&self) -> u16 {
unsafe { (*<$timer_even>::ptr()).pr.read().pr().bits() as u16 + 1 }
}
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
self.ocmp.rs.write(|w| unsafe { w.rs().bits(duty as u32) });
Ok(())
}
}
impl SetDutyCycle for Pwm<$ocmp, Timebase16odd> {
fn max_duty_cycle(&self) -> u16 {
unsafe { (*<$timer_odd>::ptr()).pr.read().pr().bits() as u16 + 1 }
}
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
self.ocmp.rs.write(|w| unsafe { w.rs().bits(duty as u32) });
Ok(())
}
}
};
}
pwm_impl!(oc1, OCMP1, TMR2, TMR3);
pwm_impl!(oc2, OCMP2, TMR2, TMR3);
pwm_impl!(oc3, OCMP3, TMR2, TMR3);
pwm_impl!(oc4, OCMP4, TMR2, TMR3);
pwm_impl!(oc5, OCMP5, TMR2, TMR3);