use core::marker::PhantomData;
use crate::{
gpio::{bank0::*, FunctionPwm, Pin, PinId, PinMode, ValidPinMode},
resets::SubsystemReset,
typelevel::Sealed,
};
use embedded_hal::PwmPin;
use pac::PWM;
use crate::atomic_register_access::{write_bitmask_clear, write_bitmask_set};
pub mod dyn_slice;
pub use dyn_slice::*;
mod reg;
use reg::RegisterInterface;
pub trait ChannelId: Sealed {
const DYN: DynChannelId;
}
pub enum A {}
pub enum B {}
impl ChannelId for A {
const DYN: DynChannelId = DynChannelId::A;
}
impl ChannelId for B {
const DYN: DynChannelId = DynChannelId::B;
}
impl Sealed for A {}
impl Sealed for B {}
pub struct FreeRunning;
pub struct InputHighRunning;
pub struct CountRisingEdge;
pub struct CountFallingEdge;
pub trait ValidSliceMode<I: SliceId>: Sealed {}
pub trait ValidSliceInputMode<I: SliceId>: Sealed + ValidSliceMode<I> {}
pub trait SliceMode: Sealed + Sized {
const DYN: DynSliceMode;
}
impl Sealed for FreeRunning {}
impl SliceMode for FreeRunning {
const DYN: DynSliceMode = DynSliceMode::FreeRunning;
}
impl Sealed for InputHighRunning {}
impl SliceMode for InputHighRunning {
const DYN: DynSliceMode = DynSliceMode::InputHighRunning;
}
impl Sealed for CountRisingEdge {}
impl SliceMode for CountRisingEdge {
const DYN: DynSliceMode = DynSliceMode::CountRisingEdge;
}
impl Sealed for CountFallingEdge {}
impl SliceMode for CountFallingEdge {
const DYN: DynSliceMode = DynSliceMode::CountFallingEdge;
}
impl<I: SliceId> ValidSliceMode<I> for FreeRunning {}
impl<I: SliceId> ValidSliceMode<I> for InputHighRunning {}
impl<I: SliceId> ValidSliceMode<I> for CountRisingEdge {}
impl<I: SliceId> ValidSliceMode<I> for CountFallingEdge {}
impl<I: SliceId> ValidSliceInputMode<I> for InputHighRunning {}
impl<I: SliceId> ValidSliceInputMode<I> for CountRisingEdge {}
impl<I: SliceId> ValidSliceInputMode<I> for CountFallingEdge {}
pub trait SliceId: Sealed {
const DYN: DynSliceId;
type Reset;
}
macro_rules! slice_id {
($Id:ident, $NUM:literal, $reset : ident) => {
$crate::paste::paste! {
#[doc = "Slice ID representing slice " $NUM]
pub enum $Id {}
impl Sealed for $Id {}
impl SliceId for $Id {
type Reset = $reset;
const DYN: DynSliceId = DynSliceId { num: $NUM };
}
}
};
}
struct Registers<I: SliceId> {
id: PhantomData<I>,
}
unsafe impl<I: SliceId> RegisterInterface for Registers<I> {
#[inline]
fn id(&self) -> DynSliceId {
I::DYN
}
}
impl<I: SliceId> Registers<I> {
#[inline]
unsafe fn new() -> Self {
Registers { id: PhantomData }
}
#[inline]
fn change_mode<M: SliceMode + ValidSliceMode<I>>(&mut self) {
RegisterInterface::do_change_mode(self, M::DYN);
}
}
pub struct Slice<I, M>
where
I: SliceId,
M: SliceMode + ValidSliceMode<I>,
{
regs: Registers<I>,
mode: PhantomData<M>,
pub channel_a: Channel<I, M, A>,
pub channel_b: Channel<I, M, B>,
}
impl<I, M> Slice<I, M>
where
I: SliceId,
M: SliceMode + ValidSliceMode<I>,
{
#[inline]
pub(crate) unsafe fn new() -> Slice<I, M> {
Slice {
regs: Registers::new(),
mode: PhantomData,
channel_a: Channel::new(0),
channel_b: Channel::new(0),
}
}
#[inline]
pub fn into_mode<N: SliceMode + ValidSliceMode<I>>(mut self) -> Slice<I, N> {
if N::DYN != M::DYN {
self.regs.change_mode::<N>();
}
unsafe { Slice::new() }
}
pub fn default_config(&mut self) {
self.regs.write_ph_correct(false);
self.regs.write_div_int(1); self.regs.write_div_frac(0); self.regs.write_inv_a(false); self.regs.write_inv_b(false); self.regs.write_top(0xffff); self.regs.write_ctr(0x0000); self.regs.write_cc_a(0); self.regs.write_cc_b(0); }
#[inline]
pub fn advance_phase(&mut self) {
self.regs.advance_phase()
}
#[inline]
pub fn retard_phase(&mut self) {
self.regs.retard_phase()
}
#[inline]
pub fn set_ph_correct(&mut self) {
self.regs.write_ph_correct(true)
}
#[inline]
pub fn clr_ph_correct(&mut self) {
self.regs.write_ph_correct(false)
}
#[inline]
pub fn enable(&mut self) {
self.regs.write_enable(true);
}
#[inline]
pub fn disable(&mut self) {
self.regs.write_enable(false)
}
#[inline]
pub fn set_div_int(&mut self, value: u8) {
self.regs.write_div_int(value)
}
#[inline]
pub fn set_div_frac(&mut self, value: u8) {
self.regs.write_div_frac(value)
}
#[inline]
pub fn get_counter(&self) -> u16 {
self.regs.read_ctr()
}
#[inline]
pub fn set_counter(&mut self, value: u16) {
self.regs.write_ctr(value)
}
#[inline]
pub fn get_top(&self) -> u16 {
self.regs.read_top()
}
#[inline]
pub fn set_top(&mut self, value: u16) {
self.regs.write_top(value)
}
#[inline]
fn bitmask(&self) -> u32 {
1 << I::DYN.num
}
#[inline]
pub fn enable_interrupt(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.inte.as_ptr();
write_bitmask_set(reg, self.bitmask());
}
}
#[inline]
pub fn disable_interrupt(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.inte.as_ptr();
write_bitmask_clear(reg, self.bitmask());
};
}
#[inline]
pub fn has_overflown(&self) -> bool {
let mask = self.bitmask();
unsafe { (*pac::PWM::ptr()).intr.read().bits() & mask == mask }
}
#[inline]
pub fn clear_interrupt(&mut self) {
unsafe { (*pac::PWM::ptr()).intr.write(|w| w.bits(self.bitmask())) };
}
#[inline]
pub fn force_interrupt(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.intf.as_ptr();
write_bitmask_set(reg, self.bitmask());
}
}
#[inline]
pub fn clear_force_interrupt(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.intf.as_ptr();
write_bitmask_clear(reg, self.bitmask());
}
}
}
macro_rules! pwm {
($PWMX:ident, [
$($SXi:ident: ($slice:literal, [$($pin_a:ident, $pin_b:ident),*], $i:expr)),+
]) => {
$(
slice_id!($SXi, $slice, FreeRunning);
$(
impl ValidPwmOutputPin<$SXi, A> for $pin_a {}
impl ValidPwmOutputPin<$SXi, B> for $pin_b {}
impl ValidPwmInputPin<$SXi> for $pin_b {}
)*
)+
$crate::paste::paste!{
pub struct Slices {
_pwm: $PWMX,
$(
#[doc = "Slice " $SXi]
pub [<$SXi:lower>] : Slice<$SXi,<$SXi as SliceId>::Reset>,
)+
}
impl Slices {
pub fn new(pwm: $PWMX, reset : &mut pac::RESETS) -> Self {
pwm.reset_bring_up(reset);
unsafe {
Self {
_pwm: pwm,
$(
[<$SXi:lower>]: Slice::new(),
)+
}
}
}
}
}
}
}
pwm! {
PWM, [
Pwm0: (0, [Gpio0, Gpio1, Gpio16, Gpio17], 0),
Pwm1: (1, [Gpio2, Gpio3, Gpio18, Gpio19], 1),
Pwm2: (2, [Gpio4, Gpio5, Gpio20, Gpio21], 2),
Pwm3: (3, [Gpio6, Gpio7, Gpio22, Gpio23], 3),
Pwm4: (4, [Gpio8, Gpio9, Gpio24, Gpio25], 4),
Pwm5: (5, [Gpio10, Gpio11, Gpio26, Gpio27], 5),
Pwm6: (6, [Gpio12, Gpio13, Gpio28, Gpio29], 6),
Pwm7: (7, [Gpio14, Gpio15], 7)
]
}
pub trait ValidPwmInputPin<S: SliceId>: Sealed {}
pub trait ValidPwmOutputPin<S: SliceId, C: ChannelId>: Sealed {}
impl Slices {
pub fn free(self) -> PWM {
self._pwm
}
}
pub struct Channel<S: SliceId, M: SliceMode, C: ChannelId> {
regs: Registers<S>,
slice_mode: PhantomData<M>,
channel_id: PhantomData<C>,
duty_cycle: u16,
enabled: bool,
}
impl<S: SliceId, M: SliceMode, C: ChannelId> Channel<S, M, C> {
pub(super) unsafe fn new(duty_cycle: u16) -> Self {
Channel {
regs: Registers::new(),
slice_mode: PhantomData,
channel_id: PhantomData,
duty_cycle, enabled: true,
}
}
}
impl<S: SliceId, M: SliceMode, C: ChannelId> Sealed for Channel<S, M, C> {}
impl<S: SliceId, M: SliceMode> PwmPin for Channel<S, M, A> {
type Duty = u16;
fn disable(&mut self) {
if self.enabled {
self.duty_cycle = self.regs.read_cc_a();
}
self.enabled = false;
self.regs.write_cc_a(0)
}
fn enable(&mut self) {
if !self.enabled {
self.enabled = true;
self.regs.write_cc_a(self.duty_cycle)
}
}
fn get_duty(&self) -> Self::Duty {
if self.enabled {
self.regs.read_cc_a()
} else {
self.duty_cycle
}
}
fn get_max_duty(&self) -> Self::Duty {
self.regs.read_top()
}
fn set_duty(&mut self, duty: Self::Duty) {
self.duty_cycle = duty;
if self.enabled {
self.regs.write_cc_a(duty)
}
}
}
impl<S: SliceId, M: SliceMode> PwmPin for Channel<S, M, B> {
type Duty = u16;
fn disable(&mut self) {
if self.enabled {
self.duty_cycle = self.regs.read_cc_b();
}
self.enabled = false;
self.regs.write_cc_b(0)
}
fn enable(&mut self) {
if !self.enabled {
self.enabled = true;
self.regs.write_cc_b(self.duty_cycle)
}
}
fn get_duty(&self) -> Self::Duty {
if self.enabled {
self.regs.read_cc_b()
} else {
self.duty_cycle
}
}
fn get_max_duty(&self) -> Self::Duty {
self.regs.read_top()
}
fn set_duty(&mut self, duty: Self::Duty) {
self.duty_cycle = duty;
if self.enabled {
self.regs.write_cc_b(duty)
}
}
}
impl<S: SliceId, M: SliceMode + ValidSliceMode<S>> Channel<S, M, A> {
pub fn output_to<
G: PinId + BankPinId + ValidPwmOutputPin<S, A>,
PM: PinMode + ValidPinMode<G>,
>(
&mut self,
pin: Pin<G, PM>,
) -> Pin<G, FunctionPwm> {
pin.into_mode()
}
#[inline]
pub fn set_inverted(&mut self) {
self.regs.write_inv_a(true)
}
#[inline]
pub fn clr_inverted(&mut self) {
self.regs.write_inv_a(false)
}
}
impl<S: SliceId, M: SliceMode + ValidSliceMode<S>> Channel<S, M, B> {
pub fn output_to<
G: PinId + BankPinId + ValidPwmOutputPin<S, B>,
PM: PinMode + ValidPinMode<G>,
>(
&mut self,
pin: Pin<G, PM>,
) -> Pin<G, FunctionPwm> {
pin.into_mode()
}
#[inline]
pub fn set_inverted(&mut self) {
self.regs.write_inv_b(true)
}
#[inline]
pub fn clr_inverted(&mut self) {
self.regs.write_inv_b(false)
}
}
impl<S: SliceId, M: SliceMode + ValidSliceInputMode<S>> Channel<S, M, B> {
pub fn input_from<G: PinId + BankPinId + ValidPwmInputPin<S>, PM: PinMode + ValidPinMode<G>>(
&mut self,
pin: Pin<G, PM>,
) -> Pin<G, FunctionPwm> {
pin.into_mode()
}
}
impl<S: SliceId, M: SliceMode + ValidSliceMode<S>> Slice<S, M> {
pub fn output_to<
G: PinId + BankPinId + ValidPwmOutputPin<S, C>,
PM: PinMode + ValidPinMode<G>,
C: ChannelId,
>(
&mut self,
pin: Pin<G, PM>,
) -> Pin<G, FunctionPwm> {
pin.into_mode()
}
}
impl<S: SliceId, M: SliceMode + ValidSliceInputMode<S>> Slice<S, M> {
pub fn input_from<G: PinId + BankPinId + ValidPwmInputPin<S>, PM: PinMode + ValidPinMode<G>>(
&mut self,
pin: Pin<G, PM>,
) -> Pin<G, FunctionPwm> {
pin.into_mode()
}
}