#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
raddds.py specializes Acq400 for RADCELF triple DDS device
- enumerates all site services, available as uut.sX.knob
- monitors transient status on uut, provides blocking events
- read_channels() reads all data from channel data service.
- simple property interface allows natural "script-like" usage
- eg::
uut1.s0.set_arm = 1
- equivalent to running this on a logged in shell session on the UUT::
set.site1 set_arm=1
Created on Sun Jan 8 12:36:38 2017
@author: pgm
"""
from . import acq400
from . import netclient
from builtins import staticmethod
[docs]class AD9854:
[docs] class CR:
regular_en = '0061'
chirp_en = '8761'
low_power = '0041'
power_down = '1F000001'
zero_hz = '00044041'
CLR_ACC2 = 1<<14
[docs] @staticmethod
# CR for clock * n
def CRX(n = 4, mode=CR.low_power, clr_acc2=False):
ca2 = AD9854.CR.CLR_ACC2 if clr_acc2 else 0
return '{:08x}'.format(int(n << 16) | int(mode, 16) | ca2)
[docs] @staticmethod
# UCR for chirps_per_sec
def UCR(chirps_per_sec, intclk=300e6):
return '{:08x}'.format(int(intclk/2/chirps_per_sec))
[docs] @staticmethod
def ftw2ratio(ftw):
return float(int('0x{}'.format(ftw), 16)/float(0x1000000000000))
[docs] @staticmethod
def ratio2ftw(ratio):
return format(int(ratio * pow(2, 48)), '012x')
[docs] @staticmethod
def CRX_chirp_off(n = 4):
return '{:08x}'.format(int(n << 16) | int(AD9854.CR.low_power, 16))
[docs] @staticmethod
def CRX_zero_hz(clr_acc2=True):
return AD9854.CR.zero_hz
[docs] @staticmethod
def CRX_power_down(clr_acc2=True):
return AD9854.CR.power_down
[docs]class AD9512:
[docs] class DIVX:
div4 = '1100'
passthru = '0080'
[docs] @staticmethod
def setDIVX(clkd, value):
clkd.DIV0 = value
clkd.DIV1 = value
clkd.DIV2 = value
clkd.DIV3 = value
clkd.DIV4 = value
clkd.UPDATE = '01'
[docs] @staticmethod
def clocksON(clkd):
clkd.LVPECL1 = '08'
clkd.LVPECL0 = '08'
clkd.UPDATE = '01'
[docs]class RAD3DDS(acq400.Acq400):
[docs] @staticmethod
def best_clock_pps_sync(fs):
return fs//512 * 512;
[docs] @staticmethod
def ftw2ratio(ftw):
return AD9854.ftw2ratio(ftw)
[docs] @staticmethod
def ratio2ftw(ratio):
return AD9854.ratio2ftw(ratio)
[docs] @staticmethod
def pulse(knob):
knob = 1
knob = 0
[docs] def chirp_freq(self, idds):
# idds 0: A, 1: B
assert idds >= 0 and idds <= 1
return acq400.freq(self.s0.get_knob('SIG_TRG_S{}_FREQ'.format(2+idds)))
[docs] def dds_freq(self, idds):
# idds 0: A, 1: B, 2: C
assert idds >= 0 and idds <= 2
return acq400.freq(self.s0.get_knob('SIG_CLK_S{}_FREQ'.format(3+idds)))
[docs] def radcelf_init(self):
# port of original RADCELF_init shell script
#Reset the entire clock chain
RAD3DDS.pulse(self.s2.clkd_hard_reset)
self.clkdA.CSPD = '00'
self.clkdA.UPDATE = '01'
# Set Primary Clock LVPECL 2 Off, set LVDS 3 to Off, Set LVDS 4 to TTL
self.clkdA.LVPECL2 = '0a'
self.clkdA.LVDS3 = '01'
self.clkdA.LVDS4 = '08'
self.clkdA.UPDATE = '01'
# Set Secondary Clock LVPECL 2 Off, set LVDS 3 to TTL
self.clkdB.LVPECL2 = '0a'
self.clkdB.LVDS3 = '08'
self.clkdB.UPDATE = '01'
#Set all the clkdA AD9512 dividers to divide by 4 to avoid overheat
#100MHz / 4 = 25Mhz source clock
AD9512.setDIVX(self.clkdA, AD9512.DIVX.div4)
# set clkdB to pass-thru
AD9512.setDIVX(self.clkdB, AD9512.DIVX.passthru)
# Reset the DDS
RAD3DDS.pulse(self.s2.ddsX_hard_reset)
#Switch the clocks off on the DDS Devices to stop I/O Updates
#Clock Remapping DDS - Device clkA Output 1
self.clkdA.LVPECL1 = '0a'
self.clkdA.UPDATE = '01'
#The two Main DDS devices on device clkB Outputs 0 and 1
self.clkdB.LVPECL0 = '0a'
self.clkdB.LVPECL1 = '0a'
self.clkdB.UPDATE = '01'
# Write to the Control Registers on the 3 DDS devices -
# External I/O Update and SDO On
# Set the RefClk Multiplier on at x4 switch off the Inverse Sinc Filter
self.ddsA.CR = AD9854.CR.low_power
self.ddsB.CR = AD9854.CR.low_power
self.ddsC.CR = AD9854.CR.low_power
#Switch the Clocks back on again
AD9512.clocksON(self.clkdA)
AD9512.clocksON(self.clkdB)
# tell FPGA to take over the clocking
self.s2.ddsA_upd_clk_fpga = 1
self.s2.ddsB_upd_clk_fpga = 1
self.s2.ddsC_upd_clk_fpga = 1
self.ddsA.strobe_mode = 1
self.ddsB.strobe_mode = 1
self.ddsC.strobe_mode = 1
[docs] def __init__(self, _uut, monitor=True):
acq400.Acq400.__init__(self, _uut, monitor)
site = 4
for sm in [ 'ddsA', 'ddsB', 'ddsC']:
self.svc[sm] = netclient.Siteclient(self.uut, acq400.AcqPorts.SITE0+site)
self.mod_count += 1
site += 1
site = 7
for sm in [ 'clkdA', 'clkdB']:
self.svc[sm] = netclient.Siteclient(self.uut, acq400.AcqPorts.SITE0+site)
self.mod_count += 1
site += 1