aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mpm/python/usrp_mpm/cores/tdc_sync.py19
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/magnesium.py37
2 files changed, 49 insertions, 7 deletions
diff --git a/mpm/python/usrp_mpm/cores/tdc_sync.py b/mpm/python/usrp_mpm/cores/tdc_sync.py
index bb4695cb6..e8e3262d1 100644
--- a/mpm/python/usrp_mpm/cores/tdc_sync.py
+++ b/mpm/python/usrp_mpm/cores/tdc_sync.py
@@ -196,7 +196,7 @@ class ClockSynchronizer(object):
meas_clk_freq = 170.542641116e6
measure_offset = lambda: self.read_tdc_meas(
- 1/meas_clk_freq, 1/self.ref_clk_freq, 1/self.radio_clk_freq
+ 1.0/meas_clk_freq, 1.0/self.ref_clk_freq, 1.0/self.radio_clk_freq
)
# Retrieve the first measurement, but throw it away since it won't align with
# all the re-run measurements.
@@ -208,7 +208,14 @@ class ClockSynchronizer(object):
self.log.trace("Reading {} TDC measurements from device...".format(num_meas))
current_value = mean([measure_offset() for _ in range(num_meas)])
- if (current_value < 120e-9) or (current_value > 150e-9):
+ # The high and low bounds for this are set programmatically based on the
+ # Reference and Sample Frequencies and the TDC structure. The bounds are:
+ # Low = T_refclk + T_sampleclk*(3)
+ # High = T_refclk + T_sampleclk*(4)
+ # For slop, we add in another T_sampleclk on either side.
+ low_bound = 1.0/self.ref_clk_freq + (1.0/self.radio_clk_freq)*2
+ high_bound = 1.0/self.ref_clk_freq + (1.0/self.radio_clk_freq)*5
+ if (current_value < low_bound) or (current_value > high_bound):
self.log.error("Clock synchronizer measured a "
"current value of {:.3f} ns!".format(
current_value*1e9
@@ -245,9 +252,9 @@ class ClockSynchronizer(object):
def read_tdc_meas(
self,
- meas_clk_period=1/170.542641116e6,
- ref_clk_period=1/10e6,
- radio_clk_period=1/104e6
+ meas_clk_period=1.0/170.542641116e6,
+ ref_clk_period=1.0/10e6,
+ radio_clk_period=1.0/104e6
):
"""
Return the offset (in seconds) the whatever what measured and whatever
@@ -307,7 +314,7 @@ class ClockSynchronizer(object):
))
# Determine the sign.
sign = 1 if distance_to_target >= 0 else -1
- coarse_step_size = 1/lmk_vco_freq
+ coarse_step_size = 1.0/lmk_vco_freq
# For negative input values, divmod occasionally returns coarse steps -1 from
# the correct value. To combat this blatent crime, I just give it a positive value
# and then sign-correct afterwards.
diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
index f5d17a3f4..7cc1ca965 100644
--- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py
+++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
@@ -173,6 +173,23 @@ class Magnesium(DboardManagerBase):
pdac_spi.poke16(0x0, init_phase_dac_word)
self.spi_lock = self._device.get_spi_lock()
return LMK04828Mg(lmk_spi, self.spi_lock, ref_clk_freq, slot_idx)
+ def _sync_db_clock(synchronizer):
+ " Synchronizes the DB clock to the common reference "
+ synchronizer.run_sync(measurement_only=False)
+ offset_error = synchronizer.run_sync(measurement_only=True)
+ if offset_error > 100e-12:
+ self.log.error("Clock synchronizer measured an offset of {:.1f} ps!".format(
+ offset_error*1e12
+ ))
+ raise RuntimeError("Clock synchronizer measured an offset of {:.1f} ps!".format(
+ offset_error*1e12
+ ))
+ else:
+ self.log.debug("Residual DAC offset error: {:.1f} ps.".format(
+ offset_error*1e12
+ ))
+ self.log.info("Sample Clock Synchronization Complete!")
+
self.log.info("init() called with args `{}'".format(
@@ -184,7 +201,6 @@ class Magnesium(DboardManagerBase):
self._spi_ifaces = _init_spi_devices()
self.log.info("Loaded SPI interfaces!")
self.dboard_clk_control = _init_clock_control(self.radio_regs)
-
self.lmk = _init_lmk(
self.slot_idx,
self._spi_ifaces['lmk'],
@@ -194,6 +210,25 @@ class Magnesium(DboardManagerBase):
)
self.dboard_clk_control.enable_mmcm()
self.log.info("Sample Clocks and Phase DAC Configured Successfully!")
+ # Synchronize DB Clocks
+ self.clock_synchronizer = ClockSynchronizer(
+ self.radio_regs,
+ self.dboard_clk_control,
+ self.lmk,
+ self._spi_ifaces['phase_dac'],
+ 0, # TODO this might not actually be zero
+ 125e6, # TODO don't hardcode
+ self.ref_clock_freq,
+ 860E-15, # TODO don't hardcode. This should live in the EEPROM
+ self.INIT_PHASE_DAC_WORD,
+ 3e9, # lmk_vco_freq
+ [128e-9,], # target_values
+ 0x0, # spi_addr TODO: make this a constant and replace in _sync_db_clock as well
+ self.log
+ )
+ _sync_db_clock(self.clock_synchronizer)
+ # Clocks and PPS are now fully active!
+
self.init_jesd(self.radio_regs)