use super::hal;
use num_enum::TryFromPrimitive;
use hal::stm32::{
tim1 as __tim8,
tim2 as __tim2,
tim2 as __tim5,
tim3 as __tim3,
};
#[allow(dead_code)]
pub enum TriggerGenerator {
Reset = 0b000,
Enable = 0b001,
Update = 0b010,
ComparePulse = 0b011,
Ch1Compare = 0b100,
Ch2Compare = 0b101,
Ch3Compare = 0b110,
Ch4Compare = 0b111,
}
#[allow(dead_code)]
pub enum TriggerSource {
Trigger0 = 0,
Trigger1 = 0b01,
Trigger2 = 0b10,
Trigger3 = 0b11,
}
#[allow(dead_code)]
#[derive(TryFromPrimitive)]
#[repr(u8)]
pub enum Prescaler {
Div1 = 0b00,
Div2 = 0b01,
Div4 = 0b10,
Div8 = 0b11,
}
#[allow(dead_code)]
pub enum SlaveMode {
Disabled = 0,
Trigger = 0b0110,
}
#[allow(dead_code)]
pub enum InputFilter {
Div1N1 = 0b0000,
Div1N8 = 0b0011,
}
macro_rules! timer_channels {
($name:ident, $TY:ident, $size:ty) => {
paste::paste! {
pub struct $name {
timer: hal::timer::Timer<hal::stm32::[< $TY >]>,
channels: Option<[< $TY:lower >]::Channels>,
update_event: Option<[< $TY:lower >]::UpdateEvent>,
}
impl $name {
#[allow(dead_code)]
pub fn new(mut timer: hal::timer::Timer<hal::stm32::[< $TY>]>) -> Self {
timer.pause();
Self {
timer,
channels: unsafe { Some([< $TY:lower >]::Channels::new()) },
update_event: unsafe { Some([< $TY:lower >]::UpdateEvent::new()) },
}
}
#[allow(dead_code)]
pub fn channels(&mut self) -> [< $TY:lower >]::Channels {
self.channels.take().unwrap()
}
#[allow(dead_code)]
pub fn update_event(&mut self) -> [< $TY:lower >]::UpdateEvent {
self.update_event.take().unwrap()
}
#[allow(dead_code)]
pub fn get_period(&self) -> $size {
let regs = unsafe { &*hal::stm32::$TY::ptr() };
regs.arr.read().arr().bits()
}
#[allow(dead_code)]
pub fn set_period_ticks(&mut self, period: $size) {
let regs = unsafe { &*hal::stm32::$TY::ptr() };
regs.arr.write(|w| w.arr().bits(period));
self.timer.apply_freq();
}
#[allow(dead_code)]
pub fn set_external_clock(&mut self, prescaler: Prescaler) {
let regs = unsafe { &*hal::stm32::$TY::ptr() };
regs.smcr.modify(|_, w| w.etps().bits(prescaler as u8).ece().set_bit());
regs.psc.write(|w| w.psc().bits(0));
}
#[allow(dead_code)]
pub fn start(&mut self) {
self.timer.apply_freq();
self.timer.reset_counter();
self.timer.resume();
}
#[allow(dead_code)]
pub fn generate_trigger(&mut self, source: TriggerGenerator) {
let regs = unsafe { &*hal::stm32::$TY::ptr() };
regs.cr2.modify(|_, w| w.mms().bits(source as u8));
}
#[allow(dead_code)]
pub fn set_trigger_source(&mut self, source: TriggerSource) {
let regs = unsafe { &*hal::stm32::$TY::ptr() };
regs.smcr.modify(|_, w| unsafe { w.ts().bits(source as u8) } );
}
#[allow(dead_code)]
pub fn set_slave_mode(&mut self, source: TriggerSource, mode: SlaveMode) {
let regs = unsafe { &*hal::stm32::$TY::ptr() };
regs.smcr.modify(|_, w| unsafe { w.sms().bits(mode as u8).ts().bits(source as u8) } );
}
}
pub mod [< $TY:lower >] {
use stm32h7xx_hal as hal;
use hal::dma::{traits::TargetAddress, PeripheralToMemory, dma::DMAReq};
use hal::stm32::$TY;
pub struct UpdateEvent {}
impl UpdateEvent {
#[allow(dead_code)]
pub unsafe fn new() -> Self {
Self {}
}
#[allow(dead_code)]
pub fn listen_dma(&self) {
let regs = unsafe { &*<$TY>::ptr() };
regs.dier.modify(|_, w| w.ude().set_bit());
}
#[allow(dead_code)]
pub fn trigger(&self) {
let regs = unsafe { &*<$TY>::ptr() };
regs.egr.write(|w| w.ug().set_bit());
}
}
pub struct Channels {
pub ch1: Channel1,
pub ch2: Channel2,
pub ch3: Channel3,
pub ch4: Channel4,
}
impl Channels {
#[allow(dead_code)]
pub unsafe fn new() -> Self {
Self {
ch1: Channel1::new(),
ch2: Channel2::new(),
ch3: Channel3::new(),
ch4: Channel4::new(),
}
}
}
timer_channels!(1, $TY, ccmr1, $size);
timer_channels!(2, $TY, ccmr1, $size);
timer_channels!(3, $TY, ccmr2, $size);
timer_channels!(4, $TY, ccmr2, $size);
}
}
};
($index:expr, $TY:ty, $ccmrx:expr, $size:ty) => {
paste::paste! {
pub use super::[< __ $TY:lower >]::[< $ccmrx _input >]::[< CC $index S_A>] as [< CaptureSource $index >];
pub struct [< Channel $index >] {}
pub struct [< Channel $index InputCapture>] {}
impl [< Channel $index >] {
#[allow(dead_code)]
unsafe fn new() -> Self {
Self {}
}
#[allow(dead_code)]
pub fn listen_dma(&self) {
let regs = unsafe { &*<$TY>::ptr() };
regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit());
}
#[allow(dead_code)]
pub fn to_output_compare(&self, value: $size) {
let regs = unsafe { &*<$TY>::ptr() };
let arr = regs.arr.read().bits() as $size;
assert!(value <= arr);
regs.ccr[$index - 1].write(|w| w.ccr().bits(value));
regs.[< $ccmrx _output >]()
.modify(|_, w| unsafe { w.[< cc $index s >]().bits(0) });
}
#[allow(dead_code)]
pub fn into_input_capture(self, input: [< CaptureSource $index >]) -> [< Channel $index InputCapture >]{
let regs = unsafe { &*<$TY>::ptr() };
regs.[< $ccmrx _input >]().modify(|_, w| w.[< cc $index s>]().variant(input));
[< Channel $index InputCapture >] {}
}
}
impl [< Channel $index InputCapture >] {
#[allow(dead_code)]
pub fn latest_capture(&mut self) -> Result<Option<$size>, Option<$size>> {
let regs = unsafe { &*<$TY>::ptr() };
if regs.sr.read().[< cc $index if >]().bit_is_set() {
let result = regs.ccr[$index - 1].read().ccr().bits();
let sr = regs.sr.read();
if sr.[< cc $index of >]().bit_is_set() {
regs.sr.write(|w| unsafe { w.bits(sr.bits()) }.[< cc $index of >]().clear_bit());
Err(Some(result))
} else {
Ok(Some(result))
}
} else {
Ok(None)
}
}
#[allow(dead_code)]
pub fn listen_dma(&self) {
let regs = unsafe { &*<$TY>::ptr() };
regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit());
}
#[allow(dead_code)]
pub fn enable(&mut self) {
let _ = self.latest_capture();
let regs = unsafe { &*<$TY>::ptr() };
regs.ccer.modify(|_, w| w.[< cc $index e >]().set_bit());
}
#[allow(dead_code)]
pub fn check_overcapture(&self) -> bool {
let regs = unsafe { &*<$TY>::ptr() };
regs.sr.read().[< cc $index of >]().bit_is_set()
}
#[allow(dead_code)]
pub fn configure_filter(&mut self, filter: super::InputFilter) {
let regs = unsafe { &*<$TY>::ptr() };
regs.[< $ccmrx _input >]().modify(|_, w| w.[< ic $index f >]().bits(filter as u8));
}
#[allow(dead_code)]
pub fn configure_prescaler(&mut self, prescaler: super::Prescaler) {
let regs = unsafe { &*<$TY>::ptr() };
#[allow(unused_unsafe)]
regs.[< $ccmrx _input >]().modify(|_, w| unsafe {
w.[< ic $index psc >]().bits(prescaler as u8)});
}
}
unsafe impl TargetAddress<PeripheralToMemory> for [< Channel $index InputCapture >] {
type MemSize = $size;
const REQUEST_LINE: Option<u8> = Some(DMAReq::[< $TY:camel Ch $index >]as u8);
fn address(&self) -> usize {
let regs = unsafe { &*<$TY>::ptr() };
®s.ccr[$index - 1] as *const _ as usize
}
}
}
};
}
timer_channels!(SamplingTimer, TIM2, u32);
timer_channels!(ShadowSamplingTimer, TIM3, u16);
timer_channels!(TimestampTimer, TIM5, u32);
timer_channels!(PounderTimestampTimer, TIM8, u16);