Fixing pounder timestamps after manual testing

This commit is contained in:
Ryan Summers 2020-12-15 13:13:05 +01:00
parent 72d14adfbf
commit 352884ea06
5 changed files with 46 additions and 18 deletions

View File

@ -172,6 +172,17 @@ impl<I: Interface> Ad9959<I> {
// Set the clock frequency to configure the device as necessary. // Set the clock frequency to configure the device as necessary.
ad9959.configure_system_clock(clock_frequency, multiplier)?; ad9959.configure_system_clock(clock_frequency, multiplier)?;
// Latch the new clock configuration.
io_update.set_high().or(Err(Error::Pin))?;
// Delay for at least 1 SYNC_CLK period for the update to occur. The SYNC_CLK is guaranteed
// to be at least 250KHz (1/4 of 1MHz minimum REF_CLK). We use 5uS instead of 4uS to
// guarantee conformance with datasheet requirements.
delay.delay_us(5);
io_update.set_low().or(Err(Error::Pin))?;
Ok(ad9959) Ok(ad9959)
} }
@ -195,7 +206,7 @@ impl<I: Interface> Ad9959<I> {
/// ///
/// Returns: /// Returns:
/// The actual frequency configured for the internal system clock. /// The actual frequency configured for the internal system clock.
pub fn configure_system_clock( fn configure_system_clock(
&mut self, &mut self,
reference_clock_frequency: f32, reference_clock_frequency: f32,
multiplier: u8, multiplier: u8,

View File

@ -7,3 +7,12 @@ pub const ADC_DAC_SCK_MHZ_MAX: u32 = 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_MHZ: u32 = 100; pub const TIMER_FREQUENCY_MHZ: u32 = 100;
/// The DDS reference clock frequency in MHz.
pub const DDS_REF_CLK_MHZ: u32 = 100;
/// The multiplier used for the DDS reference clock PLL.
pub const DDS_MULTIPLIER: u8 = 5;
/// The rate of the DDS SYNC_CLK in MHz is always 1/4 that of the internal PLL clock.
pub const DDS_SYNC_CLK_MHZ: u32 = DDS_REF_CLK_MHZ * DDS_MULTIPLIER as u32 / 4;

View File

@ -527,7 +527,7 @@ const APP: () = {
delay.delay_ms(2u8); delay.delay_ms(2u8);
let (pounder_devices, dds_output) = if pounder_pgood.is_high().unwrap() let (pounder_devices, dds_output) = if pounder_pgood.is_high().unwrap()
{ {
let mut ad9959 = { let ad9959 = {
let qspi_interface = { let qspi_interface = {
// Instantiate the QUADSPI pins and peripheral interface. // Instantiate the QUADSPI pins and peripheral interface.
let qspi_pins = { let qspi_pins = {
@ -580,8 +580,8 @@ const APP: () = {
&mut io_update, &mut io_update,
&mut delay, &mut delay,
ad9959::Mode::FourBitSerial, ad9959::Mode::FourBitSerial,
100_000_000_f32, design_parameters::DDS_REF_CLK_MHZ as f32 * 1_000_000_f32,
5, design_parameters::DDS_MULTIPLIER,
) )
.unwrap(); .unwrap();
@ -660,7 +660,6 @@ const APP: () = {
let pounder_devices = pounder::PounderDevices::new( let pounder_devices = pounder::PounderDevices::new(
io_expander, io_expander,
&mut ad9959,
spi, spi,
adc1, adc1,
adc2, adc2,
@ -686,8 +685,8 @@ const APP: () = {
); );
// IO_Update should be latched for 4 SYNC_CLK cycles after the QSPI profile // 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 // write. With pounder SYNC_CLK running at 125MHz (1/4 of the pounder reference
// clock of 400MHz), this corresponds to 40ns. To accomodate rounding errors, we // clock of 500MHz), this corresponds to 32ns. To accomodate rounding errors, we
// use 50ns instead. // use 50ns instead.
// //
// Profile writes are always 16 bytes, with 2 cycles required per byte, coming // Profile writes are always 16 bytes, with 2 cycles required per byte, coming
@ -859,8 +858,21 @@ const APP: () = {
let tim8 = let tim8 =
dp.TIM8.timer(1.khz(), ccdr.peripheral.TIM8, &ccdr.clocks); dp.TIM8.timer(1.khz(), ccdr.peripheral.TIM8, &ccdr.clocks);
let mut timestamp_timer = timers::PounderTimestampTimer::new(tim8); let mut timestamp_timer = timers::PounderTimestampTimer::new(tim8);
// Pounder is configured to generate a 400MHz reference clock, so a 125MHz sync-clock is
// output. As a result, dividing the 125MHz sync-clk provides a 31.25MHz tick rate for
// the timestamp timer. 31.25MHz corresponds with a 32ns tick rate.
timestamp_timer.set_external_clock(timers::Prescaler::Div4); timestamp_timer.set_external_clock(timers::Prescaler::Div4);
timestamp_timer.set_period(128); timestamp_timer.start();
// We want the pounder timestamp timer to overflow once per batch.
let tick_ratio = design_parameters::DDS_SYNC_CLK_MHZ as f32
/ design_parameters::TIMER_FREQUENCY_MHZ as f32;
let period = (tick_ratio
* ADC_SAMPLE_TICKS as f32
* SAMPLE_BUFFER_SIZE as f32) as u32
/ 4;
timestamp_timer.set_period((period - 1).try_into().unwrap());
let tim8_channels = timestamp_timer.channels(); let tim8_channels = timestamp_timer.channels();
pounder::timestamp::Timestamper::new( pounder::timestamp::Timestamper::new(

View File

@ -275,7 +275,6 @@ impl PounderDevices {
/// Construct and initialize pounder-specific hardware. /// Construct and initialize pounder-specific hardware.
/// ///
/// Args: /// Args:
/// * `ad9959` - The DDS driver for the pounder hardware.
/// * `attenuator_spi` - A SPI interface to control digital attenuators. /// * `attenuator_spi` - A SPI interface to control digital attenuators.
/// * `adc1` - The ADC1 peripheral for measuring power. /// * `adc1` - The ADC1 peripheral for measuring power.
/// * `adc2` - The ADC2 peripheral for measuring power. /// * `adc2` - The ADC2 peripheral for measuring power.
@ -283,7 +282,6 @@ impl PounderDevices {
/// * `adc2_in_p` - The input channel for the RF power measurement on IN1. /// * `adc2_in_p` - The input channel for the RF power measurement on IN1.
pub fn new( pub fn new(
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>, mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
ad9959: &mut ad9959::Ad9959<QspiInterface>,
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>, attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>, adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
adc2: hal::adc::Adc<hal::stm32::ADC2, hal::adc::Enabled>, adc2: hal::adc::Adc<hal::stm32::ADC2, hal::adc::Enabled>,
@ -315,14 +313,10 @@ impl PounderDevices {
.write_gpio(mcp23017::Port::GPIOB, 1 << 5) .write_gpio(mcp23017::Port::GPIOB, 1 << 5)
.map_err(|_| Error::I2c)?; .map_err(|_| Error::I2c)?;
// Select the on-board clock with a 4x prescaler (400MHz).
devices devices
.mcp23017 .mcp23017
.digital_write(EXT_CLK_SEL_PIN, false) .digital_write(EXT_CLK_SEL_PIN, false)
.map_err(|_| Error::I2c)?; .map_err(|_| Error::I2c)?;
ad9959
.configure_system_clock(100_000_000f32, 4)
.map_err(|_| Error::Dds)?;
Ok(devices) Ok(devices)
} }

View File

@ -29,6 +29,8 @@ pub enum TriggerSource {
} }
pub enum Prescaler { pub enum Prescaler {
Div1 = 0b00,
Div2 = 0b01,
Div4 = 0b10, Div4 = 0b10,
Div8 = 0b11, Div8 = 0b11,
} }
@ -100,17 +102,17 @@ macro_rules! timer_channels {
let regs = unsafe { &*hal::stm32::$TY::ptr() }; let regs = unsafe { &*hal::stm32::$TY::ptr() };
regs.smcr.modify(|_, w| w.etps().bits(prescaler as u8).ece().set_bit()); regs.smcr.modify(|_, w| w.etps().bits(prescaler as u8).ece().set_bit());
// Use a DIV4 prescaler. // Clear any other prescaler configuration.
regs.psc.write(|w| w.psc().bits(0));
} }
/// Start the timer. /// Start the timer.
#[allow(dead_code)] #[allow(dead_code)]
pub fn start(mut self) { pub fn start(&mut self) {
// Force a refresh of the frequency settings. // Force a refresh of the frequency settings.
self.timer.apply_freq(); self.timer.apply_freq();
self.timer.reset_counter(); self.timer.reset_counter();
self.timer.resume(); self.timer.resume();
} }