diff --git a/src/design_parameters.rs b/src/design_parameters.rs index 40be7b6..125e133 100644 --- a/src/design_parameters.rs +++ b/src/design_parameters.rs @@ -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. 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; diff --git a/src/digital_input_stamper.rs b/src/digital_input_stamper.rs index 43ff9c5..85f248f 100644 --- a/src/digital_input_stamper.rs +++ b/src/digital_input_stamper.rs @@ -24,7 +24,7 @@ ///! ///! 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. -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. /// @@ -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. pub fn calculate_timestamp_timer_period() -> u32 { // 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 // `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 /// most one timestamp will occur in each data processing cycle. pub fn latest_timestamp(&mut self) -> Option { - if self.capture_channel.check_overcapture() { - panic!("DI0 timestamp overrun"); - } - - self.capture_channel.latest_capture() + self.capture_channel + .latest_capture() + .expect("DI0 timestamp overrun") } } diff --git a/src/main.rs b/src/main.rs index 52c5650..ede498f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -318,7 +318,8 @@ const APP: () = { // timer, but use a period that is longer. 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 @@ -543,7 +544,7 @@ const APP: () = { let qspi = hal::qspi::Qspi::bank2( dp.QUADSPI, qspi_pins, - 40.mhz(), + design_parameters::POUNDER_QSPI_FREQUENCY, &ccdr.clocks, ccdr.peripheral.QSPI, ); @@ -665,30 +666,26 @@ const APP: () = { ccdr.peripheral.HRTIM, ); - // 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. - // - // 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. + // IO_Update occurs after a fixed delay from the QSPI write. 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::Channel::Two, - 50_e-9, - 900_e-9, + design_parameters::POUNDER_IO_UPDATE_DURATION, + design_parameters::POUNDER_IO_UPDATE_DELAY, ); // Ensure that we have enough time for an IO-update every sample. - let sample_frequency = - (design_parameters::TIMER_FREQUENCY.0 as f32 - * 1_000_000.0) - / ADC_SAMPLE_TICKS as f32; + let sample_frequency = (design_parameters::TIMER_FREQUENCY.0 + as f32 + * 1_000_000.0) + / ADC_SAMPLE_TICKS as f32; let sample_period = 1.0 / sample_frequency; - assert!(sample_period > 900_e-9); + assert!( + sample_period + > design_parameters::POUNDER_IO_UPDATE_DELAY + ); hrtimer }; diff --git a/src/timers.rs b/src/timers.rs index 8afa5cd..5ffbeaf 100644 --- a/src/timers.rs +++ b/src/timers.rs @@ -147,17 +147,25 @@ macro_rules! timer_channels { impl [< Channel $index InputCapture >] { /// Get the latest capture from the channel. #[allow(dead_code)] - pub fn latest_capture(&mut self) -> Option { + pub fn latest_capture(&mut self) -> Result, ()> { // 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() }; let sr = regs.sr.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()); Some(ccx.ccr().bits()) } else { None + }; + + // If there is an overcapture, return an error. + if sr.[< cc $index of >]().bit_is_clear() { + Ok(result) + } else { + Err(()) } }