diff options
Diffstat (limited to 'mpm/python/usrp_mpm/dboard_manager')
| -rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/lmk_mg.py | 116 | ||||
| -rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/magnesium.py | 66 | 
2 files changed, 161 insertions, 21 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py new file mode 100644 index 000000000..94d50527d --- /dev/null +++ b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py @@ -0,0 +1,116 @@ +# +# Copyright 2017 Ettus Research (National Instruments) +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# +""" +LMK04828 driver for use with Magnesium +""" + +from ..mpmlog import get_logger +from time import sleep + +class LMK04828Mg(object): +    def __init__(self, regs_iface, spi_lock): +        self.regs_iface = regs_iface +        self.spi_lock = spi_lock +        self.log = get_logger("LMK04828") +        assert hasattr(self.regs_iface, 'peek8') +        assert hasattr(self.regs_iface, 'poke8') +        assert hasattr(self.spi_lock, 'lock') +        assert hasattr(self.spi_lock, 'unlock') + +    def init(self): +        # Reset the LMK +        self.log.trace("lock?") +        self.spi_lock.lock() +        self.log.trace("locked") + +        addrs = (0x000, 0x000, 0x002, 0x14A) +        vals  =  (0x90,  0x10,  0x00,  0x33) + +        for addr, val in zip(addrs, vals): +            #self.log.trace("send {0}, {1}".format(hex(addr), hex(val),)) +            self.regs_iface.poke8(addr, val) + +        # Re-verify chip ID +        self.log.trace("check chip id") +        if not self.verify_chip_id(): +            raise Exception("Unable to locate LMK04828") + +        # Write the configuration (10 MHz reference, 125 MHz outputs) +        addrs = (0x100, 0x101, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10B, 0x10C, 0x10D, 0x10E, 0x10F, 0x110, 0x111, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118, 0x119, 0x11B, 0x11C, 0x11D, 0x11E, 0x11F, 0x120, 0x121, 0x123, 0x124, 0x125, 0x126, 0x127, 0x128, 0x129, 0x12B, 0x12C, 0x12D, 0x12E, 0x12F, 0x130, 0x131, 0x133, 0x134, 0x135, 0x136, 0x137, 0x138, 0x139, 0x13A, 0x13B, 0x13C, 0x13D, 0x13E, 0x13F, 0x140, 0x141, 0x142, 0x143, 0x144, 0x145, 0x146, 0x147, 0x148, 0x149, 0x14B, 0x14C, 0x14D, 0x14E, 0x14F, 0x150, 0x151, 0x152, 0x153, 0x154, 0x155, 0x156, 0x157, 0x158, 0x159, 0x15A, 0x15B, 0x15C, 0x15D, 0x15E, 0x15F, 0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x171, 0x172, 0x17C, 0x17D, 0x166, 0x167, 0x168, 0x169, 0x16A, 0x16B, 0x16C, 0x16D, 0x16E, 0x173) +        vals =   (0x78,  0x55,  0x00,  0x20,  0x00,  0xF2,  0x55,  0x7E,  0x55,  0x00,  0x00,  0x00,  0xF0,  0x55,  0x61,  0x55,  0x00,  0x00,  0x00,  0xF9,  0x00,  0x78,  0x55,  0x00,  0x20,  0x00,  0xF1,  0x00,  0x78,  0x55,  0x00,  0x20,  0x00,  0xF2,  0x55,  0x78,  0x55,  0x00,  0x00,  0x00,  0xF0,  0x50,  0x78,  0x55,  0x00,  0x20,  0x00,  0xF1,  0x05,  0x30,  0x00,  0x01,  0xE0,  0x00,  0x08,  0x00,  0x09,  0x00,  0x00,  0x00,  0xD1,  0x00,  0x7F,  0x10,  0x1A,  0x01,  0x01,  0x01,  0xF6,  0x00,  0x00,  0x7F,  0x03,  0x02,  0x00,  0x00,  0x01,  0x00,  0x0A,  0x00,  0x01,  0x00,  0x7D,  0xCF,  0x03,  0xE8,  0x00,  0x0B,  0x00,  0x04,  0xA4,  0x00,  0x00,  0x19,  0xAA,  0x02,  0x15,  0x33,  0x00,  0x00,  0x19,  0x51,  0x27,  0x10,  0x00,  0x00,  0x13,  0x00) + +        self.log.trace("send init sequence") +        for addr, val in zip(addrs, vals): +            self.regs_iface.poke8(addr, val)  + +        self.spi_lock.unlock() +        sleep(0.1) +        self.spi_lock.lock() + +        # Clear Lock Detect Sticky +        self.log.trace("clear lock sticky") +        addrs = (0x182, 0x182, 0x183, 0x183) +        vals  =  (0x01,  0x00,  0x01,  0x00) +         +        for addr, val in zip(addrs, vals): +            self.regs_iface.poke8(addr, val)  + +        self.spi_lock.unlock() +        sleep(0.1) +        self.spi_lock.lock() + +        # Check Lock Detects +        self.log.trace("check lock status") +        pll1_lock_status = self.regs_iface.peek8(0x182) +        pll2_lock_status = self.regs_iface.peek8(0x183) + +        if not pll1_lock_status == 0x02: +            self.log.error("LMK PLL1 did not lock. Status {0}".format(hex(pll1_lock_status))) + +        if not pll2_lock_status == 0x02: +            self.log.error("LMK PLL2 did not lock. Status {0}".format(hex(pll2_lock_status))) + +        # Toggle SYNC polarity to trigger SYNC event +        self.regs_iface.poke8(0x143, 0xF1) +        self.regs_iface.poke8(0x143, 0xD1) +        # Enable SYSREF pulses +        self.regs_iface.poke8(0x139, 0x02) +        self.regs_iface.poke8(0x144, 0xFF) +        self.regs_iface.poke8(0x143, 0x52) +        self.spi_lock.unlock() + +        self.log.trace("LMK init'd and locked") + +    def get_chip_id(self): +        """ +        Read back the chip ID +        """ +        # TODO: avoid deadlock by not locking when we already have lock (or use a recursive mutex internally) +        #self.spi_lock.lock() +        chip_id = self.regs_iface.peek8(0x03) +        #self.spi_lock.unlock() +        return chip_id + +    def verify_chip_id(self): +        """ +        Returns True if the chip ID matches what we expect, False otherwise. +        """ +        chip_id = self.get_chip_id() +        if chip_id != 6: +            self.log.error("wrong chip id {0}".format(chip_id)) +            return False +        return True diff --git a/mpm/python/usrp_mpm/dboard_manager/magnesium.py b/mpm/python/usrp_mpm/dboard_manager/magnesium.py index fa2dbe9c3..de871abf8 100644 --- a/mpm/python/usrp_mpm/dboard_manager/magnesium.py +++ b/mpm/python/usrp_mpm/dboard_manager/magnesium.py @@ -26,6 +26,25 @@ from .base import DboardManagerBase  from .. import nijesdcore  from ..uio import UIO  from ..mpmlog import get_logger +from .lmk_mg import LMK04828Mg + +def create_spidev_iface(dev_node): +    """ +    Create a regs iface from a spidev node +    """ +    SPI_SPEED_HZ = 1000000 +    SPI_ADDR_SHIFT = 8 +    SPI_DATA_SHIFT = 0 +    SPI_READ_FLAG = 1<<23 +    SPI_WRIT_FLAG = 0 +    return lib.spi.make_spidev_regs_iface( +        dev_node, +        SPI_SPEED_HZ, +        SPI_ADDR_SHIFT, +        SPI_DATA_SHIFT, +        SPI_READ_FLAG, +        SPI_WRIT_FLAG +    )  class Magnesium(DboardManagerBase):      """ @@ -54,25 +73,16 @@ class Magnesium(DboardManagerBase):          """          Execute necessary init dance to bring up dboard          """ +        self.clock_regs = create_spidev_iface(self._spi_nodes['lmk'])          self.log.debug("Loading C++ drivers...")          self._device = lib.dboards.magnesium_manager(              self._spi_nodes['mykonos'],          ) -        SPI_SPEED_HZ = 1000000 -        SPI_ADDR_SHIFT = 8 -        SPI_DATA_SHIFT = 0 -        SPI_READ_FLAG = 1<<23 -        SPI_WRIT_FLAG = 0 -        self.lmk = lib.spi.make_spidev_regs_iface( -            dev_node, -            SPI_SPEED_HZ, -            SPI_ADDR_SHIFT, -            SPI_DATA_SHIFT, -            SPI_READ_FLAG, -            SPI_WRIT_FLAG -        ) +        self.spi_lock = self._device.get_spi_lock()          self.mykonos = self._device.get_radio_ctrl()          self.log.debug("Loaded C++ drivers.") +        self.lmk = LMK04828Mg(self.clock_regs, self.spi_lock) +          self.log.debug("Getting Mg A uio...")          self.radio_regs = UIO(label="jesd204b-regs", read_only=False)          self.log.info("Radio-register UIO object successfully generated!") @@ -89,9 +99,9 @@ class Magnesium(DboardManagerBase):          self.jesdcore.check_core()          self.log.trace("Initializing LMK...")          self.lmk.init() +        self.radio_regs.poke32(0x2078, 0xA000040) +        self.log.trace("Verify LMK Chip ID...")          self.lmk.verify_chip_id() -        self.log.trace("Enabling SYSREF pulses...") -        self.lmk.enable_sysref_pulse()          self.jesdcore.unreset_mmcm() @@ -105,23 +115,36 @@ class Magnesium(DboardManagerBase):          self.jesdcore.send_sysref_pulse()          self.mykonos.finish_initialization() -        self.log.trace("Stargin Mykonos JESD framing...") +        self.log.trace("Starting Mykonos framer...")          self.mykonos.start_jesd_rx() +        self.jesdcore.send_sysref_pulse() +        self.log.trace("Resetting FPGA deframer...")          self.jesdcore.init_deframer() +        self.log.trace("Resetting FPGA framer...")          self.jesdcore.init_framer() +        self.log.trace("Starting Mykonos deframer...")          self.mykonos.start_jesd_tx() -        #TODO add function for Enable FPGA LMFC Generator +        self.log.trace("Enable LMFC and send") +        self.jesdcore.enable_lmfc()          self.jesdcore.send_sysref_pulse()          time.sleep(0.2)          if not self.jesdcore.get_framer_status():              raise Exception('JESD Core Framer is not synced!')          if not self.jesdcore.get_deframer_status():              raise Exception('JESD Core Deframer is not synced!') -        #if (!self.mykonos.get_framer_status()) -        #    raise Exception('Mykonos Framer is not synced!') -        #if (!self.mykonos.get_deframer_status()) -        #    raise Exception('Mykonos Deframer is not synced!') +        if (self.mykonos.get_framer_status() & 0xFF != 0x3E): +            raise Exception('Mykonos Framer is not synced!') +        if (self.mykonos.get_deframer_status() & 0x7F != 0x28): +            raise Exception('Mykonos Deframer is not synced!') +        self.log.trace("JESD fully synced and ready") + +    def dump_jesd_core(self): +        for i in range(0x2000, 0x2110, 0x10): +            print("0x%04X " % i), +            for j in range(0, 0x10, 0x4): +                print("%08X" % self.radio_regs.peek32(i + j)), +            print("")      def read_eeprom_v1(self, data):          """ @@ -130,3 +153,4 @@ class Magnesium(DboardManagerBase):          # magnesium eeprom contains          # nothing          return struct.unpack_from("x", data) +  | 
