1# 2# Copyright 2017 Ettus Research, a National Instruments Company 3# 4# SPDX-License-Identifier: GPL-3.0-or-later 5# 6""" 7LMK04828 driver for use with Magnesium 8""" 9 10import time 11from usrp_mpm.chips import LMK04828 12 13class LMK04828EISCAT(LMK04828): 14 """ 15 LMK04828 controls for EISCAT daughterboard 16 """ 17 def __init__(self, regs_iface, ref_clock_freq, slot=None, log=None): 18 LMK04828.__init__(self, regs_iface, log) 19 self.log.trace("Using reference clock frequency {} MHz".format(ref_clock_freq/1e6)) 20 if ref_clock_freq != 10e6: 21 error_msg = "Invalid reference clock frequency: {} MHz. " \ 22 "Must be 10 MHz.".format(ref_clock_freq) 23 self.log.error(error_msg) 24 raise RuntimeError(error_msg) 25 self.ref_clock_freq = ref_clock_freq 26 self.init() 27 self.config() 28 29 30 def get_vco_freq(self): 31 """ 32 Return the hard coded VCO frequency in the LMK PLL2. 33 """ 34 return 2.496e9 35 36 def init(self): 37 """ 38 Basic init. Turns it on. Let's us read SPI. 39 """ 40 self.log.debug("Reset LMK & Verify") 41 self.pokes8(( 42 (0x000, 0x90), # Assert reset 43 (0x000, 0x10), # De-assert reset 44 (0x002, 0x00), # De-assert power down 45 (0x16E, 0x3B), # PLL2 Lock Detect Config as SDO 46 )) 47 if not self.verify_chip_id(): 48 raise Exception("Unable to locate LMK04828") 49 50 51 def config(self): 52 """ 53 Write lots of config foo. 54 """ 55 self.log.trace("LMK Initialization") 56 clkin0_r_divider = {10e6: 0x0A, 20e6: 0x14}[self.ref_clock_freq] 57 self.pokes8(( 58 (0x100, 0x6C), # CLKout Config 59 (0x101, 0x66), # CLKout Config 60 (0x102, 0x66), # CLKout Config 61 (0x103, 0x00), # CLKout Config 62 (0x104, 0x20), # CLKout Config 63 (0x105, 0x00), # CLKout Config 64 (0x106, 0xF3), # CLKout Config 65 (0x107, 0x05), # CLKout Config 66 (0x108, 0x6C), # CLKout Config 67 (0x109, 0x67), # CLKout Config 68 (0x10A, 0x67), # CLKout Config 69 (0x10B, 0x00), # CLKout Config 70 (0x10C, 0x20), # CLKout Config 71 (0x10D, 0x00), # CLKout Config 72 (0x10E, 0x71), # CLKout Config 73 (0x10F, 0x05), # CLKout Config 74 (0x110, 0x6C), # CLKout Config 75 (0x111, 0x67), # CLKout Config 76 (0x112, 0x67), # CLKout Config 77 (0x113, 0x00), # CLKout Config 78 (0x114, 0x20), # CLKout Config 79 (0x115, 0x00), # CLKout Config 80 (0x116, 0x71), # CLKout Config 81 (0x117, 0x05), # CLKout Config 82 (0x118, 0x6C), # CLKout Config 83 (0x119, 0x67), # CLKout Config 84 (0x11A, 0x67), # CLKout Config 85 (0x11B, 0x00), # CLKout Config 86 (0x11C, 0x20), # CLKout Config 87 (0x11D, 0x00), # CLKout Config 88 (0x11E, 0x71), # CLKout Config 89 (0x11F, 0x05), # CLKout Config 90 (0x120, 0x78), # CLKout Config 91 (0x121, 0x66), # CLKout Config 92 (0x122, 0x66), # CLKout Config 93 (0x123, 0x00), # CLKout Config 94 (0x124, 0x20), # CLKout Config 95 (0x125, 0x00), # CLKout Config 96 (0x126, 0xF3), # CLKout Config 97 (0x127, 0x00), # CLKout Config 98 (0x128, 0x6C), # CLKout Config 99 (0x129, 0x55), # CLKout Config 100 (0x12A, 0x55), # CLKout Config 101 (0x12B, 0x00), # CLKout Config 102 (0x12C, 0x20), # CLKout Config 103 (0x12D, 0x00), # CLKout Config 104 (0x12E, 0xF9), # CLKout Config 105 (0x12F, 0x00), # CLKout Config 106 (0x130, 0x6C), # CLKout Config 107 (0x131, 0x67), # CLKout Config 108 (0x132, 0x67), # CLKout Config 109 (0x133, 0x00), # CLKout Config 110 (0x134, 0x20), # CLKout Config 111 (0x135, 0x00), # CLKout Config 112 (0x136, 0x71), # CLKout Config 113 (0x137, 0x01), # CLKout Config 114 (0x138, 0x10), # VCO_MUX to VCO 1; OSCout off 115 (0x139, 0x00), # SYSREF Source = MUX; SYSREF MUX = Normal SYNC 116 (0x13A, 0x01), # SYSREF Divide [12:8] 117 (0x13B, 0xE0), # SYSREF Divide [7:0] 118 (0x13C, 0x00), # SYSREF DDLY [12:8] 119 (0x13D, 0x08), # SYSREF DDLY [7:0] ... 8 is default, <8 is reserved 120 (0x13E, 0x00), # SYSREF Pulse Count = 1 pulse/request 121 (0x13F, 0x0B), # Feedback Mux: Enabled, DCLKout6, drives PLL1N divider 122 (0x140, 0x00), # POWERDOWN options 123 (0x141, 0x08), # Dynamic digital delay enable 124 (0x142, 0x00), # Dynamic digital delay step 125 (0x143, 0xD1), # SYNC edge sensitive; SYSREF_CLR; SYNC Enabled; SYNC fro 126 (0x144, 0x00), # Enable SYNC on all outputs including sysref 127 (0x145, 0x7F), # Always program to d127 128 (0x146, 0x08), # CLKin Type & En 129 (0x147, 0x0E), # CLKin_SEL = CLKin1 manual; CLKin1 to PLL1 130 (0x148, 0x01), # CLKin_SEL0 = input with pullup 131 (0x149, 0x01), # CLKin_SEL1 = input with pulldown 132 (0x14A, 0x02), # RESET type as input w/pulldown 133 (0x14B, 0x01), # Holdover & DAC Manual Mode 134 (0x14C, 0xF6), # DAC Manual Mode 135 (0x14D, 0x00), # DAC Settings (defaults) 136 (0x14E, 0x00), # DAC Settings (defaults) 137 (0x14F, 0x7F), # DAC Settings (defaults) 138 (0x150, 0x00), # Holdover Settings; bits 0/1 = '0' per long PLL1 lock time debug 139 (0x151, 0x02), # Holdover Settings (defaults) 140 (0x152, 0x00), # Holdover Settings (defaults) 141 (0x153, 0x00), # CLKin0_R divider [13:8], default = 0 142 (0x154, clkin0_r_divider), # CLKin0_R divider [7:0], default = d120 143 (0x155, 0x00), # CLKin1_R divider [13:8], default = 0 144 (0x156, 0x01), # CLKin1_R divider [7:0], default = d120 145 (0x157, 0x00), # CLKin2_R divider [13:8], default = 0 146 (0x158, 0x01), # CLKin2_R divider [7:0], default = d120 147 (0x159, 0x00), # PLL1 N divider [13:8], default = 0 148 (0x15A, 0x68), # PLL1 N divider [7:0], default = d120 149 (0x15B, 0xCF), # PLL1 PFD 150 (0x15C, 0x27), # PLL1 DLD Count [13:8] 151 (0x15D, 0x10), # PLL1 DLD Count [7:0] 152 (0x15E, 0x00), # PLL1 R/N delay, defaults = 0 153 (0x15F, 0x13), # Status LD1 pin = PLL2 LD, push-pull output 154 (0x160, 0x00), # PLL2 R divider [11:8]; 155 (0x161, 0x01), # PLL2 R divider [7:0] 156 (0x162, 0x24), # PLL2 prescaler; OSCin freq 157 (0x163, 0x00), # PLL2 Cal = PLL2 normal val 158 (0x164, 0x00), # PLL2 Cal = PLL2 normal val 159 (0x165, 0x0C), # PLL2 Cal = PLL2 normal val 160 (0x171, 0xAA), # Write this val after x165 161 (0x172, 0x02), # Write this val after x165 162 (0x17C, 0x15), # VCo1 Cal; write before x168 163 (0x17D, 0x33), # VCo1 Cal; write before x168 164 (0x166, 0x00), # PLL2 N[17:16] 165 (0x167, 0x00), # PLL2 N[15:8] 166 (0x168, 0x0C), # PLL2 N[7:0] 167 (0x169, 0x51), # PLL2 PFD 168 (0x16A, 0x27), # PLL2 DLD Count [13:8] = default d32 169 (0x16B, 0x10), # PLL2 DLD Count [7:0] = default d0 170 (0x16C, 0x00), # PLL2 Loop filter r = 200 ohm 171 (0x16D, 0x00), # PLL2 loop filter c = 10 pF 172 (0x173, 0x00), # Do not power down PLL2 or prescaler 173 )) 174 # TODO: change to Polling. 175 time.sleep(1.0) # Increased time to wait for DAC and VCXO to settle. 176 self.pokes8(( 177 (0x182, 0x1), # Clear Lock Detect Sticky 178 (0x182, 0x0), # Clear Lock Detect Sticky 179 (0x183, 0x1), # Clear Lock Detect Sticky 180 (0x183, 0x0), # Clear Lock Detect Sticky 181 )) 182 time.sleep(0.1) 183 if not self.check_plls_locked(): 184 raise RuntimeError("At least one LMK PLL did not lock! Check the logs for details.") 185 self.log.trace("Setting SYNC and SYSREF config...") 186 self.pokes8(( 187 (0x143, 0xF1), # toggle SYNC polarity to trigger SYNC event 188 (0x143, 0xD1), # toggle SYNC polarity to trigger SYNC event 189 (0x139, 0x02), # SYSREF Source = MUX; SYSREF MUX = pulser 190 (0x144, 0xFF), # Disable SYNC on all outputs including sysref 191 (0x143, 0x52), # Pulser selected; SYNC enabled; 1 shot enabled 192 )) 193 self.log.debug("LMK init'd and locked!") 194 195 def lmk_shift(self, num_shifts=0): 196 """ 197 Apply time shift 198 199 TODO: See if we can move this up to parent class 200 """ 201 ddly_value = 0x67 if num_shifts >= 0 else 0x65 202 self.pokes8(( 203 (0x141, 0x4E), # Dynamic digital delay enable 204 (0x143, 0x53), # SYSREF_CLR; SYNC Enabled; SYNC from pulser @ regwrite 205 (0x139, 0x02), # SYSREF_MUX = Pulser 206 (0x109, ddly_value), # Set DDLY values for DCLKout2 +/-1 on low cnt. 207 # To Increment phase, write 0x65. Decrement = 0x67 208 (0x10A, ddly_value), # Hidden register. Write the same as previous based on inc/dec. 209 (0x111, ddly_value), # Set DDLY values for DCLKout4 +/-1 on low cnt 210 (0x112, ddly_value), # Hidden register. Write the same as previous based on inc/dec. 211 (0x119, ddly_value), # Set DDLY values for DCLKout6 +/-1 on low cnt 212 (0x11A, ddly_value), # Hidden register. Write the same as previous based on inc/dec. 213 (0x131, ddly_value), # Set DDLY values for DCLKout12 +/-1 on low cnt 214 (0x132, ddly_value), # Hidden register. Write the same as previous based on inc/dec. 215 (0x144, 0xB1), # Enable SYNC on outputs 2,4,6,12 216 )) 217 for x in range(abs(num_shifts)): 218 self.poke8(0x142, 0x1) 219 self.poke8(0x144, 0xFF) # Disable SYNC on all outputs 220 221