use core::convert::Infallible;
use core::marker::PhantomData;
use embedded_dma::Word;
use embedded_hal::pwm::{ErrorType, SetDutyCycle};
use crate::{
atomic_register_access::{write_bitmask_clear, write_bitmask_set},
dma::{EndlessWriteTarget, WriteTarget},
gpio::{bank0::*, AnyPin, FunctionPwm, Pin, ValidFunction},
pac::{self, dma::ch::ch_al1_ctrl::TREQ_SEL_A, PWM},
resets::SubsystemReset,
typelevel::{Is, Sealed},
};
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 + SliceMode {}
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;
const WRAP_DREQ: u8 = TREQ_SEL_A::PWM_WRAP0 as u8 + Self::DYN.num;
}
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 };
}
}
};
}
pub trait AnySlice
where
Self: Sealed,
Self: Is<Type = SpecificSlice<Self>>,
<Self as AnySlice>::Mode: ValidSliceMode<<Self as AnySlice>::Id>,
{
type Id: SliceId;
type Mode: SliceMode;
}
impl<S, M> Sealed for Slice<S, M>
where
S: SliceId,
M: ValidSliceMode<S>,
{
}
impl<S, M> AnySlice for Slice<S, M>
where
S: SliceId,
M: ValidSliceMode<S>,
{
type Id = S;
type Mode = M;
}
type SpecificSlice<S> = Slice<<S as AnySlice>::Id, <S as AnySlice>::Mode>;
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: ValidSliceMode<I>>(&mut self) {
RegisterInterface::do_change_mode(self, M::DYN);
}
}
pub struct Slice<I, M>
where
I: SliceId,
M: ValidSliceMode<I>,
{
regs: Registers<I>,
mode: PhantomData<M>,
pub channel_a: Channel<Self, A>,
pub channel_b: Channel<Self, B>,
}
impl<I, M> Slice<I, M>
where
I: SliceId,
M: 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: 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(0xfffe); 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_interrupt0(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq0_inte().as_ptr();
write_bitmask_set(reg, self.bitmask());
}
}
#[inline]
pub fn disable_interrupt0(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq0_inte().as_ptr();
write_bitmask_clear(reg, self.bitmask());
};
}
#[inline]
pub fn enable_interrupt1(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq1_inte().as_ptr();
write_bitmask_set(reg, self.bitmask());
}
}
#[inline]
pub fn disable_interrupt1(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq1_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_interrupt0(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq0_intf().as_ptr();
write_bitmask_set(reg, self.bitmask());
}
}
#[inline]
pub fn clear_force_interrupt0(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq0_intf().as_ptr();
write_bitmask_clear(reg, self.bitmask());
}
}
#[inline]
pub fn force_interrupt1(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq1_intf().as_ptr();
write_bitmask_set(reg, self.bitmask());
}
}
#[inline]
pub fn clear_force_interrupt1(&mut self) {
unsafe {
let pwm = &(*pac::PWM::ptr());
let reg = pwm.irq1_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 crate::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, Gpio30, Gpio31], 7),
Pwm8: (8, [Gpio32, Gpio33, Gpio40, Gpio41], 8),
Pwm9: (9, [Gpio34, Gpio35, Gpio42, Gpio43], 9),
Pwm10: (10, [Gpio36, Gpio37, Gpio44, Gpio45], 10),
Pwm11: (11, [Gpio38, Gpio39, Gpio46, Gpio47], 11)
]
}
pub trait ValidPwmInputPin<S: SliceId>: ValidFunction<FunctionPwm> + Sealed {}
pub trait ValidPwmOutputPin<S: SliceId, C: ChannelId>: ValidFunction<FunctionPwm> + Sealed {}
impl Slices {
pub fn free(self) -> PWM {
self._pwm
}
pub fn enable_simultaneous(&mut self, bits: u8) {
unsafe {
let reg = self._pwm.en().as_ptr();
write_bitmask_set(reg, bits as u32);
}
}
}
pub struct Channel<S: AnySlice, C: ChannelId> {
regs: Registers<S::Id>,
slice_mode: PhantomData<S::Mode>,
channel_id: PhantomData<C>,
duty_cycle: u16,
enabled: bool,
}
impl<S: AnySlice, C: ChannelId> Channel<S, 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: AnySlice, C: ChannelId> Sealed for Channel<S, C> {}
impl<S: AnySlice, C: ChannelId> embedded_hal_0_2::PwmPin for Channel<S, C> {
type Duty = u16;
fn disable(&mut self) {
self.set_enabled(false);
}
fn enable(&mut self) {
self.set_enabled(true);
}
fn get_duty(&self) -> Self::Duty {
if self.enabled {
self.read_cc()
} else {
self.duty_cycle
}
}
fn get_max_duty(&self) -> Self::Duty {
SetDutyCycle::max_duty_cycle(self)
}
fn set_duty(&mut self, duty: Self::Duty) {
let _ = SetDutyCycle::set_duty_cycle(self, duty);
}
}
impl<S: AnySlice, C: ChannelId> ErrorType for Channel<S, C> {
type Error = Infallible;
}
impl<S: AnySlice, C: ChannelId> SetDutyCycle for Channel<S, C> {
fn max_duty_cycle(&self) -> u16 {
self.regs.read_top().saturating_add(1)
}
fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
self.duty_cycle = duty;
if self.enabled {
self.write_cc(duty);
}
Ok(())
}
}
impl<S: AnySlice, C: ChannelId> Channel<S, C> {
fn write_cc(&mut self, value: u16) {
match C::DYN {
DynChannelId::A => self.regs.write_cc_a(value),
DynChannelId::B => self.regs.write_cc_b(value),
}
}
fn read_cc(&self) -> u16 {
match C::DYN {
DynChannelId::A => self.regs.read_cc_a(),
DynChannelId::B => self.regs.read_cc_b(),
}
}
fn write_inv(&mut self, value: bool) {
match C::DYN {
DynChannelId::A => self.regs.write_inv_a(value),
DynChannelId::B => self.regs.write_inv_b(value),
}
}
pub fn set_enabled(&mut self, enable: bool) {
if enable && !self.enabled {
self.write_cc(self.duty_cycle);
self.enabled = true;
} else if !enable && self.enabled {
self.duty_cycle = self.read_cc();
self.write_cc(0);
self.enabled = false;
}
}
#[inline]
pub fn set_inverted(&mut self) {
self.write_inv(true)
}
#[inline]
pub fn clr_inverted(&mut self) {
self.write_inv(false)
}
}
impl<S: AnySlice> Channel<S, A> {
pub fn output_to<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
where
P::Id: ValidPwmOutputPin<S::Id, A>,
{
pin.into().into_function()
}
}
impl<S: AnySlice> Channel<S, B> {
pub fn output_to<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
where
P::Id: ValidPwmOutputPin<S::Id, B>,
{
pin.into().into_function()
}
}
impl<S: AnySlice> Channel<S, B>
where
S::Mode: ValidSliceInputMode<S::Id>,
{
pub fn input_from<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
where
P::Id: ValidPwmInputPin<S::Id>,
{
pin.into().into_function()
}
}
impl<S: SliceId, M: ValidSliceMode<S>> Slice<S, M> {
pub fn output_to<P: AnyPin, C: ChannelId>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
where
P::Id: ValidPwmOutputPin<S, C>,
{
pin.into().into_function()
}
}
impl<S: SliceId, M: ValidSliceInputMode<S>> Slice<S, M> {
pub fn input_from<P: AnyPin>(&mut self, pin: P) -> Pin<P::Id, FunctionPwm, P::Pull>
where
P::Id: ValidPwmInputPin<S>,
{
pin.into().into_function()
}
}
pub struct SliceDmaWriteCc<S: SliceId, M: ValidSliceMode<S>> {
slice: PhantomData<S>,
mode: PhantomData<M>,
}
pub struct SliceDmaWriteTop<S: SliceId, M: ValidSliceMode<S>> {
slice: PhantomData<S>,
mode: PhantomData<M>,
}
pub struct SliceDmaWrite<S: SliceId, M: ValidSliceMode<S>> {
pub top: SliceDmaWriteTop<S, M>,
pub cc: SliceDmaWriteCc<S, M>,
slice: Slice<S, M>,
}
impl<S: SliceId, M: ValidSliceMode<S>> From<Slice<S, M>> for SliceDmaWrite<S, M> {
fn from(value: Slice<S, M>) -> Self {
Self {
slice: value,
top: SliceDmaWriteTop {
slice: PhantomData,
mode: PhantomData,
},
cc: SliceDmaWriteCc {
slice: PhantomData,
mode: PhantomData,
},
}
}
}
impl<S: SliceId, M: ValidSliceMode<S>> From<SliceDmaWrite<S, M>> for Slice<S, M> {
fn from(value: SliceDmaWrite<S, M>) -> Self {
value.slice
}
}
#[derive(Clone, Copy, Eq, PartialEq)]
#[repr(C)]
#[repr(align(4))]
pub struct CcFormat {
pub a: u16,
pub b: u16,
}
unsafe impl Word for CcFormat {}
#[derive(Clone, Copy, Eq)]
#[repr(C)]
#[repr(align(4))]
pub struct TopFormat {
pub top: u16,
reserved: u16,
}
impl PartialEq<TopFormat> for TopFormat {
fn eq(&self, other: &TopFormat) -> bool {
self.top == other.top
}
}
impl TopFormat {
pub fn new(top: u16) -> Self {
TopFormat { top, reserved: 0 }
}
}
impl Default for TopFormat {
fn default() -> Self {
Self::new(u16::MAX)
}
}
unsafe impl Word for TopFormat {}
unsafe impl<S: SliceId, M: ValidSliceMode<S>> WriteTarget for SliceDmaWriteCc<S, M> {
type TransmittedWord = CcFormat;
fn tx_treq() -> Option<u8> {
Some(S::WRAP_DREQ)
}
fn tx_address_count(&mut self) -> (u32, u32) {
let regs = Registers {
id: PhantomData::<S> {},
};
(regs.ch().cc().as_ptr() as u32, u32::MAX)
}
fn tx_increment(&self) -> bool {
false
}
}
unsafe impl<S: SliceId, M: ValidSliceMode<S>> WriteTarget for SliceDmaWriteTop<S, M> {
type TransmittedWord = TopFormat;
fn tx_treq() -> Option<u8> {
Some(S::WRAP_DREQ)
}
fn tx_address_count(&mut self) -> (u32, u32) {
let regs = Registers {
id: PhantomData::<S> {},
};
(regs.ch().top().as_ptr() as u32, u32::MAX)
}
fn tx_increment(&self) -> bool {
false
}
}
impl<S: SliceId, M: ValidSliceMode<S>> EndlessWriteTarget for SliceDmaWriteCc<S, M> {}
impl<S: SliceId, M: ValidSliceMode<S>> EndlessWriteTarget for SliceDmaWriteTop<S, M> {}