forked from M-Labs/artiq
phaser: dac and trf register maps, init code
This commit is contained in:
parent
3e036e365a
commit
fd5e221898
|
@ -0,0 +1,262 @@
|
|||
class DAC34H84:
|
||||
"""DAC34H84 settings and register map.
|
||||
|
||||
For possible values, documentation, and explanation, see the DAC datasheet
|
||||
at https://www.ti.com/lit/pdf/slas751
|
||||
"""
|
||||
qmc_corr_ena = 0 # msb ab
|
||||
qmc_offset_ena = 0 # msb ab
|
||||
invsinc_ena = 0 # msb ab
|
||||
interpolation = 1 # 2x
|
||||
fifo_ena = 1
|
||||
alarm_out_ena = 1
|
||||
alarm_out_pol = 1
|
||||
clkdiv_sync_ena = 1
|
||||
|
||||
iotest_ena = 0
|
||||
cnt64_ena = 0
|
||||
oddeven_parity = 0 # even
|
||||
single_parity_ena = 1
|
||||
dual_parity_ena = 0
|
||||
rev_interface = 0
|
||||
dac_complement = 0b0000 # msb A
|
||||
alarm_fifo = 0b111 # msb 2-away
|
||||
|
||||
dacclkgone_ena = 1
|
||||
dataclkgone_ena = 1
|
||||
collisiongone_ena = 1
|
||||
sif4_ena = 1
|
||||
mixer_ena = 0
|
||||
mixer_gain = 1
|
||||
nco_ena = 0
|
||||
revbus = 0
|
||||
twos = 1
|
||||
|
||||
coarse_dac = 0xa # 20.6 mA, 0-15
|
||||
sif_txenable = 0
|
||||
|
||||
mask_alarm_from_zerochk = 0
|
||||
mask_alarm_fifo_collision = 0
|
||||
mask_alarm_fifo_1away = 0
|
||||
mask_alarm_fifo_2away = 0
|
||||
mask_alarm_dacclk_gone = 0
|
||||
mask_alarm_dataclk_gone = 0
|
||||
mask_alarm_output_gone = 0
|
||||
mask_alarm_from_iotest = 0
|
||||
mask_alarm_from_pll = 0
|
||||
mask_alarm_parity = 0b0000 # msb a
|
||||
|
||||
qmc_offseta = 0 # 12b
|
||||
fifo_offset = 2 # 0-7
|
||||
qmc_offsetb = 0 # 12b
|
||||
|
||||
qmc_offsetc = 0 # 12b
|
||||
|
||||
qmc_offsetd = 0 # 12b
|
||||
|
||||
qmc_gaina = 0 # 11b
|
||||
|
||||
cmix_fs8 = 0
|
||||
cmix_fs4 = 0
|
||||
cmix_fs2 = 0
|
||||
cmix_nfs4 = 0
|
||||
qmc_gainb = 0 # 11b
|
||||
|
||||
qmc_gainc = 0 # 11b
|
||||
|
||||
output_delayab = 0b00
|
||||
output_delaycd = 0b00
|
||||
qmc_gaind = 0 # 11b
|
||||
|
||||
qmc_phaseab = 0 # 12b
|
||||
|
||||
qmc_phasecd = 0 # 12b
|
||||
|
||||
pll_reset = 0
|
||||
pll_ndivsync_ena = 1
|
||||
pll_ena = 1
|
||||
pll_cp = 0b01 # single charge pump
|
||||
pll_p = 0b100 # p=4
|
||||
|
||||
pll_m2 = 1 # x2
|
||||
pll_m = 8 # m = 8
|
||||
pll_n = 0b0001 # n = 2
|
||||
pll_vcotune = 0b01
|
||||
|
||||
pll_vco = 0x3f # 4 GHz
|
||||
bias_sleep = 0
|
||||
tsense_sleep = 0
|
||||
pll_sleep = 0
|
||||
clkrecv_sleep = 0
|
||||
dac_sleep = 0b0000 # msb a
|
||||
|
||||
extref_ena = 0
|
||||
fuse_sleep = 1
|
||||
atest = 0b00000 # atest mode
|
||||
|
||||
syncsel_qmcoffsetab = 0b1001 # sif_sync and register write
|
||||
syncsel_qmcoffsetcd = 0b1001 # sif_sync and register write
|
||||
syncsel_qmccorrab = 0b1001 # sif_sync and register write
|
||||
syncsel_qmccorrcd = 0b1001 # sif_sync and register write
|
||||
|
||||
syncsel_mixerab = 0b1001 # sif_sync and register write
|
||||
syncsel_mixercd = 0b1001 # sif_sync and register write
|
||||
syncsel_nco = 0b1000 # sif_sync
|
||||
syncsel_fifo_input = 0b10 # external lvds istr
|
||||
sif_sync = 1
|
||||
|
||||
syncsel_fifoin = 0b0010 # istr
|
||||
syncsel_fifoout = 0b0100 # ostr
|
||||
clkdiv_sync_sel = 0 # ostr
|
||||
|
||||
path_a_sel = 0b00
|
||||
path_b_sel = 0b01
|
||||
path_c_sel = 0b10
|
||||
path_d_sel = 0b11
|
||||
# reverse dacs (DCBA) for spectral inversion and layout
|
||||
dac_a_sel = 0b11
|
||||
dac_b_sel = 0b10
|
||||
dac_c_sel = 0b01
|
||||
dac_d_sel = 0b00
|
||||
|
||||
dac_sleep_en = 0b1111 # msb a
|
||||
clkrecv_sleep_en = 1
|
||||
pll_sleep_en = 1
|
||||
lvds_data_sleep_en = 1
|
||||
lvds_control_sleep_en = 1
|
||||
temp_sense_sleep_en = 1
|
||||
bias_sleep_en = 1
|
||||
|
||||
data_dly = 2
|
||||
clk_dly = 0
|
||||
|
||||
ostrtodig_sel = 0
|
||||
ramp_ena = 0
|
||||
sifdac_ena = 0
|
||||
|
||||
grp_delaya = 0x00
|
||||
grp_delayb = 0x00
|
||||
|
||||
grp_delayc = 0x00
|
||||
grp_delayd = 0x00
|
||||
|
||||
sifdac = 0
|
||||
|
||||
def __init__(self, updates=None):
|
||||
if updates is None:
|
||||
return
|
||||
for key, value in updates.items():
|
||||
if not hasattr(self, key):
|
||||
raise KeyError("invalid setting", key)
|
||||
setattr(self, key, value)
|
||||
|
||||
def get_mmap(self):
|
||||
mmap = []
|
||||
mmap.append(
|
||||
(0x00 << 16) |
|
||||
(self.qmc_offset_ena << 14) | (self.qmc_corr_ena << 12) |
|
||||
(self.interpolation << 8) | (self.fifo_ena << 7) |
|
||||
(self.alarm_out_ena << 4) | (self.alarm_out_pol << 3) |
|
||||
(self.clkdiv_sync_ena << 2) | (self.invsinc_ena << 0))
|
||||
mmap.append(
|
||||
(0x01 << 16) |
|
||||
(self.iotest_ena << 15) | (self.cnt64_ena << 12) |
|
||||
(self.oddeven_parity << 11) | (self.single_parity_ena << 10) |
|
||||
(self.dual_parity_ena << 9) | (self.rev_interface << 8) |
|
||||
(self.dac_complement << 4) | (self.alarm_fifo << 1))
|
||||
mmap.append(
|
||||
(0x02 << 16) |
|
||||
(self.dacclkgone_ena << 14) | (self.dataclkgone_ena << 13) |
|
||||
(self.collisiongone_ena << 12) | (self.sif4_ena << 7) |
|
||||
(self.mixer_ena << 6) | (self.mixer_gain << 5) |
|
||||
(self.nco_ena << 4) | (self.revbus << 3) | (self.twos << 1))
|
||||
mmap.append((0x03 << 16) | (self.coarse_dac << 12) | (self.sif_txenable << 0))
|
||||
mmap.append(
|
||||
(0x07 << 16) |
|
||||
(self.mask_alarm_from_zerochk << 15) | (1 << 14) |
|
||||
(self.mask_alarm_fifo_collision << 13) |
|
||||
(self.mask_alarm_fifo_1away << 12) |
|
||||
(self.mask_alarm_fifo_2away << 11) |
|
||||
(self.mask_alarm_dacclk_gone << 10) |
|
||||
(self.mask_alarm_dataclk_gone << 9) |
|
||||
(self.mask_alarm_output_gone << 8) |
|
||||
(self.mask_alarm_from_iotest << 7) | (1 << 6) |
|
||||
(self.mask_alarm_from_pll << 5) | (self.mask_alarm_parity << 1))
|
||||
mmap.append(
|
||||
(0x08 << 16) | (self.qmc_offseta << 0))
|
||||
mmap.append(
|
||||
(0x09 << 16) | (self.fifo_offset << 13) | (self.qmc_offsetb << 0))
|
||||
mmap.append((0x0a << 16) | (self.qmc_offsetc << 0))
|
||||
mmap.append((0x0b << 16) | (self.qmc_offsetd << 0))
|
||||
mmap.append((0x0c << 16) | (self.qmc_gaina << 0))
|
||||
mmap.append(
|
||||
(0x0d << 16) |
|
||||
(self.cmix_fs8 << 15) | (self.cmix_fs4 << 14) |
|
||||
(self.cmix_fs2 << 12) | (self.cmix_nfs4 << 11) |
|
||||
(self.qmc_gainb << 0))
|
||||
mmap.append((0x0e << 16) | (self.qmc_gainc << 0))
|
||||
mmap.append(
|
||||
(0x0f << 16) |
|
||||
(self.output_delayab << 14) | (self.output_delaycd << 12) |
|
||||
(self.qmc_gaind << 0))
|
||||
mmap.append((0x10 << 16) | (self.qmc_phaseab << 0))
|
||||
mmap.append((0x11 << 16) | (self.qmc_phasecd << 0))
|
||||
mmap.append(
|
||||
(0x18 << 16) |
|
||||
(0b001 << 13) | (self.pll_reset << 12) |
|
||||
(self.pll_ndivsync_ena << 11) | (self.pll_ena << 10) |
|
||||
(self.pll_cp << 6) | (self.pll_p << 3))
|
||||
mmap.append(
|
||||
(0x19 << 16) |
|
||||
(self.pll_m2 << 15) | (self.pll_m << 8) | (self.pll_n << 4) |
|
||||
(self.pll_vcotune << 2))
|
||||
mmap.append(
|
||||
(0x1a << 16) |
|
||||
(self.pll_vco << 10) | (self.bias_sleep << 7) |
|
||||
(self.tsense_sleep << 6) |
|
||||
(self.pll_sleep << 5) | (self.clkrecv_sleep << 4) |
|
||||
(self.dac_sleep << 0))
|
||||
mmap.append(
|
||||
(0x1b << 16) |
|
||||
(self.extref_ena << 15) | (self.fuse_sleep << 11) |
|
||||
(self.atest << 0))
|
||||
mmap.append(
|
||||
(0x1e << 16) |
|
||||
(self.syncsel_qmcoffsetab << 12) |
|
||||
(self.syncsel_qmcoffsetcd << 8) |
|
||||
(self.syncsel_qmccorrab << 4) |
|
||||
(self.syncsel_qmccorrcd << 0))
|
||||
mmap.append(
|
||||
(0x1f << 16) |
|
||||
(self.syncsel_mixerab << 12) | (self.syncsel_mixercd << 8) |
|
||||
(self.syncsel_nco << 4) | (self.syncsel_fifo_input << 2) |
|
||||
(self.sif_sync << 1))
|
||||
mmap.append(
|
||||
(0x20 << 16) |
|
||||
(self.syncsel_fifoin << 12) | (self.syncsel_fifoout << 8) |
|
||||
(self.clkdiv_sync_sel << 0))
|
||||
mmap.append(
|
||||
(0x22 << 16) |
|
||||
(self.path_a_sel << 14) | (self.path_b_sel << 12) |
|
||||
(self.path_c_sel << 10) | (self.path_d_sel << 8) |
|
||||
(self.dac_a_sel << 6) | (self.dac_b_sel << 4) |
|
||||
(self.dac_c_sel << 2) | (self.dac_d_sel << 0))
|
||||
mmap.append(
|
||||
(0x23 << 16) |
|
||||
(self.dac_sleep_en << 12) | (self.clkrecv_sleep_en << 11) |
|
||||
(self.pll_sleep_en << 10) | (self.lvds_data_sleep_en << 9) |
|
||||
(self.lvds_control_sleep_en << 8) |
|
||||
(self.temp_sense_sleep_en << 7) | (1 << 6) |
|
||||
(self.bias_sleep_en << 5) | (0x1f << 0))
|
||||
mmap.append(
|
||||
(0x24 << 16) | (self.data_dly << 13) | (self.clk_dly << 10))
|
||||
mmap.append(
|
||||
(0x2d << 16) |
|
||||
(self.ostrtodig_sel << 14) | (self.ramp_ena << 13) |
|
||||
(0x002 << 1) | (self.sifdac_ena << 0))
|
||||
mmap.append(
|
||||
(0x2e << 16) | (self.grp_delaya << 8) | (self.grp_delayb << 0))
|
||||
mmap.append(
|
||||
(0x2f << 16) | (self.grp_delayc << 8) | (self.grp_delayd << 0))
|
||||
mmap.append((0x30 << 16) | self.sifdac)
|
||||
return mmap
|
|
@ -2,6 +2,8 @@ from artiq.language.core import kernel, delay_mu, delay
|
|||
from artiq.coredevice.rtio import rtio_output, rtio_input_data
|
||||
from artiq.language.units import us, ns, ms, MHz, dB
|
||||
from artiq.language.types import TInt32
|
||||
from artiq.coredevice.dac34h84 import DAC34H84
|
||||
from artiq.coredevice.trf372017 import TRF372017
|
||||
|
||||
|
||||
PHASER_BOARD_ID = 19
|
||||
|
@ -106,10 +108,22 @@ class Phaser:
|
|||
configured through a shared SPI bus that is accessed and controlled via
|
||||
FPGA registers.
|
||||
|
||||
.. note:: Various register settings of the DAC and the quadrature
|
||||
upconverters are available to be modified through the `dac`, `trf0`,
|
||||
`trf1` dictionaries. These can be set through the device database
|
||||
(`device_db.py`). The settings are frozen during instantiation of the
|
||||
class and applied during `init()`. See the :class:`DAC34H84` and
|
||||
:class:`TRF372017` source for details.
|
||||
|
||||
:param channel: Base RTIO channel number
|
||||
:param core_device: Core device name (default: "core")
|
||||
:param miso_delay: Fastlink MISO signal delay to account for cable
|
||||
and buffer round trip. This might be automated later.
|
||||
and buffer round trip. Tuning this might be automated later.
|
||||
:param dac: DAC34H84 DAC settings as a dictionary.
|
||||
:param trf0: Channel 0 TRF372017 quadrature upconverter settings as a
|
||||
dictionary.
|
||||
:param trf1: Channel 1 TRF372017 quadrature upconverter settings as a
|
||||
dictionary.
|
||||
|
||||
Attributes:
|
||||
|
||||
|
@ -117,9 +131,11 @@ class Phaser:
|
|||
To access oscillators, digital upconverters, PLL/VCO analog
|
||||
quadrature upconverters and attenuators.
|
||||
"""
|
||||
kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay"}
|
||||
kernel_invariants = {"core", "channel_base", "t_frame", "miso_delay",
|
||||
"dac_mmap"}
|
||||
|
||||
def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core"):
|
||||
def __init__(self, dmgr, channel_base, miso_delay=1, core_device="core",
|
||||
dac=None, trf0=None, trf1=None):
|
||||
self.channel_base = channel_base
|
||||
self.core = dmgr.get(core_device)
|
||||
# TODO: auto-align miso-delay in phy
|
||||
|
@ -129,14 +145,18 @@ class Phaser:
|
|||
assert self.core.ref_period == 1*ns
|
||||
self.t_frame = 10*8*4
|
||||
|
||||
self.channel = [PhaserChannel(self, ch) for ch in range(2)]
|
||||
self.dac_mmap = DAC34H84(dac).get_mmap()
|
||||
|
||||
self.channel = [PhaserChannel(self, ch, trf)
|
||||
for ch, trf in enumerate([trf0, trf1])]
|
||||
|
||||
@kernel
|
||||
def init(self, clk_sel=0):
|
||||
"""Initialize the board.
|
||||
|
||||
Verifies board and chip presence, resets components, performs communication
|
||||
and configuration tests and establishes initial conditions.
|
||||
Verifies board and chip presence, resets components, performs
|
||||
communication and configuration tests and establishes initial
|
||||
conditions.
|
||||
|
||||
:param clk_sel: Select the external SMA clock input (1 or 0)
|
||||
"""
|
||||
|
@ -145,18 +165,28 @@ class Phaser:
|
|||
raise ValueError("invalid board id")
|
||||
delay(20*us) # slack
|
||||
|
||||
hw_rev = self.read8(PHASER_ADDR_HW_REV)
|
||||
delay(.1*ms) # slack
|
||||
has_upconverter = hw_rev & PHASER_HW_REV_VARIANT
|
||||
|
||||
gw_rev = self.read8(PHASER_ADDR_GW_REV)
|
||||
delay(.1*ms) # slack
|
||||
|
||||
# allow a few errors during startup and alignment since boot
|
||||
if self.get_crc_err() > 20:
|
||||
raise ValueError("large number of frame CRC errors")
|
||||
delay(.1*ms) # slack
|
||||
|
||||
# reset
|
||||
self.set_cfg(dac_resetb=0, att0_rstn=0, att1_rstn=0, dac_txena=0)
|
||||
self.set_cfg(dac_resetb=0, dac_sleep=1, att0_rstn=0, att1_rstn=0,
|
||||
dac_txena=0)
|
||||
self.set_leds(0x00)
|
||||
self.set_fan_mu(0)
|
||||
self.set_cfg(clk_sel=clk_sel, dac_txena=0) # bring everything out of reset
|
||||
# bring everything out of reset, keep tx off
|
||||
self.set_cfg(clk_sel=clk_sel, dac_txena=0)
|
||||
|
||||
# TODO: crossing dac_clk (125 MHz) edges with sync_dly (0-7 ns)
|
||||
# should change the optimal fifo_offset
|
||||
# should change the optimal fifo_offset by 4
|
||||
self.set_sync_dly(4)
|
||||
delay(.1*ms) # slack
|
||||
|
||||
|
@ -174,6 +204,10 @@ class Phaser:
|
|||
if t < 10 or t > 90:
|
||||
raise ValueError("DAC temperature out of bounds")
|
||||
|
||||
for data in self.dac_mmap:
|
||||
self.dac_write(data >> 16, data)
|
||||
delay(.1*ms)
|
||||
|
||||
patterns = [
|
||||
[0xf05a, 0x05af, 0x5af0, 0xaf05], # test channel/iq/byte/nibble
|
||||
[0x7a7a, 0xb6b6, 0xeaea, 0x4545], # datasheet pattern a
|
||||
|
@ -183,206 +217,25 @@ class Phaser:
|
|||
# FPGA+board+DAC skews. There is plenty of margin (>= 250 ps
|
||||
# either side) and no need to tune at runtime.
|
||||
# Parity provides another level of safety.
|
||||
for dly in [-2]: # range(-7, 8)
|
||||
if dly < 0: # use data delay, else use clock delay
|
||||
dly = -dly << 3
|
||||
self.dac_write(0x24, dly << 10)
|
||||
for i in range(len(patterns)):
|
||||
delay(.5*ms)
|
||||
errors = self.dac_iotest(patterns[i])
|
||||
if errors:
|
||||
raise ValueError("DAC iotest failure")
|
||||
delay(.5*ms)
|
||||
|
||||
qmc_corr_ena = 0 # msb ab
|
||||
qmc_offset_ena = 0 # msb ab
|
||||
invsinc_ena = 0 # msb ab
|
||||
|
||||
interpolation = 1 # 2x
|
||||
fifo_ena = 1
|
||||
alarm_out_ena = 1
|
||||
alarm_out_pol = 1
|
||||
clkdiv_sync_ena = 1
|
||||
self.dac_write(0x00,
|
||||
(qmc_offset_ena << 14) | (qmc_corr_ena << 12) |
|
||||
(interpolation << 8) | (fifo_ena << 7) |
|
||||
(alarm_out_ena << 4) | (alarm_out_pol << 3) |
|
||||
(clkdiv_sync_ena << 2) | (invsinc_ena << 0))
|
||||
iotest_ena = 0
|
||||
cnt64_ena = 0
|
||||
oddeven_parity = 0 # even
|
||||
single_parity_ena = 1
|
||||
dual_parity_ena = 0
|
||||
rev_interface = 0
|
||||
dac_complement = 0b0000 # msb A
|
||||
alarm_fifo = 0b111 # msb 2-away
|
||||
self.dac_write(0x01,
|
||||
(iotest_ena << 15) | (cnt64_ena << 12) |
|
||||
(oddeven_parity << 11) | (single_parity_ena << 10) |
|
||||
(dual_parity_ena << 9) | (rev_interface << 8) |
|
||||
(dac_complement << 4) | (alarm_fifo << 1))
|
||||
dacclkgone_ena = 1
|
||||
dataclkgone_ena = 1
|
||||
collisiongone_ena = 1
|
||||
sif4_ena = 1
|
||||
mixer_ena = 0
|
||||
mixer_gain = 1
|
||||
nco_ena = 0
|
||||
revbus = 0
|
||||
twos = 1
|
||||
self.dac_write(0x02,
|
||||
(dacclkgone_ena << 14) | (dataclkgone_ena << 13) |
|
||||
(collisiongone_ena << 12) | (sif4_ena << 7) |
|
||||
(mixer_ena << 6) | (mixer_gain << 5) |
|
||||
(nco_ena << 4) | (revbus << 3) | (twos << 1))
|
||||
coarse_dac = 0xa # 20.6 mA, 0-15
|
||||
sif_txenable = 0
|
||||
self.dac_write(0x03, (coarse_dac << 12) | (sif_txenable << 0))
|
||||
mask_alarm_from_zerochk = 0
|
||||
mask_alarm_fifo_collision = 0
|
||||
mask_alarm_fifo_1away = 0
|
||||
mask_alarm_fifo_2away = 0
|
||||
mask_alarm_dacclk_gone = 0
|
||||
mask_alarm_dataclk_gone = 0
|
||||
mask_alarm_output_gone = 0
|
||||
mask_alarm_from_iotest = 0
|
||||
mask_alarm_from_pll = 0
|
||||
mask_alarm_parity = 0b0000 # msb a
|
||||
self.dac_write(0x07,
|
||||
(mask_alarm_from_zerochk << 15) | (1 << 14) |
|
||||
(mask_alarm_fifo_collision << 13) | (mask_alarm_fifo_1away << 12) |
|
||||
(mask_alarm_fifo_2away << 11) | (mask_alarm_dacclk_gone << 10) |
|
||||
(mask_alarm_dataclk_gone << 9) | (mask_alarm_output_gone << 8) |
|
||||
(mask_alarm_from_iotest << 7) | (1 << 6) |
|
||||
(mask_alarm_from_pll << 5) | (mask_alarm_parity << 1))
|
||||
qmc_offseta = 0 # 12b
|
||||
self.dac_write(0x08, qmc_offseta)
|
||||
fifo_offset = 2 # 0-7
|
||||
qmc_offsetb = 0 # 12b
|
||||
self.dac_write(0x09, (fifo_offset << 13) | qmc_offsetb)
|
||||
qmc_offsetc = 0 # 12b
|
||||
self.dac_write(0x0a, qmc_offsetc)
|
||||
qmc_offsetd = 0 # 12b
|
||||
self.dac_write(0x0b, qmc_offsetd)
|
||||
qmc_gaina = 0 # 11b
|
||||
self.dac_write(0x0c, qmc_gaina)
|
||||
cmix_fs8 = 0
|
||||
cmix_fs4 = 0
|
||||
cmix_fs2 = 0
|
||||
cmix_nfs4 = 0
|
||||
qmc_gainb = 0 # 11b
|
||||
self.dac_write(0x0d,
|
||||
(cmix_fs8 << 15) | (cmix_fs4 << 14) | (cmix_fs2 << 12) |
|
||||
(cmix_nfs4 << 11) | qmc_gainb)
|
||||
qmc_gainc = 0 # 11b
|
||||
self.dac_write(0x0e, qmc_gainc)
|
||||
output_delayab = 0b00
|
||||
output_delaycd = 0b00
|
||||
qmc_gaind = 0 # 11b
|
||||
self.dac_write(0x0f, (output_delayab << 14) | (output_delaycd << 12) |
|
||||
qmc_gaind)
|
||||
qmc_phaseab = 0 # 12b
|
||||
self.dac_write(0x10, qmc_phaseab)
|
||||
qmc_phasecd = 0 # 12b
|
||||
self.dac_write(0x11, qmc_phasecd)
|
||||
pll_reset = 0
|
||||
pll_ndivsync_ena = 1
|
||||
pll_ena = 1
|
||||
pll_cp = 0b01 # single charge pump
|
||||
pll_p = 0b100 # p=4
|
||||
self.dac_write(0x18,
|
||||
(0b001 << 13) | (pll_reset << 12) |
|
||||
(pll_ndivsync_ena << 11) | (pll_ena << 10) |
|
||||
(pll_cp << 6) | (pll_p << 3))
|
||||
pll_m2 = 1 # x2
|
||||
pll_m = 8 # m = 8
|
||||
pll_n = 0b0001 # n = 2
|
||||
pll_vcotune = 0b01
|
||||
self.dac_write(0x19,
|
||||
(pll_m2 << 15) | (pll_m << 8) | (pll_n << 4) | (pll_vcotune << 2))
|
||||
delay(.5*ms) # slack
|
||||
pll_vco = 0x3f # 4 GHz
|
||||
bias_sleep = 0
|
||||
tsense_sleep = 0
|
||||
pll_sleep = 0
|
||||
clkrecv_sleep = 0
|
||||
dac_sleep = 0b0000 # msb a
|
||||
self.dac_write(0x1a,
|
||||
(pll_vco << 10) | (bias_sleep << 7) | (tsense_sleep << 6) |
|
||||
(pll_sleep << 5) | (clkrecv_sleep << 4) | (dac_sleep << 0))
|
||||
extref_ena = 0
|
||||
fuse_sleep = 1
|
||||
atest = 0b00000 # atest mode
|
||||
self.dac_write(0x1b,
|
||||
(extref_ena << 15) | (fuse_sleep << 11) | (atest << 0))
|
||||
syncsel_qmcoffsetab = 0b1001 # sif_sync and register write
|
||||
syncsel_qmcoffsetcd = 0b1001 # sif_sync and register write
|
||||
syncsel_qmccorrab = 0b1001 # sif_sync and register write
|
||||
syncsel_qmccorrcd = 0b1001 # sif_sync and register write
|
||||
self.dac_write(0x1e,
|
||||
(syncsel_qmcoffsetab << 12) | (syncsel_qmcoffsetcd << 8) |
|
||||
(syncsel_qmccorrab << 4) | (syncsel_qmccorrcd << 0))
|
||||
syncsel_mixerab = 0b1001 # sif_sync and register write
|
||||
syncsel_mixercd = 0b1001 # sif_sync and register write
|
||||
syncsel_nco = 0b1000 # sif_sync
|
||||
syncsel_fifo_input = 0b10 # external lvds istr
|
||||
sif_sync = 1
|
||||
self.dac_write(0x1e,
|
||||
(syncsel_mixerab << 12) | (syncsel_mixercd << 8) |
|
||||
(syncsel_nco << 4) | (syncsel_fifo_input << 2) |
|
||||
(sif_sync << 1))
|
||||
syncsel_fifoin = 0b0010 # istr
|
||||
syncsel_fifoout = 0b0100 # ostr
|
||||
clkdiv_sync_sel = 0 # ostr
|
||||
self.dac_write(0x20,
|
||||
(syncsel_fifoin << 12) | (syncsel_fifoout << 8) |
|
||||
(clkdiv_sync_sel << 0))
|
||||
path_a_sel = 0b00
|
||||
path_b_sel = 0b01
|
||||
path_c_sel = 0b10
|
||||
path_d_sel = 0b11
|
||||
# reverse dacs (DCBA) for spectral inversion and layout
|
||||
dac_a_sel = 0b11
|
||||
dac_b_sel = 0b10
|
||||
dac_c_sel = 0b01
|
||||
dac_d_sel = 0b00
|
||||
self.dac_write(0x22,
|
||||
(path_a_sel << 14) | (path_b_sel << 12) |
|
||||
(path_c_sel << 10) | (path_d_sel << 8) |
|
||||
(dac_a_sel << 6) | (dac_b_sel << 4) |
|
||||
(dac_c_sel << 2) | (dac_d_sel << 0))
|
||||
dac_sleep_en = 0b1111 # msb a
|
||||
clkrecv_sleep_en = 1
|
||||
pll_sleep_en = 1
|
||||
lvds_data_sleep_en = 1
|
||||
lvds_control_sleep_en = 1
|
||||
temp_sense_sleep_en = 1
|
||||
bias_sleep_en = 1
|
||||
self.dac_write(0x23,
|
||||
(dac_sleep_en << 12) | (clkrecv_sleep_en << 11) |
|
||||
(pll_sleep_en << 10) | (lvds_data_sleep_en << 9) |
|
||||
(lvds_control_sleep_en << 8) | (temp_sense_sleep_en << 7) |
|
||||
(1 << 6) | (bias_sleep_en << 5) | (0x1f << 0))
|
||||
# self.dac_write(0x24, 0x0000) # clk and data delays (tuned above)
|
||||
ostrtodig_sel = 0
|
||||
ramp_ena = 0
|
||||
sifdac_ena = 0
|
||||
self.dac_write(0x2d,
|
||||
(ostrtodig_sel << 14) | (ramp_ena << 13) | (0x002 << 1) |
|
||||
(sifdac_ena << 0))
|
||||
grp_delaya = 0x00
|
||||
grp_delayb = 0x00
|
||||
self.dac_write(0x2e, (grp_delaya << 8) | (grp_delayb << 0))
|
||||
grp_delayc = 0x00
|
||||
grp_delayd = 0x00
|
||||
self.dac_write(0x2f, (grp_delayc << 8) | (grp_delayd << 0))
|
||||
sifdac = 0
|
||||
self.dac_write(0x30, sifdac)
|
||||
|
||||
delay(10*ms) # let it settle
|
||||
lvolt = self.dac_read(0x18) & 7
|
||||
delay(.1*ms)
|
||||
if lvolt < 2 or lvolt > 5:
|
||||
raise ValueError("DAC PLL tuning voltage out of bounds")
|
||||
|
||||
# self.dac_write(0x20, 0x0000) # stop fifo sync
|
||||
# alarm = self.get_sta() & 1
|
||||
# delay(.1*ms)
|
||||
self.clear_dac_alarms()
|
||||
delay(2*ms) # let it run a bit
|
||||
self.check_dac_alarms()
|
||||
|
||||
for ch in range(2):
|
||||
channel = self.channel[ch]
|
||||
# test attenuator write and readback
|
||||
|
@ -400,7 +253,7 @@ class Phaser:
|
|||
asf = 0x7fff
|
||||
# 6pi/4 phase
|
||||
oscillator.set_amplitude_phase_mu(asf=asf, pow=0xc000, clr=1)
|
||||
delay_mu(8)
|
||||
delay(1*us)
|
||||
# 3pi/4
|
||||
channel.set_duc_phase_mu(0x6000)
|
||||
channel.set_duc_cfg(select=0, clr=1)
|
||||
|
@ -414,19 +267,17 @@ class Phaser:
|
|||
# allow ripple
|
||||
if (data_i < sqrt2 - 30 or data_i > sqrt2 or
|
||||
abs(data_i - data_q) > 2):
|
||||
print(data)
|
||||
raise ValueError("DUC+oscillator phase/amplitude test failed")
|
||||
|
||||
# self.dac_write(0x20, 0x0000) # stop fifo sync
|
||||
# alarm = self.get_sta() & 1
|
||||
# delay(.1*ms)
|
||||
self.clear_dac_alarms()
|
||||
delay(2*ms) # let it run a bit
|
||||
self.check_dac_alarms()
|
||||
|
||||
hw_rev = self.read8(PHASER_ADDR_HW_REV)
|
||||
has_upconverter = hw_rev & PHASER_HW_REV_VARIANT
|
||||
delay(.1*ms) # slack
|
||||
if has_upconverter:
|
||||
for data in channel.trf_mmap:
|
||||
channel.trf_write(data)
|
||||
delay(.1*ms)
|
||||
delay(1*ms) # lock
|
||||
lock_detect = self.get_sta() & (PHASER_STA_TRF0_LD << ch)
|
||||
delay(.1*ms)
|
||||
if not lock_detect:
|
||||
raise ValueError("TRF quadrature upconverter lock failure")
|
||||
|
||||
self.set_cfg(clk_sel=clk_sel) # txena
|
||||
|
||||
|
@ -662,7 +513,6 @@ class Phaser:
|
|||
alarm = self.get_dac_alarms()
|
||||
delay(.1*ms) # slack
|
||||
if alarm & ~0x0040: # ignore PLL alarms (see DS)
|
||||
print(alarm)
|
||||
raise ValueError("DAC alarm")
|
||||
|
||||
@kernel
|
||||
|
@ -693,7 +543,9 @@ class Phaser:
|
|||
if channel.get_dac_data() != data:
|
||||
raise ValueError("DAC test data readback failed")
|
||||
delay(.1*ms)
|
||||
self.dac_write(0x01, 0x8000) # iotest_ena
|
||||
cfg = self.dac_read(0x01)
|
||||
delay(.1*ms)
|
||||
self.dac_write(0x01, cfg | 0x8000) # iotest_ena
|
||||
self.dac_write(0x04, 0x0000) # clear iotest_result
|
||||
delay(.2*ms) # let it rip
|
||||
# no need to go through the alarm register,
|
||||
|
@ -706,7 +558,7 @@ class Phaser:
|
|||
delay(.1*ms) # slack
|
||||
else:
|
||||
errors = 0
|
||||
self.dac_write(0x01, 0x0000) # clear config
|
||||
self.dac_write(0x01, cfg) # clear config
|
||||
self.dac_write(0x04, 0x0000) # clear iotest_result
|
||||
return errors
|
||||
|
||||
|
@ -741,11 +593,12 @@ class PhaserChannel:
|
|||
or overflow after the interpolation. Either band-limit any changes
|
||||
in the oscillator parameters or back off the amplitude sufficiently.
|
||||
"""
|
||||
kernel_invariants = {"index", "phaser"}
|
||||
kernel_invariants = {"index", "phaser", "trf_mmap"}
|
||||
|
||||
def __init__(self, phaser, index):
|
||||
def __init__(self, phaser, index, trf):
|
||||
self.phaser = phaser
|
||||
self.index = index
|
||||
self.trf_mmap = TRF372017(trf).get_mmap()
|
||||
self.oscillator = [PhaserOscillator(self, osc) for osc in range(5)]
|
||||
|
||||
@kernel
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
class TRF372017:
|
||||
"""TRF372017 settings and register map.
|
||||
|
||||
For possible values, documentation, and explanation, see the datasheet.
|
||||
https://www.ti.com/lit/gpn/trf372017
|
||||
"""
|
||||
rdiv = 21 # 13b
|
||||
ref_inv = 0
|
||||
neg_vco = 1
|
||||
icp = 0 # 1.94 mA, 5b
|
||||
icp_double = 0
|
||||
cal_clk_sel = 12 # /16, 4b
|
||||
|
||||
ndiv = 420 # 16b
|
||||
pll_div_sel = 0b01 # /1, 2b
|
||||
prsc_sel = 1 # 8/9
|
||||
vco_sel = 2 # 2b
|
||||
vcosel_mode = 0
|
||||
cal_acc = 0b00 # 2b
|
||||
en_cal = 1
|
||||
|
||||
nfrac = 0 # 25b
|
||||
|
||||
pwd_pll = 0
|
||||
pwd_cp = 0
|
||||
pwd_vco = 0
|
||||
pwd_vcomux = 0
|
||||
pwd_div124 = 0
|
||||
pwd_presc = 0
|
||||
pwd_out_buff = 1
|
||||
pwd_lo_div = 1
|
||||
pwd_tx_div = 0
|
||||
pwd_bb_vcm = 0
|
||||
pwd_dc_off = 0
|
||||
en_extvco = 0
|
||||
en_isource = 0
|
||||
ld_ana_prec = 0 # 2b
|
||||
cp_tristate = 0 # 2b
|
||||
speedup = 0
|
||||
ld_dig_prec = 0
|
||||
en_dith = 1
|
||||
mod_ord = 2 # 3rd order, 2b
|
||||
dith_sel = 0
|
||||
del_sd_clk = 2 # 2b
|
||||
en_frac = 0
|
||||
|
||||
vcobias_rtrim = 4 # 3b
|
||||
pllbias_rtrim = 2 # 2b
|
||||
vco_bias = 8 # 460 µA, 4b
|
||||
vcobuf_bias = 2 # 2b
|
||||
vcomux_bias = 3 # 2b
|
||||
bufout_bias = 0 # 300 µA, 2b
|
||||
vco_cal_ib = 0 # PTAT
|
||||
vco_cal_ref = 2 # 1.04 V, 2b
|
||||
vco_ampl_ctrl = 3 # 2b
|
||||
vco_vb_ctrl = 0 # 1.2 V, 2b
|
||||
en_ld_isource = 0
|
||||
|
||||
ioff = 0x80 # 8b
|
||||
qoff = 0x80 # 8b
|
||||
vref_sel = 4 # 0.85 V, 3b
|
||||
tx_div_sel = 1 # div2, 2b
|
||||
lo_div_sel = 3 # div8, 2b
|
||||
tx_div_bias = 1 # 37.5 µA, 2b
|
||||
lo_div_bias = 2 # 50 µA, 2b
|
||||
|
||||
vco_trim = 0x20 # 6b
|
||||
vco_test_mode = 0
|
||||
cal_bypass = 0
|
||||
mux_ctrl = 1 # lock detect, 3b
|
||||
isource_sink = 0
|
||||
isource_trim = 4 # 3b
|
||||
pd_tc = 0 # 2b
|
||||
ib_vcm_sel = 0 # ptat
|
||||
dcoffset_i = 2 # 150 µA, 2b
|
||||
vco_bias_sel = 1 # spi
|
||||
|
||||
def __init__(self, updates=None):
|
||||
if updates is None:
|
||||
return
|
||||
for key, value in updates.items():
|
||||
if not hasattr(self, key):
|
||||
raise KeyError("invalid setting", key)
|
||||
setattr(self, key, value)
|
||||
|
||||
def get_mmap(self):
|
||||
mmap = []
|
||||
mmap.append(
|
||||
0x9 |
|
||||
(self.rdiv << 5) | (self.ref_inv << 19) | (self.neg_vco << 20) |
|
||||
(self.icp << 21) | (self.icp_double << 26) |
|
||||
(self.cal_clk_sel << 27))
|
||||
mmap.append(
|
||||
0xa |
|
||||
(self.ndiv << 5) | (self.pll_div_sel << 21) | (self.prsc_sel << 23) |
|
||||
(self.vco_sel << 26) | (self.vcosel_mode << 28) |
|
||||
(self.cal_acc << 29) | (self.en_cal << 31))
|
||||
mmap.append(0xb | (self.nfrac << 5))
|
||||
mmap.append(
|
||||
0xc |
|
||||
(self.pwd_pll << 5) | (self.pwd_cp << 6) | (self.pwd_vco << 7) |
|
||||
(self.pwd_vcomux << 8) | (self.pwd_div124 << 9) |
|
||||
(self.pwd_presc << 10) | (self.pwd_out_buff << 12) |
|
||||
(self.pwd_lo_div << 13) | (self.pwd_tx_div << 14) |
|
||||
(self.pwd_bb_vcm << 15) | (self.pwd_dc_off << 16) |
|
||||
(self.en_extvco << 17) | (self.en_isource << 18) |
|
||||
(self.ld_ana_prec << 19) | (self.cp_tristate << 21) |
|
||||
(self.speedup << 23) | (self.ld_dig_prec << 24) |
|
||||
(self.en_dith << 25) | (self.mod_ord << 27) |
|
||||
(self.dith_sel << 28) | (self.del_sd_clk << 29) |
|
||||
(self.en_frac << 31))
|
||||
mmap.append(
|
||||
0xd |
|
||||
(self.vcobias_rtrim << 5) | (self.pllbias_rtrim << 8) |
|
||||
(self.vco_bias << 10) | (self.vcobuf_bias << 14) |
|
||||
(self.vcomux_bias << 16) | (self.bufout_bias << 18) |
|
||||
(1 << 21) | (self.vco_cal_ib << 22) | (self.vco_cal_ref << 23) |
|
||||
(self.vco_ampl_ctrl << 26) | (self.vco_vb_ctrl << 28) |
|
||||
(self.en_ld_isource << 31))
|
||||
mmap.append(
|
||||
0xe |
|
||||
(self.ioff << 5) | (self.qoff << 13) | (self.vref_sel << 21) |
|
||||
(self.tx_div_sel << 24) | (self.lo_div_sel << 26) |
|
||||
(self.tx_div_bias << 28) | (self.lo_div_bias << 30))
|
||||
mmap.append(
|
||||
0xf |
|
||||
(self.vco_trim << 7) | (self.vco_test_mode << 14) |
|
||||
(self.cal_bypass << 15) | (self.mux_ctrl << 16) |
|
||||
(self.isource_sink << 19) | (self.isource_trim << 20) |
|
||||
(self.pd_tc << 23) | (self.ib_vcm_sel << 25) |
|
||||
(1 << 28) | (self.dcoffset_i << 29) |
|
||||
(self.vco_bias_sel << 31))
|
||||
return mmap
|
Loading…
Reference in New Issue