diff options
Diffstat (limited to 'mpm/python/usrp_mpm/dboard_manager/lmk_mg.py')
-rw-r--r-- | mpm/python/usrp_mpm/dboard_manager/lmk_mg.py | 212 |
1 files changed, 153 insertions, 59 deletions
diff --git a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py index 6c2660521..b295874a1 100644 --- a/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py +++ b/mpm/python/usrp_mpm/dboard_manager/lmk_mg.py @@ -18,7 +18,7 @@ LMK04828 driver for use with Magnesium """ -from time import sleep +import time from builtins import zip from builtins import hex from ..mpmlog import get_logger @@ -33,66 +33,160 @@ class LMK04828Mg(LMK04828): 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") + """ + Basic init. Turns it on. Let's read SPI. + """ + self.log.info("Reset LMK & Verify") + self.pokes8(( + (0x000, 0x90), # Assert reset + (0x000, 0x10), # De-assert reset + (0x002, 0x00), # De-assert power down + (0x148, 0x33), # Clock Select as SDO + )) 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 config(self): + """ + 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 + self.pokes8(( + (0x100, 0x78), # CLKout Config + (0x101, 0x55), # CLKout Config + (0x102, 0x55), # 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) + (0x107, 0x15), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL + (0x108, 0x7E), # CLKout Config + (0x109, 0x55), # CLKout Config + (0x10A, 0x55), # CLKout Config + (0x10B, 0x00), # CLKout Config + (0x10C, 0x00), # CLKout Config + (0x10D, 0x00), # CLKout Config + (0x10E, 0xF0), # CLKout Config + (0x10F, 0x55), # CLKout Config + (0x110, 0x61), # CLKout Config + (0x111, 0x55), # CLKout Config + (0x112, 0x55), # 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 + (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 + (0x123, 0x00), # CLKout Config + (0x124, 0x20), # CLKout Config + (0x125, 0x00), # CLKout Config + (0x126, 0xF2), # CLKout Config FPGA: (0xAB where A = SYSREF, B = CLK) + (0x127, 0x55), # CLKout Config 0x15 = LVDS, 0x55 = LVPECL + (0x128, 0x78), # CLKout Config + (0x129, 0x55), # CLKout Config + (0x12A, 0x55), # CLKout Config + (0x12B, 0x00), # CLKout Config + (0x12C, 0x00), # CLKout Config + (0x12D, 0x00), # CLKout Config + (0x12E, 0xF0), # CLKout Config + (0x12F, 0x50), # CLKout Config + (0x130, 0x78), # CLKout Config + (0x131, 0x55), # CLKout Config + (0x132, 0x55), # CLKout Config + (0x133, 0x00), # CLKout Config + (0x134, 0x20), # CLKout Config + (0x135, 0x00), # CLKout Config + (0x136, 0xF1), # CLKout Config + (0x137, 0x05), # CLKout Config + (0x138, 0x30), # VCO_MUX to VCO 1; OSCout off + (0x139, 0x00), # SYSREF Source = MUX; SYSREF MUX = Normal SYNC + (0x13A, 0x01), # SYSREF Divide [12:8] + (0x13B, 0xE0), # SYSREF Divide [7:0] + (0x13C, 0x00), # SYSREF DDLY [12:8] + (0x13D, 0x08), # SYSREF DDLY [7:0] ... 8 is default, <8 is reserved + (0x13E, 0x00), # SYSREF Pulse Count = 1 pulse/request + (0x13F, 0x09), # Feedback Mux: Enabled, DCLKout6, drives PLL1N divider + (0x140, 0x00), # POWERDOWN options + (0x141, 0x00), # Dynamic digital delay enable + (0x142, 0x00), # Dynamic digital delay step + (0x143, 0xD1), # SYNC edge sensitive; SYSREF_CLR; SYNC Enabled; SYNC from pin no pulser + (0x144, 0x00), # Enable SYNC on all outputs including sysref + (0x145, 0x7F), # Always program to d127 + (0x146, 0x10), # CLKin Type & En + (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 + (0x14B, 0x01), # Holdover & DAC Manual Mode + (0x14C, 0xF6), # DAC Manual Mode + (0x14D, 0x00), # DAC Settings (defaults) + (0x14E, 0x00), # DAC Settings (defaults) + (0x14F, 0x7F), # DAC Settings (defaults) + (0x150, 0x03), # Holdover Settings (defaults) + (0x151, 0x02), # Holdover Settings (defaults) + (0x152, 0x00), # Holdover Settings (defaults) + (0x153, 0x00), # CLKin0_R divider [13:8], default = 0 + (0x154, clkin0_r_divider), # CLKin0_R divider [7:0], default = d120 + (0x155, 0x00), # CLKin1_R divider [13:8], default = 0 + (0x156, clkin0_r_divider), # CLKin1_R divider [7:0], default = d120 + (0x157, 0x00), # CLKin2_R divider [13:8], default = 0 + (0x158, 0x01), # CLKin2_R divider [7:0], default = d120 + (0x159, 0x00), # PLL1 N divider [13:8], default = 0 + (0x15A, 0x7D), # PLL1 N divider [7:0], default = d120 + (0x15B, 0xCF), # PLL1 PFD + (0x15C, 0x27), # PLL1 DLD Count [13:8] + (0x15D, 0x10), # PLL1 DLD Count [7:0] + (0x15E, 0x00), # PLL1 R/N delay, defaults = 0 + (0x15F, 0x0B), # Status LD1 pin = PLL1 LD, push-pull output + (0x160, 0x00), # PLL2 R divider [11:8]; + (0x161, 0x04), # PLL2 R divider [7:0] + (0x162, 0xA4), # PLL2 prescaler; OSCin freq + (0x163, 0x00), # PLL2 Cal = PLL2 normal val + (0x164, 0x00), # PLL2 Cal = PLL2 normal val + (0x165, 0x19), # PLL2 Cal = PLL2 normal val + (0x171, 0xAA), # Write this val after x165 + (0x172, 0x02), # Write this val after x165 + (0x17C, 0x15), # VCo1 Cal; write before x168 + (0x17D, 0x33), # VCo1 Cal; write before x168 + (0x166, 0x00), # PLL2 N[17:16] + (0x167, 0x00), # PLL2 N[15:8] + (0x168, 0x19), # PLL2 N[7:0] + (0x169, 0x51), # PLL2 PFD + (0x16A, 0x27), # PLL2 DLD Count [13:8] = default d32 + (0x16B, 0x10), # PLL2 DLD Count [7:0] = default d0 + (0x16C, 0x00), # PLL2 Loop filter r = 200 ohm + (0x16D, 0x00), # PLL2 loop filter c = 10 pF + (0x16E, 0x13), # Status LD2 pin = Output push-pull, PLL2 DLD + (0x173, 0x00), # Do not power down PLL2 or prescaler + )) + time.sleep(1.0) # Increased time to wait for DAC and VCXO to settle. + self.pokes8(( + (0x182, 0x1), # Clear Lock Detect Sticky + (0x182, 0x0), # Clear Lock Detect Sticky + (0x183, 0x1), # Clear Lock Detect Sticky + (0x183, 0x0), # Clear Lock Detect Sticky + )) + time.sleep(0.1) + if not self.check_plls_locked(): + raise RuntimeError("At least one LMK PLL did not lock! Check the logs for details.") + self.log.trace("Setting SYNC and SYSREF config...") + self.pokes8(( + (0x143, 0xF1), # toggle SYNC polarity to trigger SYNC event + (0x143, 0xD1), # toggle SYNC polarity to trigger SYNC event + (0x139, 0x02), # SYSREF Source = MUX; SYSREF MUX = pulser + (0x144, 0xFF), # Disable SYNC on all outputs including sysref + (0x143, 0x52), # Pulser selected; SYNC enabled; 1 shot enabled + )) + self.log.info("LMK init'd and locked!") |