Skip to content

Instantly share code, notes, and snippets.

@mvirkkunen
Last active August 25, 2019 05:50
Show Gist options
  • Save mvirkkunen/ab21c59448df08072245c5f5c3747743 to your computer and use it in GitHub Desktop.
Save mvirkkunen/ab21c59448df08072245c5f5c3747743 to your computer and use it in GitHub Desktop.
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