use crate::pac::{TIM2, TIM3, TIM4};
use bobbin_bits::*;
use cast::{u16, u32};
use core::intrinsics::transmute;
use cortex_m::peripheral::syst::SystClkSource;
use cortex_m::peripheral::SYST;
use hal::timer::{CountDown, Periodic};
use nb;
use void::Void;
use crate::rcc::Clocks;
use crate::time::Hertz;
#[doc(hidden)]
mod private {
#[doc(hidden)]
pub trait Sealed {}
impl Sealed for super::PwmFree {}
impl Sealed for super::PwmTaken {}
impl Sealed for super::CH1 {}
impl Sealed for super::CH2 {}
impl Sealed for super::CH3 {}
impl Sealed for super::CH4 {}
}
pub enum Event {
TimeOut,
}
pub trait TimerChannel {
fn enable(&mut self);
fn disable(&mut self);
fn read_ccr(&self) -> u32;
fn read_arr(&self) -> u32;
fn write_ccr(&mut self, value: u32);
}
pub mod syst {
use super::*;
pub struct Timer {
clocks: Clocks,
tim: SYST,
timeout: Hertz<u32>,
}
impl Timer {
pub fn new<T>(mut syst: SYST, timeout: T, clocks: Clocks) -> Self
where T: Into<Hertz<u32>>
{
syst.set_clock_source(SystClkSource::Core);
let mut timer = Timer { tim: syst,
clocks,
timeout: Hertz(0) };
timer.reset(timeout);
timer
}
pub fn reset<T: Into<Hertz<u32>>>(&mut self, timeout: T) {
self.timeout = timeout.into();
let rvr = self.clocks.sysclk().0 / self.timeout.0 - 1;
assert!(rvr < (1 << 24));
self.tim.set_reload(rvr);
self.tim.clear_current();
}
pub fn listen(&mut self, event: Event) {
match event {
Event::TimeOut => self.tim.enable_interrupt(),
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::TimeOut => self.tim.disable_interrupt(),
}
}
}
impl CountDown for Timer {
type Time = Hertz<u32>;
fn start<T>(&mut self, timeout: T)
where T: Into<Self::Time>
{
self.reset(timeout);
self.tim.enable_counter();
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.has_wrapped() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl Periodic for Timer {}
}
pub trait PwmState: private::Sealed {}
pub struct PwmFree;
impl PwmState for PwmFree {}
pub struct PwmTaken;
impl PwmState for PwmTaken {}
pub trait ChMode {
fn channel_mode(&self) -> U4;
}
pub struct Frozen;
impl ChMode for Frozen {
fn channel_mode(&self) -> U4 {
U4::B0000
}
}
pub struct Active;
impl ChMode for Active {
fn channel_mode(&self) -> U4 {
U4::B0001
}
}
pub struct Inactive;
impl ChMode for Inactive {
fn channel_mode(&self) -> U4 {
U4::B0010
}
}
pub struct Toggle;
impl ChMode for Toggle {
fn channel_mode(&self) -> U4 {
U4::B0011
}
}
pub struct ForceInactive;
impl ChMode for ForceInactive {
fn channel_mode(&self) -> U4 {
U4::B0100
}
}
pub struct ForceActive;
impl ChMode for ForceActive {
fn channel_mode(&self) -> U4 {
U4::B0101
}
}
pub struct Pwm1;
impl ChMode for Pwm1 {
fn channel_mode(&self) -> U4 {
U4::B0110
}
}
pub struct Pwm2;
impl ChMode for Pwm2 {
fn channel_mode(&self) -> U4 {
U4::B0111
}
}
pub struct CombinedPwm1;
impl ChMode for CombinedPwm1 {
fn channel_mode(&self) -> U4 {
U4::B1100
}
}
pub struct CombinedPwm2;
impl ChMode for CombinedPwm2 {
fn channel_mode(&self) -> U4 {
U4::B1101
}
}
pub struct AsymPwm1;
impl ChMode for AsymPwm1 {
fn channel_mode(&self) -> U4 {
U4::B1110
}
}
pub struct AsymPwm2;
impl ChMode for AsymPwm2 {
fn channel_mode(&self) -> U4 {
U4::B1111
}
}
pub trait ChNum: private::Sealed {
fn channel_number() -> U2;
}
pub struct CH1;
impl ChNum for CH1 {
fn channel_number() -> U2 {
U2::B00
}
}
pub struct CH2;
impl ChNum for CH2 {
fn channel_number() -> U2 {
U2::B01
}
}
pub struct CH3;
impl ChNum for CH3 {
fn channel_number() -> U2 {
U2::B10
}
}
pub struct CH4;
impl ChNum for CH4 {
fn channel_number() -> U2 {
U2::B11
}
}
macro_rules! tim {
($TIMSRC:ident, $apb:ident, $timmod:ident, $timXen:ident, $timXrst:ident) => {
pub mod $timmod {
use super::*;
use crate::rcc;
use crate::rcc::Clocks;
use core::marker::PhantomData;
pub struct Channel<CN: ChNum, M: ChMode> {
_index: PhantomData<CN>,
_mode: PhantomData<M>,
}
impl<CN: ChNum, M: ChMode> TimerChannel for Channel<CN, M> {
fn enable(&mut self) {
self.ccer(true)
}
fn disable(&mut self) {
self.ccer(false)
}
fn write_ccr(&mut self, value: u32) {
let index = CN::channel_number();
let tim = unsafe { &(*$TIMSRC::ptr()) };
unsafe {
match index {
U2::B00 => tim.ccr1.write(|w| w.bits(value)),
U2::B01 => tim.ccr2.write(|w| w.bits(value)),
U2::B10 => tim.ccr3.write(|w| w.bits(value)),
U2::B11 => tim.ccr4.write(|w| w.bits(value)),
}
}
}
fn read_ccr(&self) -> u32 {
let index = CN::channel_number();
let tim = unsafe { &(*$TIMSRC::ptr()) };
match index {
U2::B00 => tim.ccr1.read().bits(),
U2::B01 => tim.ccr2.read().bits(),
U2::B10 => tim.ccr3.read().bits(),
U2::B11 => tim.ccr4.read().bits(),
}
}
fn read_arr(&self) -> u32 {
let tim = unsafe { &(*$TIMSRC::ptr()) };
tim.arr.read().bits()
}
}
impl<M: ChMode, CN: ChNum> Channel<CN, M> {
fn ccer(&mut self, value: bool) {
let index: u32 = CN::channel_number().into();
let ccer_offset = index * 4;
let ccer_mask: u32 = 1;
let ccer_value: u32 = if value { 1 } else { 0 };
let tim = unsafe { &(*$TIMSRC::ptr()) };
tim.ccer.modify(|r, w| unsafe {
w.bits((r.bits() & !(ccer_mask << ccer_offset))
| ((ccer_value & ccer_mask)
<< ccer_offset))
});
}
pub fn mode<NM: ChMode>(self, nm: NM) -> Channel<CN, NM> {
let tim = unsafe { &(*$TIMSRC::ptr()) };
let mode_bits: u8 = nm.channel_mode().into();
match CN::channel_number() {
U2::B00 => tim.ccmr1_output()
.modify(|_, w| w.oc1m().bits(mode_bits)),
U2::B01 => tim.ccmr1_output()
.modify(|_, w| w.oc2m().bits(mode_bits)),
U2::B10 => tim.ccmr2_output()
.modify(|_, w| w.oc3m().bits(mode_bits)),
U2::B11 => tim.ccmr2_output()
.modify(|_, w| w.oc4m().bits(mode_bits)),
}
unsafe { transmute(self) }
}
pub fn preload(&mut self, value: bool) {
let index: u32 = CN::channel_number().into();
let tim = unsafe { &(*$TIMSRC::ptr()) };
let mask = true;
if index < 2 {
let offset: u32 = 3 + (index * 4);
tim.ccmr1_output().modify(|r, w| unsafe {
w.bits((r.bits()
& !((mask as u32)
<< offset))
| (((value & mask)
as u32)
<< offset))
})
} else {
let offset: u32 = 3 + (index - 2) * 4;
tim.ccmr2_output().modify(|r, w| unsafe {
w.bits((r.bits()
& !((mask as u32)
<< offset))
| (((value & mask)
as u32)
<< offset))
})
};
}
}
pub struct Timer<PS: PwmState> {
clocks: Clocks,
tim: $TIMSRC,
timeout: Hertz<u32>,
_ps: PhantomData<PS>,
}
impl Timer<PwmFree> {
pub fn new<T>(tim: $TIMSRC,
timeout: T,
clocks: Clocks)
-> Timer<PwmFree>
where T: Into<Hertz<u32>>
{
let mut apb = rcc::$apb::internal_get();
apb.enr().modify(|_, w| w.$timXen().enabled());
apb.rstr().modify(|_, w| w.$timXrst().set_bit());
apb.rstr().modify(|_, w| w.$timXrst().clear_bit());
let mut t = Timer { clocks,
tim,
timeout: Hertz(0),
_ps: PhantomData };
t.reset(timeout);
t
}
pub fn free(self, apb: &mut rcc::$apb) -> $TIMSRC {
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
apb.rstr().modify(|_, w| w.$timXrst().set_bit());
apb.rstr().modify(|_, w| w.$timXrst().clear_bit());
apb.enr().modify(|_, w| w.$timXen().disabled());
self.tim
}
}
impl<PS: PwmState> Timer<PS> {
pub fn reset<T>(&mut self, timeout: T)
where T: Into<Hertz<u32>>
{
self.tim.cr1.modify(|_, w| w.cen().clear_bit());
self.tim.cnt.reset();
let timeout = timeout.into();
let frequency = timeout.0;
let mult = if self.clocks.ppre1() == 1 { 1 } else { 2 };
let ticks = self.clocks.pclk1().0 * mult / frequency;
let psc = u16((ticks - 1) / (1 << 16)).unwrap();
self.tim.psc.write(|w| unsafe { w.bits(u32(psc)) });
let arr = u16(ticks / u32(psc + 1)).unwrap();
self.tim.arr.write(|w| unsafe { w.bits(u32(arr)) });
self.timeout = timeout;
}
pub fn listen(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.dier.write(|w| w.uie().set_bit());
}
}
}
pub fn unlisten(&mut self, event: Event) {
match event {
Event::TimeOut => {
self.tim.dier.write(|w| w.uie().clear_bit());
}
}
}
pub fn enable(&mut self) {
self.tim.cr1.modify(|_, w| w.cen().bit(true));
}
}
impl<PS: PwmState> Periodic for Timer<PS> {}
impl<PS: PwmState> CountDown for Timer<PS> {
type Time = Hertz<u32>;
fn start<T>(&mut self, timeout: T)
where T: Into<Hertz<u32>>
{
self.reset(timeout);
self.enable();
}
fn wait(&mut self) -> nb::Result<(), Void> {
if self.tim.sr.read().uif().bit_is_clear() {
Err(nb::Error::WouldBlock)
} else {
self.tim.sr.modify(|_, w| w.uif().clear_bit());
Ok(())
}
}
}
impl Timer<PwmFree> {
pub fn use_pwm(
self)
-> ((Channel<CH1, Inactive>,
Channel<CH2, Inactive>,
Channel<CH3, Inactive>,
Channel<CH4, Inactive>),
Timer<PwmTaken>) {
let ch1: Channel<CH1, Inactive> =
Channel { _index: PhantomData,
_mode: PhantomData };
let ch2: Channel<CH2, Inactive> =
Channel { _index: PhantomData,
_mode: PhantomData };
let ch3: Channel<CH3, Inactive> =
Channel { _index: PhantomData,
_mode: PhantomData };
let ch4: Channel<CH4, Inactive> =
Channel { _index: PhantomData,
_mode: PhantomData };
((ch1, ch2, ch3, ch4), unsafe { transmute(self) })
}
}
impl Timer<PwmTaken> {
pub fn return_pwm<M1, M2, M3, M4>(self,
_channels: (Channel<CH1,
M1>,
Channel<CH2,
M2>,
Channel<CH3,
M3>,
Channel<CH4,
M4>))
-> Timer<PwmFree>
where M1: ChMode,
M2: ChMode,
M3: ChMode,
M4: ChMode
{
unsafe { transmute(self) }
}
}
}
};
}
tim!(TIM2, APB1, tim2, tim2en, tim2rst);
tim!(TIM3, APB1, tim3, tim3en, tim3rst);
tim!(TIM4, APB1, tim4, tim4en, tim4rst);