More updates after PR review
This commit is contained in:
parent
67b6990fc0
commit
7ecd08d86b
|
@ -9,3 +9,18 @@ pub const ADC_DAC_SCK_MAX: MegaHertz = MegaHertz(50);
|
||||||
|
|
||||||
/// The optimal counting frequency of the hardware timers used for timestamping and sampling.
|
/// The optimal counting frequency of the hardware timers used for timestamping and sampling.
|
||||||
pub const TIMER_FREQUENCY: MegaHertz = MegaHertz(100);
|
pub const TIMER_FREQUENCY: MegaHertz = MegaHertz(100);
|
||||||
|
|
||||||
|
/// The QSPI frequency for communicating with the pounder DDS.
|
||||||
|
pub const POUNDER_QSPI_FREQUENCY: MegaHertz = MegaHertz(40);
|
||||||
|
|
||||||
|
/// The delay after initiating a QSPI transfer before asserting the IO_Update for the pounder DDS.
|
||||||
|
// Pounder Profile writes are always 16 bytes, with 2 cycles required per byte, coming out to a
|
||||||
|
// total of 32 QSPI clock cycles. The QSPI is configured for 40MHz, so this comes out to an offset
|
||||||
|
// of 800nS. We use 900ns to be safe.
|
||||||
|
pub const POUNDER_IO_UPDATE_DELAY: f32 = 900_e-9;
|
||||||
|
|
||||||
|
/// The duration to assert IO_Update for the pounder DDS.
|
||||||
|
// IO_Update should be latched for 4 SYNC_CLK cycles after the QSPI profile write. With pounder
|
||||||
|
// SYNC_CLK running at 100MHz (1/4 of the pounder reference clock of 400MHz), this corresponds to
|
||||||
|
// 40ns. To accomodate rounding errors, we use 50ns instead.
|
||||||
|
pub const POUNDER_IO_UPDATE_DURATION: f32 = 50_e-9;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
///!
|
///!
|
||||||
///! This module only supports DI0 for timestamping due to trigger constraints on the DIx pins. If
|
///! This module only supports DI0 for timestamping due to trigger constraints on the DIx pins. If
|
||||||
///! timestamping is desired in DI1, a separate timer + capture channel will be necessary.
|
///! timestamping is desired in DI1, a separate timer + capture channel will be necessary.
|
||||||
use super::{hal, timers, SAMPLE_BUFFER_SIZE, ADC_SAMPLE_TICKS};
|
use super::{hal, timers, ADC_SAMPLE_TICKS, SAMPLE_BUFFER_SIZE};
|
||||||
|
|
||||||
/// Calculate the period of the digital input timestampe timer.
|
/// Calculate the period of the digital input timestampe timer.
|
||||||
///
|
///
|
||||||
|
@ -39,7 +39,8 @@ use super::{hal, timers, SAMPLE_BUFFER_SIZE, ADC_SAMPLE_TICKS};
|
||||||
/// A 32-bit value that can be programmed into a hardware timer period register.
|
/// A 32-bit value that can be programmed into a hardware timer period register.
|
||||||
pub fn calculate_timestamp_timer_period() -> u32 {
|
pub fn calculate_timestamp_timer_period() -> u32 {
|
||||||
// Calculate how long a single batch requires in timer ticks.
|
// Calculate how long a single batch requires in timer ticks.
|
||||||
let batch_duration_ticks: u64 = SAMPLE_BUFFER_SIZE as u64 * ADC_SAMPLE_TICKS as u64;
|
let batch_duration_ticks: u64 =
|
||||||
|
SAMPLE_BUFFER_SIZE as u64 * ADC_SAMPLE_TICKS as u64;
|
||||||
|
|
||||||
// Calculate the largest power-of-two that is less than or equal to
|
// Calculate the largest power-of-two that is less than or equal to
|
||||||
// `batches_per_overflow`. This is completed by eliminating the least significant
|
// `batches_per_overflow`. This is completed by eliminating the least significant
|
||||||
|
@ -101,10 +102,8 @@ impl InputStamper {
|
||||||
/// To prevent timestamp loss, the batch size and sampling rate must be adjusted such that at
|
/// To prevent timestamp loss, the batch size and sampling rate must be adjusted such that at
|
||||||
/// most one timestamp will occur in each data processing cycle.
|
/// most one timestamp will occur in each data processing cycle.
|
||||||
pub fn latest_timestamp(&mut self) -> Option<u32> {
|
pub fn latest_timestamp(&mut self) -> Option<u32> {
|
||||||
if self.capture_channel.check_overcapture() {
|
self.capture_channel
|
||||||
panic!("DI0 timestamp overrun");
|
.latest_capture()
|
||||||
}
|
.expect("DI0 timestamp overrun")
|
||||||
|
|
||||||
self.capture_channel.latest_capture()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
35
src/main.rs
35
src/main.rs
|
@ -318,7 +318,8 @@ const APP: () = {
|
||||||
// timer, but use a period that is longer.
|
// timer, but use a period that is longer.
|
||||||
let mut timer = timers::TimestampTimer::new(timer5);
|
let mut timer = timers::TimestampTimer::new(timer5);
|
||||||
|
|
||||||
let period = digital_input_stamper::calculate_timestamp_timer_period();
|
let period =
|
||||||
|
digital_input_stamper::calculate_timestamp_timer_period();
|
||||||
timer.set_period_ticks(period);
|
timer.set_period_ticks(period);
|
||||||
|
|
||||||
timer
|
timer
|
||||||
|
@ -543,7 +544,7 @@ const APP: () = {
|
||||||
let qspi = hal::qspi::Qspi::bank2(
|
let qspi = hal::qspi::Qspi::bank2(
|
||||||
dp.QUADSPI,
|
dp.QUADSPI,
|
||||||
qspi_pins,
|
qspi_pins,
|
||||||
40.mhz(),
|
design_parameters::POUNDER_QSPI_FREQUENCY,
|
||||||
&ccdr.clocks,
|
&ccdr.clocks,
|
||||||
ccdr.peripheral.QSPI,
|
ccdr.peripheral.QSPI,
|
||||||
);
|
);
|
||||||
|
@ -665,30 +666,26 @@ const APP: () = {
|
||||||
ccdr.peripheral.HRTIM,
|
ccdr.peripheral.HRTIM,
|
||||||
);
|
);
|
||||||
|
|
||||||
// IO_Update should be latched for 4 SYNC_CLK cycles after the QSPI profile
|
// IO_Update occurs after a fixed delay from the QSPI write. Note that the timer
|
||||||
// write. With pounder SYNC_CLK running at 100MHz (1/4 of the pounder reference
|
// is triggered after the QSPI write, which can take approximately 120nS, so
|
||||||
// clock of 400MHz), this corresponds to 40ns. To accomodate rounding errors, we
|
// there is additional margin.
|
||||||
// use 50ns instead.
|
|
||||||
//
|
|
||||||
// Profile writes are always 16 bytes, with 2 cycles required per byte, coming
|
|
||||||
// out to a total of 32 QSPI clock cycles. The QSPI is configured for 40MHz, so
|
|
||||||
// this comes out to an offset of 800nS. We use 900ns to be safe - note that the
|
|
||||||
// timer is triggered after the QSPI write, which can take approximately 120nS,
|
|
||||||
// so there is additional margin.
|
|
||||||
hrtimer.configure_single_shot(
|
hrtimer.configure_single_shot(
|
||||||
hrtimer::Channel::Two,
|
hrtimer::Channel::Two,
|
||||||
50_e-9,
|
design_parameters::POUNDER_IO_UPDATE_DURATION,
|
||||||
900_e-9,
|
design_parameters::POUNDER_IO_UPDATE_DELAY,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Ensure that we have enough time for an IO-update every sample.
|
// Ensure that we have enough time for an IO-update every sample.
|
||||||
let sample_frequency =
|
let sample_frequency = (design_parameters::TIMER_FREQUENCY.0
|
||||||
(design_parameters::TIMER_FREQUENCY.0 as f32
|
as f32
|
||||||
* 1_000_000.0)
|
* 1_000_000.0)
|
||||||
/ ADC_SAMPLE_TICKS as f32;
|
/ ADC_SAMPLE_TICKS as f32;
|
||||||
|
|
||||||
let sample_period = 1.0 / sample_frequency;
|
let sample_period = 1.0 / sample_frequency;
|
||||||
assert!(sample_period > 900_e-9);
|
assert!(
|
||||||
|
sample_period
|
||||||
|
> design_parameters::POUNDER_IO_UPDATE_DELAY
|
||||||
|
);
|
||||||
|
|
||||||
hrtimer
|
hrtimer
|
||||||
};
|
};
|
||||||
|
|
|
@ -147,17 +147,25 @@ macro_rules! timer_channels {
|
||||||
impl [< Channel $index InputCapture >] {
|
impl [< Channel $index InputCapture >] {
|
||||||
/// Get the latest capture from the channel.
|
/// Get the latest capture from the channel.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn latest_capture(&mut self) -> Option<u32> {
|
pub fn latest_capture(&mut self) -> Result<Option<u32>, ()> {
|
||||||
// Note(unsafe): This channel owns all access to the specific timer channel.
|
// Note(unsafe): This channel owns all access to the specific timer channel.
|
||||||
// Only atomic operations on completed on the timer registers.
|
// Only atomic operations on completed on the timer registers.
|
||||||
let regs = unsafe { &*<$TY>::ptr() };
|
let regs = unsafe { &*<$TY>::ptr() };
|
||||||
let sr = regs.sr.read();
|
let sr = regs.sr.read();
|
||||||
let ccx = regs.[< ccr $index >].read();
|
let ccx = regs.[< ccr $index >].read();
|
||||||
if sr.[< cc $index if >]().bit_is_set() {
|
|
||||||
|
let result = if sr.[< cc $index if >]().bit_is_set() {
|
||||||
regs.sr.modify(|_, w| w.[< cc $index if >]().clear_bit());
|
regs.sr.modify(|_, w| w.[< cc $index if >]().clear_bit());
|
||||||
Some(ccx.ccr().bits())
|
Some(ccx.ccr().bits())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// If there is an overcapture, return an error.
|
||||||
|
if sr.[< cc $index of >]().bit_is_clear() {
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue