Updating timestamper after testing
This commit is contained in:
parent
3886dab961
commit
645a1cd832
|
@ -8,10 +8,10 @@
|
|||
///!
|
||||
///! # Design
|
||||
///! An input capture channel is configured on DI0 and fed into TIM5's capture channel 4. TIM5 is
|
||||
///! then run in a free-running mode with a configured frequency and period. Whenever an edge on DI0
|
||||
///! triggers, the current TIM5 counter value is captured and recorded as a timestamp. This timestamp can be
|
||||
///! either directly read from the timer channel or can be collected asynchronously via DMA
|
||||
///! collection.
|
||||
///! then run in a free-running mode with a configured tick rate (PSC) and maximum count value
|
||||
///! (ARR). Whenever an edge on DI0 triggers, the current TIM5 counter value is captured and
|
||||
///! recorded as a timestamp. This timestamp can be either directly read from the timer channel or
|
||||
///! can be collected asynchronously via DMA collection.
|
||||
///!
|
||||
///! When DMA is used for timestamp collection, a DMA transfer is configured to collect as many
|
||||
///! timestamps as there are samples, but it is intended that this DMA transfer should never
|
||||
|
@ -19,9 +19,9 @@
|
|||
///! checks to see how many timestamps were collected. These collected timestamps are then returned
|
||||
///! for further processing.
|
||||
///!
|
||||
///! To prevent silently discarding timestamps, the TIM5 input capture over-capture interrupt is
|
||||
///! used. Any over-capture event (which indicates an overwritten timestamp) then generates an ISR
|
||||
///! which handles the over-capture.
|
||||
///! To prevent silently discarding timestamps, the TIM5 input capture over-capture flag is
|
||||
///! continually checked. Any over-capture event (which indicates an overwritten timestamp) then
|
||||
///! triggers a panic to indicate the dropped timestamp so that design parameters can be adjusted.
|
||||
///!
|
||||
///! # Tradeoffs
|
||||
///! It appears that DMA transfers can take a significant amount of time to disable (400ns) if they
|
||||
|
@ -77,9 +77,6 @@ impl InputStamper {
|
|||
let input_capture =
|
||||
timer_channel.to_input_capture(timers::tim5::CC4S_A::TI4);
|
||||
|
||||
// Listen for over-capture events, which indicates an over-run of DI0 timestamps.
|
||||
input_capture.listen_overcapture();
|
||||
|
||||
// For small batch sizes, the overhead of DMA can become burdensome to the point where
|
||||
// timing is not met. The DMA requires 500ns overhead, whereas a direct register read only
|
||||
// requires ~80ns. When batches of 2-or-greater are used, use a DMA-based approach.
|
||||
|
@ -89,7 +86,7 @@ impl InputStamper {
|
|||
// Set up the DMA transfer.
|
||||
let dma_config = DmaConfig::default().memory_increment(true);
|
||||
|
||||
let mut timestamp_transfer: Transfer<_, _, PeripheralToMemory, _> =
|
||||
let timestamp_transfer: Transfer<_, _, PeripheralToMemory, _> =
|
||||
Transfer::init(
|
||||
stream,
|
||||
input_capture,
|
||||
|
@ -97,8 +94,6 @@ impl InputStamper {
|
|||
None,
|
||||
dma_config,
|
||||
);
|
||||
|
||||
timestamp_transfer.start(|_| {});
|
||||
(Some(timestamp_transfer), None)
|
||||
} else {
|
||||
(None, Some(input_capture))
|
||||
|
@ -112,12 +107,29 @@ impl InputStamper {
|
|||
}
|
||||
}
|
||||
|
||||
/// Start capture timestamps on DI0.
|
||||
pub fn start(&mut self) {
|
||||
if let Some(transfer) = &mut self.transfer {
|
||||
transfer.start(|capture_channel| {
|
||||
capture_channel.enable();
|
||||
});
|
||||
} else {
|
||||
self.capture_channel.as_mut().unwrap().enable();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get all of the timestamps that have occurred during the last processing cycle.
|
||||
pub fn acquire_buffer(&mut self) -> &[u32] {
|
||||
// If we are using DMA, finish the transfer and swap over buffers.
|
||||
if self.transfer.is_some() {
|
||||
let next_buffer = self.next_buffer.take().unwrap();
|
||||
|
||||
self.transfer.as_mut().unwrap().pause(|channel| {
|
||||
if channel.check_overcapture() {
|
||||
panic!("DI0 timestamp overrun");
|
||||
}
|
||||
});
|
||||
|
||||
let (prev_buffer, _, remaining_transfers) = self
|
||||
.transfer
|
||||
.as_mut()
|
||||
|
@ -132,6 +144,10 @@ impl InputStamper {
|
|||
// timestamps actually collected.
|
||||
&self.next_buffer.as_ref().unwrap()[..valid_count]
|
||||
} else {
|
||||
if self.capture_channel.as_ref().unwrap().check_overcapture() {
|
||||
panic!("DI0 timestamp overrun");
|
||||
}
|
||||
|
||||
// If we aren't using DMA, just manually check the input capture channel for a
|
||||
// timestamp.
|
||||
match self.capture_channel.as_mut().unwrap().latest_capture() {
|
||||
|
|
12
src/main.rs
12
src/main.rs
|
@ -58,10 +58,10 @@ use heapless::{consts::*, String};
|
|||
|
||||
// The number of ticks in the ADC sampling timer. The timer runs at 100MHz, so the step size is
|
||||
// equal to 10ns per tick.
|
||||
const ADC_SAMPLE_TICKS: u32 = 128;
|
||||
const ADC_SAMPLE_TICKS: u32 = 256;
|
||||
|
||||
// The desired ADC sample processing buffer size.
|
||||
const SAMPLE_BUFFER_SIZE: usize = 8;
|
||||
const SAMPLE_BUFFER_SIZE: usize = 1;
|
||||
|
||||
// The number of cascaded IIR biquads per channel. Select 1 or 2!
|
||||
const IIR_CASCADE_LENGTH: usize = 1;
|
||||
|
@ -831,7 +831,7 @@ const APP: () = {
|
|||
// Utilize the cycle counter for RTIC scheduling.
|
||||
cp.DWT.enable_cycle_counter();
|
||||
|
||||
let input_stamper = {
|
||||
let mut input_stamper = {
|
||||
let trigger = gpioa.pa3.into_alternate_af2();
|
||||
digital_input_stamper::InputStamper::new(
|
||||
trigger,
|
||||
|
@ -844,6 +844,7 @@ const APP: () = {
|
|||
// Start sampling ADCs.
|
||||
sampling_timer.start();
|
||||
timestamp_timer.start();
|
||||
input_stamper.start();
|
||||
|
||||
init::LateResources {
|
||||
afes: (afe0, afe1),
|
||||
|
@ -1085,11 +1086,6 @@ const APP: () = {
|
|||
panic!("DAC1 output error");
|
||||
}
|
||||
|
||||
#[task(binds = TIM5, priority = 3)]
|
||||
fn di0(_: di0::Context) {
|
||||
panic!("DI0 timestamp overrun");
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
// hw interrupt handlers for RTIC to use for scheduling tasks
|
||||
// one per priority
|
||||
|
|
|
@ -32,21 +32,6 @@ macro_rules! timer_channels {
|
|||
self.channels.take().unwrap()
|
||||
}
|
||||
|
||||
/// Get the prescaler of a timer.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_prescaler(&self) -> u16 {
|
||||
let regs = unsafe { &*hal::stm32::$TY::ptr() };
|
||||
regs.psc.read().psc().bits() + 1
|
||||
}
|
||||
|
||||
/// Manually set the prescaler of the timer.
|
||||
#[allow(dead_code)]
|
||||
pub fn set_prescaler(&mut self, prescaler: u16) {
|
||||
let regs = unsafe { &*hal::stm32::$TY::ptr() };
|
||||
assert!(prescaler >= 1);
|
||||
regs.psc.write(|w| w.psc().bits(prescaler - 1));
|
||||
}
|
||||
|
||||
/// Get the period of the timer.
|
||||
#[allow(dead_code)]
|
||||
pub fn get_period(&self) -> u32 {
|
||||
|
@ -176,20 +161,6 @@ macro_rules! timer_channels {
|
|||
}
|
||||
}
|
||||
|
||||
/// Listen for over-capture events on the timer channel.
|
||||
///
|
||||
/// # Note
|
||||
/// An over-capture event is when a previous capture was lost due to a new capture.
|
||||
///
|
||||
/// "Listening" is equivalent to enabling the interrupt for the event.
|
||||
#[allow(dead_code)]
|
||||
pub fn listen_overcapture(&self) {
|
||||
// Note(unsafe): This channel owns all access to the specific timer channel.
|
||||
// Only atomic operations on completed on the timer registers.
|
||||
let regs = unsafe { &*<$TY>::ptr() };
|
||||
regs.dier.modify(|_, w| w.[<cc $index ie>]().set_bit());
|
||||
}
|
||||
|
||||
/// Allow the channel to generate DMA requests.
|
||||
#[allow(dead_code)]
|
||||
pub fn listen_dma(&self) {
|
||||
|
@ -198,6 +169,24 @@ macro_rules! timer_channels {
|
|||
let regs = unsafe { &*<$TY>::ptr() };
|
||||
regs.dier.modify(|_, w| w.[< cc $index de >]().set_bit());
|
||||
}
|
||||
|
||||
/// Enable the input capture to begin capturing timer values.
|
||||
#[allow(dead_code)]
|
||||
pub fn enable(&mut self) {
|
||||
// Note(unsafe): This channel owns all access to the specific timer channel.
|
||||
// Only atomic operations on completed on the timer registers.
|
||||
let regs = unsafe { &*<$TY>::ptr() };
|
||||
regs.ccer.modify(|_, w| w.[< cc $index e >]().set_bit());
|
||||
}
|
||||
|
||||
/// Check if an over-capture event has occurred.
|
||||
#[allow(dead_code)]
|
||||
pub fn check_overcapture(&self) -> bool {
|
||||
// Note(unsafe): This channel owns all access to the specific timer channel.
|
||||
// Only atomic operations on completed on the timer registers.
|
||||
let regs = unsafe { &*<$TY>::ptr() };
|
||||
regs.sr.read().[< cc $index of >]().bit_is_set()
|
||||
}
|
||||
}
|
||||
|
||||
// Note(unsafe): This manually implements DMA support for input-capture channels. This
|
||||
|
|
Loading…
Reference in New Issue