diff options
author | djepson1 <daniel.jepson@ni.com> | 2017-10-09 10:35:25 -0500 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2017-12-22 15:04:02 -0800 |
commit | ee3f82e4544c06cb25f90ecd3871d1a2ac4638c7 (patch) | |
tree | d92a80b6505f279dd40e79dea89376e0062afa5c /mpm | |
parent | 5c489c2597948b131aaddb516fe6af40e438b251 (diff) | |
download | uhd-ee3f82e4544c06cb25f90ecd3871d1a2ac4638c7.tar.gz uhd-ee3f82e4544c06cb25f90ecd3871d1a2ac4638c7.tar.bz2 uhd-ee3f82e4544c06cb25f90ecd3871d1a2ac4638c7.zip |
mg: Updated support for LMK
- add clock shifting
- add DAC support
- modify __init__ calls for cleanup
Signed-off-by: djepson1 <daniel.jepson@ni.com>
Diffstat (limited to 'mpm')
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/lmk_mg.py | 82 | ||||
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/magnesium.py | 66 |
2 files changed, 116 insertions, 32 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py index b295874a1..ca088b80b 100644 --- a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py +++ b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py @@ -25,12 +25,16 @@ from ..mpmlog import get_logger from ..chips import LMK04828 class LMK04828Mg(LMK04828): - def __init__(self, regs_iface, spi_lock, slot=None): + def __init__(self, regs_iface, spi_lock, ref_clock_freq, slot=None): LMK04828.__init__(self, regs_iface, slot) + self.log.trace("Using reference clock frequency {} MHz".format(ref_clock_freq/1e6)) self.spi_lock = spi_lock self.log = get_logger("LMK04828") assert hasattr(self.spi_lock, 'lock') assert hasattr(self.spi_lock, 'unlock') + self.ref_clock_freq = ref_clock_freq + self.init() + self.config() def init(self): """ @@ -52,59 +56,59 @@ class LMK04828Mg(LMK04828): Write lots of config foo. """ self.log.trace("LMK Initialization") - clkin0_r_divider = {10e6: 0x0A, 20e6: 0x14}[10e6] # FIXME: hard coded to use 10 MHz + clkin0_r_divider = {10e6: 0x0A, 20e6: 0x14}[self.ref_clock_freq] self.pokes8(( (0x100, 0x78), # CLKout Config - (0x101, 0x55), # CLKout Config - (0x102, 0x55), # CLKout Config + (0x101, 0xCC), # CLKout Config + (0x102, 0xCC), # CLKout Config (0x103, 0x00), # CLKout Config (0x104, 0x20), # CLKout Config (0x105, 0x00), # CLKout Config - (0x106, 0xF2), # CLKout Config MYK: (0xAB where A = SYSREF, B = CLK) + (0x106, 0x72), # CLKout Config MYK: (0xAB where A = SYSREF, B = CLK) (0x107, 0x15), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL (0x108, 0x7E), # CLKout Config - (0x109, 0x55), # CLKout Config - (0x10A, 0x55), # CLKout Config + (0x109, 0xFF), # CLKout Config + (0x10A, 0xFF), # CLKout Config (0x10B, 0x00), # CLKout Config (0x10C, 0x00), # CLKout Config (0x10D, 0x00), # CLKout Config - (0x10E, 0xF0), # CLKout Config + (0x10E, 0x70), # CLKout Config (0x10F, 0x55), # CLKout Config - (0x110, 0x61), # CLKout Config - (0x111, 0x55), # CLKout Config - (0x112, 0x55), # CLKout Config + (0x110, 0x78), # CLKout Config + (0x111, 0xCC), # CLKout Config + (0x112, 0xCC), # CLKout Config (0x113, 0x00), # CLKout Config (0x114, 0x00), # CLKout Config (0x115, 0x00), # CLKout Config (0x116, 0xF9), # CLKout Config (0x117, 0x00), # CLKout Config (0x118, 0x78), # CLKout Config - (0x119, 0x55), # CLKout Config - (0x11A, 0x55), # CLKout Config + (0x119, 0xCC), # CLKout Config + (0x11A, 0xCC), # CLKout Config (0x11B, 0x00), # CLKout Config (0x11C, 0x20), # CLKout Config (0x11D, 0x00), # CLKout Config (0x11E, 0xF1), # CLKout Config (0x11F, 0x00), # CLKout Config (0x120, 0x78), # CLKout Config - (0x121, 0x55), # CLKout Config - (0x122, 0x55), # CLKout Config + (0x121, 0xCC), # CLKout Config + (0x122, 0xCC), # CLKout Config (0x123, 0x00), # CLKout Config - (0x124, 0x20), # CLKout Config + (0x124, 0x20), # CLKout Config 0x20 = SYSREF output, 0x00 = DEVCLK (0x125, 0x00), # CLKout Config - (0x126, 0xF2), # CLKout Config FPGA: (0xAB where A = SYSREF, B = CLK) - (0x127, 0x55), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL + (0x126, 0x72), # CLKout Config FPGA: (0xAB where A = SYSREF, B = CLK) + (0x127, 0x55), # CLKout Config 0x1 = LVDS, 0x5 = LVPECL (0x128, 0x78), # CLKout Config - (0x129, 0x55), # CLKout Config - (0x12A, 0x55), # CLKout Config + (0x129, 0xCC), # CLKout Config + (0x12A, 0xCC), # CLKout Config (0x12B, 0x00), # CLKout Config (0x12C, 0x00), # CLKout Config (0x12D, 0x00), # CLKout Config - (0x12E, 0xF0), # CLKout Config - (0x12F, 0x50), # CLKout Config + (0x12E, 0x72), # CLKout Config + (0x12F, 0xD0), # CLKout Config (0x130, 0x78), # CLKout Config - (0x131, 0x55), # CLKout Config - (0x132, 0x55), # CLKout Config + (0x131, 0xCC), # CLKout Config + (0x132, 0xCC), # CLKout Config (0x133, 0x00), # CLKout Config (0x134, 0x20), # CLKout Config (0x135, 0x00), # CLKout Config @@ -128,6 +132,7 @@ class LMK04828Mg(LMK04828): (0x147, 0x1A), # CLKin_SEL = CLKin1 manual; CLKin1 to PLL1 # (0x148, 0x01), # CLKin_SEL0 = input with pullup: previously written above! (0x149, 0x01), # CLKin_SEL1 = input with pulldown + (0x14A, 0x02), # RESET type (0x14B, 0x01), # Holdover & DAC Manual Mode (0x14C, 0xF6), # DAC Manual Mode (0x14D, 0x00), # DAC Settings (defaults) @@ -190,3 +195,32 @@ class LMK04828Mg(LMK04828): )) self.log.info("LMK init'd and locked!") + def lmk_shift(self, num_shifts=0): + """ + Apply time shift + """ + # TODO: these numbers need to be based off the radio clock freq. + self.log.trace("LMK04828 Clock Phase Shifting Commencing...") + ddly_value = 0xCD if num_shifts >= 0 else 0xCB + ddly_value_sysref_reg0 = 0x01 + ddly_value_sysref_reg1 = 0xE1 if num_shifts >= 0 else 0xDF # 0xE0 is normal + self.pokes8(( + (0x141, 0xB1), # Dynamic digital delay enable on outputs 0, 8, 10 + (0x143, 0x53), # SYSREF_CLR; SYNC Enabled; SYNC from pulser @ regwrite + (0x139, 0x02), # SYSREF_MUX = Pulser + (0x101, ddly_value), # Set DDLY values for DCLKout0 +/-1 on low cnt. + (0x102, ddly_value), # Hidden register. Write the same as previous based on inc/dec. + (0x121, ddly_value), # Set DDLY values for DCLKout8 +/-1 on low cnt + (0x122, ddly_value), # Hidden register. Write the same as previous based on inc/dec. + (0x129, ddly_value), # Set DDLY values for DCLKout10 +/-1 on low cnt + (0x12A, ddly_value), # Hidden register. Write the same as previous based on inc/dec. + (0x13C, ddly_value_sysref_reg0), # SYSREF DDLY value + (0x13D, ddly_value_sysref_reg1), # SYSREF DDLY value + (0x144, 0x4E), # Enable SYNC on outputs 0, 8, 10 + )) + for x in range(abs(num_shifts)): + self.poke8(0x142, 0x1) + # Put everything back the way it was before shifting. + self.poke8(0x144, 0xFF) # Disable SYNC on all outputs including SYSREF + # self.poke8(0x143, 0xD2) # Reset SYSREF engine to proper SYNC settings + self.poke8(0x143, 0x52) # Pulser selected; SYNC enabled; 1 shot enabled diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py index 55a53b984..df573219d 100644 --- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py +++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py @@ -28,6 +28,7 @@ from .. import nijesdcore from ..uio import UIO from ..mpmlog import get_logger from .lmk_mg import LMK04828Mg +from usrp_mpm.cores import ClockSynchronizer def create_spidev_iface(dev_node): """ @@ -69,6 +70,20 @@ def create_spidev_iface_cpld(dev_node): SPI_WRIT_FLAG ) +def create_spidev_iface_phasedac(dev_node): + """ + Create a regs iface from a spidev node (ADS5681) + """ + return lib.spi.make_spidev_regs_iface( + str(dev_node), + 1000000, # Speed (Hz) + 1, # SPI mode + 16, # Addr shift + 0, # Data shift + 0, # Read flag + 0, # Write flag + ) + class Magnesium(DboardManagerBase): """ Holds all dboard specific information and methods of the magnesium dboard @@ -81,7 +96,18 @@ class Magnesium(DboardManagerBase): pids = [0x150] # Maps the chipselects to the corresponding devices: - spi_chipselect = {"cpld": 0, "lmk": 1, "mykonos": 2} + spi_chipselect = {"cpld": 0, "lmk": 1, "mykonos": 2, "phase_dac": 3} + spi_factories = { + "cpld": create_spidev_iface_cpld, + "lmk": create_spidev_iface, + "mykonos": create_spidev_iface, + "phase_dac": create_spidev_iface_phasedac, + } + + # DAC is initialized to midscale automatically on power-on: 16-bit DAC, so midpoint + # is at 2^15 = 32768. However, the linearity of the DAC is best just below that + # point, so we set it to the (carefully calculated) alternate value instead. + INIT_PHASE_DAC_WORD = 31000 # Intentionally decimal def _get_mykonos_function(self, name): mykfunc = getattr(self.mykonos, name) @@ -95,6 +121,7 @@ class Magnesium(DboardManagerBase): self.log = get_logger("Magnesium-{}".format(slot_idx)) self.log.trace("Initializing Magnesium daughterboard, slot index {}".format(self.slot_idx)) + self.ref_clock_freq = 10e6 # TODO: make this not fixed self.log.debug("Loading C++ drivers for CPLD SPI.") self.cpld_regs = create_spidev_iface_cpld(self._spi_nodes['cpld']) @@ -102,10 +129,6 @@ class Magnesium(DboardManagerBase): self._device = lib.dboards.magnesium_manager( self._spi_nodes['mykonos'], ) - self.spi_lock = self._device.get_spi_lock() - self.log.debug("Loading C++ drivers for LMK SPI.") - self.clock_regs = create_spidev_iface(self._spi_nodes['lmk']) - self.lmk = LMK04828Mg(self.clock_regs, self.spi_lock) self.mykonos = self._device.get_radio_ctrl() self.log.debug("Loaded C++ drivers.") @@ -122,11 +145,31 @@ class Magnesium(DboardManagerBase): Execute necessary init dance to bring up dboard """ + def _init_spi_devices(): + " Returns abstraction layers to all the SPI devices " + self.log.trace("Loading SPI interfaces...") + return { + key: self.spi_factories[key](self._spi_nodes[key]) + for key in self._spi_nodes + } def _init_clock_control(dboard_regs): " Create a dboard clock control object and reset it " dboard_clk_control = DboardClockControl(dboard_regs, self.log) dboard_clk_control.reset_mmcm() return dboard_clk_control + def _init_lmk(slot_idx, lmk_spi, ref_clk_freq, + pdac_spi, init_phase_dac_word): + """ + Sets the phase DAC to initial value, and then brings up the LMK + according to the selected ref clock frequency. + Will throw if something fails. + """ + self.log.trace("Initializing Phase DAC to d{}.".format( + init_phase_dac_word + )) + 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) self.log.info("init() called with args `{}'".format( @@ -134,12 +177,19 @@ 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() - self.lmk.config() + self.lmk = _init_lmk( + self.slot_idx, + self._spi_ifaces['lmk'], + self.ref_clock_freq, + self._spi_ifaces['phase_dac'], + self.INIT_PHASE_DAC_WORD, + ) self.dboard_clk_control.enable_mmcm() - self.log.info("Clocking Configured Successfully!") + self.log.info("Sample Clocks and Phase DAC Configured Successfully!") self.init_jesd(self.radio_regs) |