use core::marker::PhantomData;
use core::mem;
use crate::pac::DBGMCU as DBG;
#[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 crate::afio::MAPR;
use crate::gpio::{self, Floating, Input};
use crate::rcc::{sealed::RccBus, Clocks, GetBusFreq};
use crate::time::Hertz;
use crate::timer::Timer;
pub trait Pins<REMAP> {}
use crate::timer::sealed::{Ch1, Ch2, Remap};
impl<TIM, REMAP, P1, P2> Pins<REMAP> for (P1, P2)
where
REMAP: Remap<Periph = TIM>,
P1: Ch1<REMAP> + gpio::Mode<Input<Floating>>,
P2: Ch2<REMAP> + gpio::Mode<Input<Floating>>,
{
}
pub struct PwmInput<TIM, REMAP, PINS> {
_timer: PhantomData<TIM>,
_remap: PhantomData<REMAP>,
_pins: PhantomData<PINS>,
}
pub enum ReadMode {
Instant,
WaitForNextCapture,
}
#[derive(Debug)]
pub enum Error {
FrequencyTooLow,
}
pub enum Configuration<T>
where
T: Into<Hertz>,
{
Frequency(T),
DutyCycle(T),
RawFrequency(T),
RawValues { arr: u16, presc: u16 },
}
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
impl Timer<TIM1> {
pub fn pwm_input<REMAP, PINS, T>(
mut self,
pins: PINS,
mapr: &mut MAPR,
dbg: &mut DBG,
mode: Configuration<T>,
) -> PwmInput<TIM1, REMAP, PINS>
where
REMAP: Remap<Periph = TIM1>,
PINS: Pins<REMAP>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim1_remap().bits(REMAP::REMAP) });
self.stop_in_debug(dbg, false);
let Self { tim, clk } = self;
tim1(tim, pins, clk, mode)
}
}
impl Timer<TIM2> {
pub fn pwm_input<REMAP, PINS, T>(
mut self,
pins: PINS,
mapr: &mut MAPR,
dbg: &mut DBG,
mode: Configuration<T>,
) -> PwmInput<TIM2, REMAP, PINS>
where
REMAP: Remap<Periph = TIM2>,
PINS: Pins<REMAP>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim2_remap().bits(REMAP::REMAP) });
self.stop_in_debug(dbg, false);
let Self { tim, clk } = self;
tim2(tim, pins, clk, mode)
}
}
impl Timer<TIM3> {
pub fn pwm_input<REMAP, PINS, T>(
mut self,
pins: PINS,
mapr: &mut MAPR,
dbg: &mut DBG,
mode: Configuration<T>,
) -> PwmInput<TIM3, REMAP, PINS>
where
REMAP: Remap<Periph = TIM3>,
PINS: Pins<REMAP>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| unsafe { w.tim3_remap().bits(REMAP::REMAP) });
self.stop_in_debug(dbg, false);
let Self { tim, clk } = self;
tim3(tim, pins, clk, mode)
}
}
#[cfg(feature = "medium")]
impl Timer<TIM4> {
pub fn pwm_input<REMAP, PINS, T>(
mut self,
pins: PINS,
mapr: &mut MAPR,
dbg: &mut DBG,
mode: Configuration<T>,
) -> PwmInput<TIM4, REMAP, PINS>
where
REMAP: Remap<Periph = TIM4>,
PINS: Pins<REMAP>,
T: Into<Hertz>,
{
mapr.modify_mapr(|_, w| w.tim4_remap().bit(REMAP::REMAP == 1));
self.stop_in_debug(dbg, false);
let Self { tim, clk } = self;
tim4(tim, pins, clk, mode)
}
}
fn compute_arr_presc(freq: u32, clock: u32) -> (u16, u16) {
if freq == 0 {
return (core::u16::MAX, core::u16::MAX);
}
let presc = clock / freq.saturating_mul(core::u16::MAX as u32 + 1);
let arr = clock / freq.saturating_mul(presc + 1);
(core::cmp::max(1, arr as u16), presc as u16)
}
macro_rules! hal {
($($TIMX:ident: ($timX:ident),)+) => {
$(
fn $timX<REMAP, PINS,T>(
tim: $TIMX,
_pins: PINS,
clk: Hertz,
mode : Configuration<T>,
) -> PwmInput<$TIMX, REMAP, PINS>
where
REMAP: Remap<Periph = $TIMX>,
PINS: Pins<REMAP>,
T : Into<Hertz>
{
use crate::pwm_input::Configuration::*;
tim.ccer.modify(|_,w| w.cc1e().clear_bit().cc2e().clear_bit()
.cc1p().clear_bit().cc2p().set_bit());
tim.ccmr1_input().modify( |_,w| w.cc1s().ti1().cc2s().ti1());
tim.dier.write(|w| w.cc1ie().set_bit());
tim.smcr.modify( |_,w| unsafe {w.ts().bits(0b101).sms().bits(0b100)});
match mode {
Frequency(f) => {
let freq = f.into().0;
let max_freq = if freq > 5 {freq/5} else {1};
let (arr,presc) = compute_arr_presc(max_freq, clk.0);
tim.arr.write(|w| w.arr().bits(arr));
tim.psc.write(|w| w.psc().bits(presc) );
},
DutyCycle(f) => {
let freq = f.into().0;
let max_freq = if freq > 2 {freq/2 + freq/4 + freq/8} else {1};
let (arr,presc) = compute_arr_presc(max_freq, clk.0);
tim.arr.write(|w| w.arr().bits(arr));
tim.psc.write(|w| w.psc().bits(presc) );
},
RawFrequency(f) => {
let freq = f.into().0;
let (arr,presc) = compute_arr_presc(freq, clk.0);
tim.arr.write(|w| w.arr().bits(arr));
tim.psc.write(|w| w.psc().bits(presc) );
}
RawValues{arr, presc} => {
tim.arr.write(|w| w.arr().bits(arr));
tim.psc.write(|w| w.psc().bits(presc) );
}
}
tim.ccer.modify(|_,w| w.cc1e().set_bit().cc2e().set_bit());
tim.cr1.modify(|_,w| w.cen().set_bit());
unsafe { mem::MaybeUninit::uninit().assume_init() }
}
impl<REMAP, PINS> PwmInput<$TIMX, REMAP, PINS>
where
REMAP: Remap<Periph = $TIMX>,
PINS: Pins<REMAP>,
{
pub fn read_frequency(&self, mode : ReadMode, clocks : &Clocks) -> Result<Hertz,Error> {
if let ReadMode::WaitForNextCapture = mode {
self.wait_for_capture();
}
let presc = unsafe { (*$TIMX::ptr()).psc.read().bits() as u16};
let ccr1 = unsafe { (*$TIMX::ptr()).ccr1.read().bits() as u16};
if ccr1 == 0 {
Err(Error::FrequencyTooLow)
} else {
let clk : u32 = <$TIMX as RccBus>::Bus::get_timer_frequency(&clocks).0;
Ok(Hertz(clk/((presc+1) as u32*(ccr1 + 1)as u32)))
}
}
pub fn read_duty(&self, mode : ReadMode) -> Result<(u16,u16),Error> {
if let ReadMode::WaitForNextCapture = mode {
self.wait_for_capture();
}
let ccr1 = unsafe { (*$TIMX::ptr()).ccr1.read().bits() as u16};
let ccr2 = unsafe { (*$TIMX::ptr()).ccr2.read().bits() as u16};
if ccr1 == 0 {
Err(Error::FrequencyTooLow)
} else {
Ok((ccr2,ccr1))
}
}
fn wait_for_capture(&self) {
unsafe { (*$TIMX::ptr()).sr.write(|w| w.uif().clear_bit().cc1if().clear_bit().cc1of().clear_bit())};
while unsafe { (*$TIMX::ptr()).sr.read().cc1if().bit_is_clear()} {}
}
}
)+
}
}
#[cfg(any(feature = "stm32f100", feature = "stm32f103", feature = "connectivity",))]
hal! {
TIM1: (tim1),
}
hal! {
TIM2: (tim2),
TIM3: (tim3),
}
#[cfg(feature = "medium")]
hal! {
TIM4: (tim4),
}