use core::marker::Copy;
use core::marker::PhantomData;
use core::mem;
use crate::hal;
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
use crate::pac::TIM1;
#[cfg(feature = "medium")]
use crate::pac::TIM4;
use crate::pac::{TIM2, TIM3};
use cast::{u16, u32};
use crate::afio::MAPR;
use crate::bb;
use crate::gpio::{self, Alternate, PushPull};
use crate::time::Hertz;
use crate::time::U32Ext;
use crate::timer::Timer;
pub trait Pins<REMAP, P> {
const C1: bool = false;
const C2: bool = false;
const C3: bool = false;
const C4: bool = false;
type Channels;
fn check_used(c: Channel) -> Channel {
if (c == Channel::C1 && Self::C1)
|| (c == Channel::C2 && Self::C2)
|| (c == Channel::C3 && Self::C3)
|| (c == Channel::C4 && Self::C4)
{
c
} else {
panic!("Unused channel")
}
}
}
#[derive(Clone, Copy, PartialEq)]
pub enum Channel {
C1,
C2,
C3,
C4,
}
use crate::timer::sealed::{Ch1, Ch2, Ch3, Ch4, Remap};
macro_rules! pins_impl {
( $( ( $($PINX:ident),+ ), ( $($TRAIT:ident),+ ), ( $($ENCHX:ident),* ); )+ ) => {
$(
#[allow(unused_parens)]
impl<TIM, REMAP, $($PINX,)+> Pins<REMAP, ($($ENCHX),+)> for ($($PINX),+)
where
REMAP: Remap<Periph = TIM>,
$($PINX: $TRAIT<REMAP> + gpio::Mode<Alternate<PushPull>>,)+
{
$(const $ENCHX: bool = true;)+
type Channels = ($(PwmChannel<TIM, $ENCHX>),+);
}
)+
};
}
pins_impl!(
(P1, P2, P3, P4), (Ch1, Ch2, Ch3, Ch4), (C1, C2, C3, C4);
(P2, P3, P4), (Ch2, Ch3, Ch4), (C2, C3, C4);
(P1, P3, P4), (Ch1, Ch3, Ch4), (C1, C3, C4);
(P1, P2, P4), (Ch1, Ch2, Ch4), (C1, C2, C4);
(P1, P2, P3), (Ch1, Ch2, Ch3), (C1, C2, C3);
(P3, P4), (Ch3, Ch4), (C3, C4);
(P2, P4), (Ch2, Ch4), (C2, C4);
(P2, P3), (Ch2, Ch3), (C2, C3);
(P1, P4), (Ch1, Ch4), (C1, C4);
(P1, P3), (Ch1, Ch3), (C1, C3);
(P1, P2), (Ch1, Ch2), (C1, C2);
(P1), (Ch1), (C1);
(P2), (Ch2), (C2);
(P3), (Ch3), (C3);
(P4), (Ch4), (C4);
);
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
impl Timer<TIM1> {
pub fn pwm<REMAP, P, PINS, T>(
self,
_pins: PINS,
mapr: &mut MAPR,
freq: T,
) -> Pwm<TIM1, REMAP, P, PINS>
where
REMAP: Remap<Periph = TIM1>,
PINS: Pins<REMAP, P>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim1_remap().bits(REMAP::REMAP) });
self.tim.bdtr.modify(|_, w| w.aoe().set_bit());
let Self { tim, clk } = self;
tim1(tim, _pins, freq.into(), clk)
}
}
impl Timer<TIM2> {
pub fn pwm<REMAP, P, PINS, T>(
self,
_pins: PINS,
mapr: &mut MAPR,
freq: T,
) -> Pwm<TIM2, REMAP, P, PINS>
where
REMAP: Remap<Periph = TIM2>,
PINS: Pins<REMAP, P>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim2_remap().bits(REMAP::REMAP) });
let Self { tim, clk } = self;
tim2(tim, _pins, freq.into(), clk)
}
}
impl Timer<TIM3> {
pub fn pwm<REMAP, P, PINS, T>(
self,
_pins: PINS,
mapr: &mut MAPR,
freq: T,
) -> Pwm<TIM3, REMAP, P, PINS>
where
REMAP: Remap<Periph = TIM3>,
PINS: Pins<REMAP, P>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim3_remap().bits(REMAP::REMAP) });
let Self { tim, clk } = self;
tim3(tim, _pins, freq.into(), clk)
}
}
#[cfg(feature = "medium")]
impl Timer<TIM4> {
pub fn pwm<REMAP, P, PINS, T>(
self,
_pins: PINS,
mapr: &mut MAPR,
freq: T,
) -> Pwm<TIM4, REMAP, P, PINS>
where
REMAP: Remap<Periph = TIM4>,
PINS: Pins<REMAP, P>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| w.tim4_remap().bit(REMAP::REMAP == 1));
let Self { tim, clk } = self;
tim4(tim, _pins, freq.into(), clk)
}
}
pub struct Pwm<TIM, REMAP, P, PINS>
where
REMAP: Remap<Periph = TIM>,
PINS: Pins<REMAP, P>,
{
clk: Hertz,
_pins: PhantomData<(TIM, REMAP, P, PINS)>,
}
impl<TIM, REMAP, P, PINS> Pwm<TIM, REMAP, P, PINS>
where
REMAP: Remap<Periph = TIM>,
PINS: Pins<REMAP, P>,
{
pub fn split(self) -> PINS::Channels {
unsafe { mem::MaybeUninit::uninit().assume_init() }
}
}
pub struct PwmChannel<TIM, CHANNEL> {
_channel: PhantomData<CHANNEL>,
_tim: PhantomData<TIM>,
}
pub struct C1;
pub struct C2;
pub struct C3;
pub struct C4;
macro_rules! hal {
($($TIMX:ident: ($timX:ident),)+) => {
$(
fn $timX<REMAP, P, PINS>(
tim: $TIMX,
_pins: PINS,
freq: Hertz,
clk: Hertz,
) -> Pwm<$TIMX, REMAP, P, PINS>
where
REMAP: Remap<Periph = $TIMX>,
PINS: Pins<REMAP, P>,
{
if PINS::C1 {
tim.ccmr1_output()
.modify(|_, w| w.oc1pe().set_bit().oc1m().pwm_mode1() );
}
if PINS::C2 {
tim.ccmr1_output()
.modify(|_, w| w.oc2pe().set_bit().oc2m().pwm_mode1() );
}
if PINS::C3 {
tim.ccmr2_output()
.modify(|_, w| w.oc3pe().set_bit().oc3m().pwm_mode1() );
}
if PINS::C4 {
tim.ccmr2_output()
.modify(|_, w| w.oc4pe().set_bit().oc4m().pwm_mode1() );
}
let ticks = clk.0 / freq.0;
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.modify(|_, w| w.urs().set_bit());
tim.egr.write(|w| w.ug().set_bit());
tim.cr1.modify(|_, w| w.urs().clear_bit());
tim.cr1.write(|w|
w.cms()
.bits(0b00)
.dir()
.clear_bit()
.opm()
.clear_bit()
.cen()
.set_bit()
);
Pwm {
clk: clk,
_pins: PhantomData
}
}
impl<REMAP, P, PINS> hal::Pwm for Pwm<$TIMX, REMAP, P, PINS> where
REMAP: Remap<Periph = $TIMX>,
PINS: Pins<REMAP, P>,
{
type Channel = Channel;
type Duty = u16;
type Time = Hertz;
fn enable(&mut self, channel: Self::Channel) {
match PINS::check_used(channel) {
Channel::C1 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 0) },
Channel::C2 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 4) },
Channel::C3 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 8) },
Channel::C4 => unsafe { bb::set(&(*$TIMX::ptr()).ccer, 12) }
}
}
fn disable(&mut self, channel: Self::Channel) {
match PINS::check_used(channel) {
Channel::C1 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 0) },
Channel::C2 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 4) },
Channel::C3 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 8) },
Channel::C4 => unsafe { bb::clear(&(*$TIMX::ptr()).ccer, 12) },
}
}
fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
match PINS::check_used(channel) {
Channel::C1 => unsafe { (*$TIMX::ptr()).ccr1.read().ccr().bits() },
Channel::C2 => unsafe { (*$TIMX::ptr()).ccr2.read().ccr().bits() },
Channel::C3 => unsafe { (*$TIMX::ptr()).ccr3.read().ccr().bits() },
Channel::C4 => unsafe { (*$TIMX::ptr()).ccr4.read().ccr().bits() },
}
}
fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) {
match PINS::check_used(channel) {
Channel::C1 => unsafe { (*$TIMX::ptr()).ccr1.write(|w| w.ccr().bits(duty)) },
Channel::C2 => unsafe { (*$TIMX::ptr()).ccr2.write(|w| w.ccr().bits(duty)) },
Channel::C3 => unsafe { (*$TIMX::ptr()).ccr3.write(|w| w.ccr().bits(duty)) },
Channel::C4 => unsafe { (*$TIMX::ptr()).ccr4.write(|w| w.ccr().bits(duty)) },
}
}
fn get_max_duty(&self) -> Self::Duty {
unsafe { (*$TIMX::ptr()).arr.read().arr().bits() }
}
fn get_period(&self) -> Self::Time {
let clk = self.clk;
let psc: u16 = unsafe{(*$TIMX::ptr()).psc.read().psc().bits()};
let arr: u16 = unsafe{(*$TIMX::ptr()).arr.read().arr().bits()};
(clk.0 / u32(psc * arr)).hz()
}
fn set_period<T>(&mut self, period: T) where
T: Into<Self::Time> {
let clk = self.clk;
let ticks = clk.0 / period.into().0;
let psc = u16(ticks / (1 << 16)).unwrap();
let arr = u16(ticks / u32(psc + 1)).unwrap();
unsafe {
(*$TIMX::ptr()).psc.write(|w| w.psc().bits(psc));
(*$TIMX::ptr()).arr.write(|w| w.arr().bits(arr));
}
}
}
impl hal::PwmPin for PwmChannel<$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().ccr().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.ccr().bits(duty)) }
}
}
impl hal::PwmPin for PwmChannel<$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().ccr().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.ccr().bits(duty)) }
}
}
impl hal::PwmPin for PwmChannel<$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().ccr().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.ccr().bits(duty)) }
}
}
impl hal::PwmPin for PwmChannel<$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().ccr().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.ccr().bits(duty)) }
}
}
)+
}
}
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
hal! {
TIM1: (tim1),
}
hal! {
TIM2: (tim2),
TIM3: (tim3),
}
#[cfg(feature = "medium")]
hal! {
TIM4: (tim4),
}