Last active
August 25, 2019 05:50
-
-
Save mvirkkunen/ab21c59448df08072245c5f5c3747743 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use vcell::VolatileCell; | |
use stm32f1xx_hal::dma::Event; | |
use stm32f1xx_hal::dma::dma1; | |
use stm32f1xx_hal::stm32::TIM1; | |
pub type DmaBuffer = [VolatileCell<u16>]; | |
pub struct PulseInput { | |
dma: dma1::C2, | |
tim: TIM1, | |
dma_buf: &'static mut DmaBuffer, | |
synced: bool, | |
} | |
impl PulseInput { | |
pub fn new( | |
tim: TIM1, | |
dma: dma1::C2, | |
prescaler: u16, | |
sync_len: u16, | |
dma_buf: &'static mut DmaBuffer) -> PulseInput | |
{ | |
let mut pi = PulseInput { | |
dma, | |
tim, | |
dma_buf, | |
synced: false, | |
}; | |
pi.init(prescaler, sync_len); | |
pi | |
} | |
pub fn listen(&mut self) { | |
self.dma.listen(Event::TransferComplete); | |
self.tim.dier.modify(|_, w| w.uie().set_bit()); | |
} | |
pub fn unlisten(&mut self) { | |
self.dma.unlisten(Event::TransferComplete); | |
self.tim.dier.modify(|_, w| w.uie().clear_bit()); | |
} | |
fn init(&mut self, prescaler: u16, sync_len: u16) { | |
self.dma.set_peripheral_address(&self.tim.dmar as *const _ as *const u32 as u32, false); | |
self.dma.set_memory_address(self.dma_buf as *const _ as *const u16 as u32, true); | |
// Memory size 16 bits, peripheral size 16 bits, memory increment | |
unsafe { | |
self.dma.ch().cr.modify(|_, w| w | |
.msize().bits(0b01) | |
.psize().bits(0b01) | |
.minc().set_bit()); | |
} | |
// Prescale timer | |
self.tim.psc.modify(|_, w| w.psc().bits(prescaler)); | |
// Only overflow generates events | |
self.tim.cr1.modify(|_, w| w.urs().set_bit()); | |
unsafe { | |
// Map both CC1 and CC2 to input TI1 (PA8), 8 clock filter | |
self.tim.ccmr1_input().modify(|_, w| w | |
.ic1f().bits(0b0011) | |
.cc1s().bits(0b01) | |
.ic2f().bits(0b0011) | |
.cc2s().bits(0b10)); | |
// Slave mode trigger = TI1FP1, slave mode selection = reset | |
self.tim.smcr.modify(|_, w| w | |
.ts().bits(0b101) | |
.sms().bits(0b100)); | |
// DMA burst length = 2, base address = CCR1 | |
self.tim.dcr.modify(|_, w| w.dbl().bits(1).dba().bits(13)); | |
} | |
// CC1 captures on rising edge, CC2 captures on falling edge, enable both | |
self.tim.ccer.modify(|_, w| w | |
.cc1p().clear_bit() | |
.cc1e().set_bit() | |
.cc2p().set_bit() | |
.cc2e().set_bit()); | |
// Set ARR to sync_len worth of ticks | |
self.tim.arr.modify(|_, w| w.arr().bits(sync_len)); | |
self.start_sync(); | |
} | |
fn start_sync(&mut self) { | |
self.synced = false; | |
// Reset timer | |
unsafe { | |
self.tim.cnt.modify(|_, w| w.bits(0)); | |
} | |
self.tim.egr.write(|w| w.ug().set_bit()); | |
self.tim.sr.modify(|_, w| w.cc1if().clear_bit().uif().clear_bit()); | |
// Enable timer | |
self.tim.cr1.modify(|_, w| w.cen().set_bit()); | |
} | |
fn start_capture(&mut self) { | |
self.dma.stop(); | |
// Reset timer | |
unsafe { | |
self.tim.cnt.modify(|_, w| w.bits(0)); | |
} | |
self.tim.egr.write(|w| w.ug().set_bit()); | |
// Clear interrupt bits | |
self.tim.sr.modify(|_, w| w.cc1if().clear_bit().uif().clear_bit()); | |
self.dma.ifcr().write(|w| w.ctcif2().set_bit()); | |
// Enable CC1 DMA request | |
self.tim.dier.modify(|_, w| w.cc1de().set_bit()); | |
self.dma.set_transfer_length(self.dma_buf.len() & !1); | |
self.dma.start(); | |
// Enable timer | |
self.tim.cr1.modify(|_, w| w.cen().set_bit()); | |
} | |
fn get_pulse_train(&mut self) -> Option<PulseTrain> { | |
// Disable timer | |
self.tim.cr1.modify(|_, w| w.cen().clear_bit()); | |
self.dma.stop(); | |
// Clear DMA interrupt | |
self.dma.ifcr().write(|w| w.ctcif2().set_bit()); | |
// Disable CC1 DMA request | |
self.tim.dier.modify(|_, w| w.cc1de().clear_bit()); | |
let count = (self.dma_buf.len() - self.dma.get_ndtr() as usize) / 2; | |
if count > 1 { | |
Some(PulseTrain { | |
parent: self, | |
count, | |
i: 1, // first element is garbage | |
}) | |
} else { | |
self.start_sync(); | |
None | |
} | |
} | |
pub fn tim1_isr(&mut self) -> Option<PulseTrain> { | |
if self.tim.sr.read().uif().bit_is_set() { | |
self.tim.sr.modify(|_, w| w.uif().clear_bit()); | |
if self.synced { | |
return self.get_pulse_train(); | |
} else { | |
self.synced = true; | |
self.start_capture(); | |
} | |
} | |
None | |
} | |
pub fn dma1_ch2_isr(&mut self) -> Option<PulseTrain> { | |
if self.dma.isr().tcif2().bit_is_set() { | |
self.synced = false; | |
self.get_pulse_train() | |
} else { | |
None | |
} | |
} | |
} | |
pub struct PulseTrain<'a> { | |
parent: &'a mut PulseInput, | |
count: usize, | |
i: usize, | |
} | |
impl Iterator for PulseTrain<'_> { | |
type Item = (u16, u16); | |
fn next(&mut self) -> Option<Self::Item> { | |
if self.i == self.count { | |
None | |
} else { | |
let r = Some(( | |
self.parent.dma_buf[self.i * 2].get(), | |
self.parent.dma_buf[self.i * 2 + 1].get(), | |
)); | |
self.i += 1; | |
r | |
} | |
} | |
fn size_hint(&self) -> (usize, Option<usize>) { | |
let left = self.count - self.i; | |
(left, Some(left)) | |
} | |
} | |
impl ExactSizeIterator for PulseTrain<'_> { } | |
impl Drop for PulseTrain<'_> { | |
fn drop(&mut self) { | |
//println!("drop"); | |
if self.parent.synced { | |
self.parent.start_capture(); | |
} else { | |
self.parent.start_sync(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment