aboutsummaryrefslogtreecommitdiffstats
path: root/mpm/python/usrp_mpm/dboard_manager/magnesium.py
diff options
context:
space:
mode:
authorDaniel Jepson <daniel.jepson@ni.com>2018-08-02 09:00:01 -0500
committerMartin Braun <martin.braun@ettus.com>2018-08-02 12:37:34 -0700
commit065740babdea2cac56473db040cd67b84f3fa598 (patch)
treeee335769fb98a612663dfef0d85ff2d5c51130d0 /mpm/python/usrp_mpm/dboard_manager/magnesium.py
parent5f624d6592c82d65c14d2d81e6add5147a77c39c (diff)
downloaduhd-065740babdea2cac56473db040cd67b84f3fa598.tar.gz
uhd-065740babdea2cac56473db040cd67b84f3fa598.tar.bz2
uhd-065740babdea2cac56473db040cd67b84f3fa598.zip
mpm: n3xx: clocking API changes for transitioning clock and time sources
Added set_sync_source method to set both the time and clock sources without forcing a re-init twice. Modified the existing set_time_source and set_clock_source methods to call into set_sync_source.
Diffstat (limited to 'mpm/python/usrp_mpm/dboard_manager/magnesium.py')
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/magnesium.py84
1 files changed, 81 insertions, 3 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
index 35d3bb22f..c67acdc55 100644
--- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py
+++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py
@@ -15,6 +15,8 @@ from usrp_mpm import lib # Pulls in everything from C++-land
from usrp_mpm.dboard_manager import DboardManagerBase
from usrp_mpm.dboard_manager.mg_periphs import TCA6408, MgCPLD
from usrp_mpm.dboard_manager.mg_init import MagnesiumInitManager
+from usrp_mpm.dboard_manager.mg_periphs import DboardClockControl
+from usrp_mpm.cores import nijesdcore
from usrp_mpm.mpmlog import get_logger
from usrp_mpm.sys_utils.uio import open_uio
from usrp_mpm.sys_utils.udev import get_eeprom_paths
@@ -134,7 +136,8 @@ class Magnesium(DboardManagerBase):
self.eeprom_fs = None
self.eeprom_path = None
self.cpld = None
- self._init_args = {}
+ # If _init_args is None, it means that init() hasn't yet been called.
+ self._init_args = None
# Now initialize all peripherals. If that doesn't work, put this class
# into a non-functional state (but don't crash, or we can't talk to it
# any more):
@@ -291,6 +294,10 @@ class Magnesium(DboardManagerBase):
if new_ref_clock_freq != self.ref_clock_freq:
self.ref_clock_freq = float(args['ref_clk_freq'])
ref_clk_freq_changed = True
+ self.log.debug(
+ "Updating reference clock frequency to {:.02f} MHz!"
+ .format(self.ref_clock_freq / 1e6)
+ )
assert self.ref_clock_freq is not None
# Check if master clock freq changed (would require a full init)
master_clock_rate = \
@@ -390,19 +397,90 @@ class Magnesium(DboardManagerBase):
# This does not stop anyone from killing this process (and the thread)
# while the EEPROM write is happening, though.
+ ##########################################################################
+ # Clocking control APIs
+ ##########################################################################
+ def set_clk_safe_state(self):
+ """
+ Disable all components that could react badly to a sudden change in
+ clocking. After calling this method, all clocks will be off. Calling
+ _reinit() will turn them on again.
+
+ The only downstream receiver of the clock that is not reset here are the
+ lowband LOs, which are controlled through the host UHD interface.
+ """
+ if self._init_args is None:
+ # Then we're already in a safe state
+ return
+ # Reset Mykonos, since it receives a copy of the clock from the LMK.
+ self.cpld.reset_mykonos(keep_in_reset=True)
+ with open_uio(
+ label="dboard-regs-{}".format(self.slot_idx),
+ read_only=False
+ ) as dboard_ctrl_regs:
+ # Clear the Sample Clock enables and place the MMCM in reset.
+ db_clk_control = DboardClockControl(dboard_ctrl_regs, self.log)
+ db_clk_control.reset_mmcm()
+ # Place the JESD204b core in reset, mainly to reset QPLL/CPLLs.
+ jesdcore = nijesdcore.NIMgJESDCore(dboard_ctrl_regs, self.slot_idx)
+ jesdcore.reset()
+ # The reference clock is handled elsewhere since it is a motherboard-
+ # level clock.
+
+
+ def _reinit(self, master_clock_rate):
+ """
+ This will re-run init(). We store all the settings in _init_args, so we
+ will bring the device into the same state that it was before, with the
+ exception of frequency and gain. Those need to be re-set by UHD in order
+ not to invalidate the UHD caches.
+ """
+ args = self._init_args
+ args["master_clock_rate"] = master_clock_rate
+ args["ref_clk_freq"] = self.ref_clock_freq
+ # If we add API calls to reset the cals, they need to update
+ # self._init_args
+ self.master_clock_rate = None # <= This will force a re-init
+ self.init(args)
+ # self.master_clock_rate is now OK again
+
+
+ def set_master_clock_rate(self, rate):
+ """
+ Set the master clock rate to rate. Note this will trigger a
+ re-initialization of the entire clocking, unless rate matches the
+ current master clock rate.
+ """
+ if rate == self.master_clock_rate:
+ self.log.debug(
+ "New master clock rate assignment matches previous assignment. "
+ "Ignoring set_master_clock_rate() command.")
+ return self.master_clock_rate
+ self._reinit(rate)
+ return rate
+
def get_master_clock_rate(self):
" Return master clock rate (== sampling rate) "
return self.master_clock_rate
def update_ref_clock_freq(self, freq):
"""
- Call this function if the frequency of the reference clock changes (the
- 10, 20, 25 MHz one). Note: Won't actually re-run any settings.
+ Call this function if the frequency of the reference clock changes
+ (the 10, 20, 25 MHz one).
+
+ If this function is called while the device is in an initialized state,
+ it will also re-trigger the initialization sequence.
+
+ No need to set the device in a safe state because (presumably) the user
+ has already switched the clock rate externally. All we need to do now
+ is re-initialize with the new rate.
"""
assert freq in (10e6, 20e6, 25e6), \
"Invalid ref clock frequency: {}".format(freq)
self.log.trace("Changing ref clock frequency to %f MHz", freq/1e6)
self.ref_clock_freq = freq
+ if self._init_args is not None:
+ self._reinit(self.master_clock_rate)
##########################################################################