forked from M-Labs/artiq
phaser: rework rtio channels, sync_dly, init()
This commit is contained in:
parent
f3b0398720
commit
c18f515bf9
|
@ -21,12 +21,14 @@ PHASER_ADDR_SPI_SEL = 0x0c
|
||||||
PHASER_ADDR_SPI_DATW = 0x0d
|
PHASER_ADDR_SPI_DATW = 0x0d
|
||||||
PHASER_ADDR_SPI_DATR = 0x0e
|
PHASER_ADDR_SPI_DATR = 0x0e
|
||||||
PHASER_ADDR_SYNC_DLY = 0x0f
|
PHASER_ADDR_SYNC_DLY = 0x0f
|
||||||
|
|
||||||
PHASER_ADDR_DUC0_CFG = 0x10
|
PHASER_ADDR_DUC0_CFG = 0x10
|
||||||
# PHASER_ADDR_DUC0_RESERVED0 = 0x11
|
# PHASER_ADDR_DUC0_RESERVED0 = 0x11
|
||||||
PHASER_ADDR_DUC0_F = 0x12
|
PHASER_ADDR_DUC0_F = 0x12
|
||||||
PHASER_ADDR_DUC0_P = 0x16
|
PHASER_ADDR_DUC0_P = 0x16
|
||||||
PHASER_ADDR_DAC0_DATA = 0x18
|
PHASER_ADDR_DAC0_DATA = 0x18
|
||||||
PHASER_ADDR_DAC0_TEST = 0x1c
|
PHASER_ADDR_DAC0_TEST = 0x1c
|
||||||
|
|
||||||
PHASER_ADDR_DUC1_CFG = 0x20
|
PHASER_ADDR_DUC1_CFG = 0x20
|
||||||
# PHASER_ADDR_DUC1_RESERVED0 = 0x21
|
# PHASER_ADDR_DUC1_RESERVED0 = 0x21
|
||||||
PHASER_ADDR_DUC1_F = 0x22
|
PHASER_ADDR_DUC1_F = 0x22
|
||||||
|
@ -152,6 +154,7 @@ class Phaser:
|
||||||
self.set_leds(0x00)
|
self.set_leds(0x00)
|
||||||
self.set_fan_mu(0)
|
self.set_fan_mu(0)
|
||||||
self.set_cfg(clk_sel=clk_sel) # bring everything out of reset
|
self.set_cfg(clk_sel=clk_sel) # bring everything out of reset
|
||||||
|
self.set_sync_dly(4) # tune?
|
||||||
delay(.1*ms) # slack
|
delay(.1*ms) # slack
|
||||||
|
|
||||||
# 4 wire SPI, sif4_enable
|
# 4 wire SPI, sif4_enable
|
||||||
|
@ -175,7 +178,6 @@ class Phaser:
|
||||||
self.dac_write(0x03, 0x4000) # coarse dac 20.6 mA
|
self.dac_write(0x03, 0x4000) # coarse dac 20.6 mA
|
||||||
self.dac_write(0x07, 0x40c1) # alarm mask
|
self.dac_write(0x07, 0x40c1) # alarm mask
|
||||||
self.dac_write(0x09, 0x4000) # fifo_offset
|
self.dac_write(0x09, 0x4000) # fifo_offset
|
||||||
self.set_sync_dly(0)
|
|
||||||
self.dac_write(0x0d, 0x0000) # fmix, no cmix
|
self.dac_write(0x0d, 0x0000) # fmix, no cmix
|
||||||
self.dac_write(0x14, 0x5431) # fine nco ab
|
self.dac_write(0x14, 0x5431) # fine nco ab
|
||||||
self.dac_write(0x15, 0x0323) # coarse nco ab
|
self.dac_write(0x15, 0x0323) # coarse nco ab
|
||||||
|
@ -183,7 +185,7 @@ class Phaser:
|
||||||
self.dac_write(0x17, 0x0323) # coarse nco cd
|
self.dac_write(0x17, 0x0323) # coarse nco cd
|
||||||
self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync
|
self.dac_write(0x18, 0x2c60) # P=4, pll run, single cp, pll_ndivsync
|
||||||
self.dac_write(0x19, 0x8814) # M=16 N=2
|
self.dac_write(0x19, 0x8814) # M=16 N=2
|
||||||
self.dac_write(0x1a, 0xfc00) # pll_vco=63
|
self.dac_write(0x1a, 0xfc00) # pll_vco=63, 4 GHz
|
||||||
delay(.2*ms) # slack
|
delay(.2*ms) # slack
|
||||||
self.dac_write(0x1b, 0x0800) # int ref, fuse
|
self.dac_write(0x1b, 0x0800) # int ref, fuse
|
||||||
self.dac_write(0x1e, 0x9999) # qmc sync from sif and reg
|
self.dac_write(0x1e, 0x9999) # qmc sync from sif and reg
|
||||||
|
@ -192,19 +194,20 @@ class Phaser:
|
||||||
self.dac_write(0x22, 0x1be4) # reverse dacs for spectral inversion and layout
|
self.dac_write(0x22, 0x1be4) # reverse dacs for spectral inversion and layout
|
||||||
self.dac_write(0x24, 0x0000) # clk and data delays
|
self.dac_write(0x24, 0x0000) # clk and data delays
|
||||||
|
|
||||||
|
self.clear_dac_alarms()
|
||||||
delay(1*ms) # lock pll
|
delay(1*ms) # lock pll
|
||||||
lvolt = self.dac_read(0x18) & 7
|
lvolt = self.dac_read(0x18) & 7
|
||||||
delay(.1*ms)
|
delay(.1*ms)
|
||||||
if lvolt < 2 or lvolt > 5:
|
if lvolt < 2 or lvolt > 5:
|
||||||
raise ValueError("DAC PLL tuning voltage out of bounds")
|
raise ValueError("DAC PLL tuning voltage out of bounds")
|
||||||
# self.dac_write(0x20, 0x0000) # stop fifo sync
|
# self.dac_write(0x20, 0x0000) # stop fifo sync
|
||||||
self.dac_write(0x05, 0x0000) # clear alarms
|
# alarm = self.get_sta() & 1
|
||||||
delay(1*ms) # run it
|
# delay(.1*ms)
|
||||||
alarm = self.get_sta() & 1
|
alarm = self.get_dac_alarms()
|
||||||
delay(.1*ms)
|
if alarm & ~0x0040: # ignore PLL alarms (see DS)
|
||||||
if alarm:
|
print(alarm)
|
||||||
alarm = self.dac_read(0x05)
|
|
||||||
raise ValueError("DAC alarm")
|
raise ValueError("DAC alarm")
|
||||||
|
delay(.5*ms)
|
||||||
|
|
||||||
patterns = [
|
patterns = [
|
||||||
[0xffff, 0xffff, 0x0000, 0x0000], # test channel
|
[0xffff, 0xffff, 0x0000, 0x0000], # test channel
|
||||||
|
@ -213,11 +216,10 @@ class Phaser:
|
||||||
[0x7a7a, 0xb6b6, 0xeaea, 0x4545], # ds pattern a
|
[0x7a7a, 0xb6b6, 0xeaea, 0x4545], # ds pattern a
|
||||||
[0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # ds pattern b
|
[0x1a1a, 0x1616, 0xaaaa, 0xc6c6], # ds pattern b
|
||||||
]
|
]
|
||||||
delay(.5*ms)
|
# A data delay of 2*50 ps heuristically matches FPGA+board+DAC skews.
|
||||||
# A data delay of 3*50 ps heuristically matches FPGA+board+DAC skews.
|
|
||||||
# There is plenty of margin and no need to tune at runtime.
|
# There is plenty of margin and no need to tune at runtime.
|
||||||
# Parity provides another level of safety.
|
# Parity provides another level of safety.
|
||||||
for dly in [-3]: # range(-7, 8)
|
for dly in [-2]: # range(-7, 8)
|
||||||
if dly < 0:
|
if dly < 0:
|
||||||
dly = -dly << 3 # data delay, else clock delay
|
dly = -dly << 3 # data delay, else clock delay
|
||||||
self.dac_write(0x24, dly << 10)
|
self.dac_write(0x24, dly << 10)
|
||||||
|
@ -226,6 +228,7 @@ class Phaser:
|
||||||
if errors:
|
if errors:
|
||||||
raise ValueError("iotest error")
|
raise ValueError("iotest error")
|
||||||
delay(.5*ms)
|
delay(.5*ms)
|
||||||
|
self.clear_dac_alarms()
|
||||||
|
|
||||||
hw_rev = self.read8(PHASER_ADDR_HW_REV)
|
hw_rev = self.read8(PHASER_ADDR_HW_REV)
|
||||||
has_upconverter = hw_rev & PHASER_HW_REV_VARIANT
|
has_upconverter = hw_rev & PHASER_HW_REV_VARIANT
|
||||||
|
@ -362,6 +365,16 @@ class Phaser:
|
||||||
"""
|
"""
|
||||||
return self.read8(PHASER_ADDR_CRC_ERR)
|
return self.read8(PHASER_ADDR_CRC_ERR)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set_sync_dly(self, dly):
|
||||||
|
"""Set SYNC delay.
|
||||||
|
|
||||||
|
:param dly: DAC SYNC delay setting (0 to 7)
|
||||||
|
"""
|
||||||
|
if dly < 0 or dly > 7:
|
||||||
|
raise ValueError("SYNC delay out of bounds")
|
||||||
|
self.write8(PHASER_ADDR_SYNC_DLY, dly)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def duc_stb(self):
|
def duc_stb(self):
|
||||||
"""Strobe the DUC configuration register update.
|
"""Strobe the DUC configuration register update.
|
||||||
|
@ -456,6 +469,19 @@ class Phaser:
|
||||||
"""
|
"""
|
||||||
return self.dac_read(0x06, div=257) >> 8
|
return self.dac_read(0x06, div=257) >> 8
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def get_dac_alarms(self):
|
||||||
|
"""Read the DAC alarm flags.
|
||||||
|
|
||||||
|
:return: DAC alarm flags (see datasheet for bit meaning)
|
||||||
|
"""
|
||||||
|
return self.dac_read(0x05)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def clear_dac_alarms(self):
|
||||||
|
"""Clear DAC alarm flags."""
|
||||||
|
self.dac_write(0x05, 0x0000)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def dac_iotest(self, pattern) -> TInt32:
|
def dac_iotest(self, pattern) -> TInt32:
|
||||||
"""Performs a DAC IO test according to the datasheet.
|
"""Performs a DAC IO test according to the datasheet.
|
||||||
|
@ -479,7 +505,7 @@ class Phaser:
|
||||||
delay(.2*ms) # let it rip
|
delay(.2*ms) # let it rip
|
||||||
# no need to go through the alarm register,
|
# no need to go through the alarm register,
|
||||||
# just read the error mask
|
# just read the error mask
|
||||||
# self.dac_write(0x05, 0x0000) # clear alarms
|
# self.clear_dac_alarms()
|
||||||
# alarm = self.dac_read(0x05)
|
# alarm = self.dac_read(0x05)
|
||||||
# delay(.1*ms) # slack
|
# delay(.1*ms) # slack
|
||||||
# if alarm & 0x0080: # alarm_from_iotest
|
# if alarm & 0x0080: # alarm_from_iotest
|
||||||
|
@ -489,16 +515,6 @@ class Phaser:
|
||||||
self.dac_write(0x04, 0x0000) # clear iotest_result
|
self.dac_write(0x04, 0x0000) # clear iotest_result
|
||||||
return errors
|
return errors
|
||||||
|
|
||||||
@kernel
|
|
||||||
def set_sync_dly(self, dly):
|
|
||||||
"""Set SYNC delay.
|
|
||||||
|
|
||||||
:param dly: DAC SYNC delay setting (0 to 7)
|
|
||||||
"""
|
|
||||||
if dly < 0 or dly > 7:
|
|
||||||
raise ValueError("SYNC delay out of bounds")
|
|
||||||
self.write8(PHASER_ADDR_SYNC_DLY, dly)
|
|
||||||
|
|
||||||
|
|
||||||
class PhaserChannel:
|
class PhaserChannel:
|
||||||
"""Phaser channel IQ pair.
|
"""Phaser channel IQ pair.
|
||||||
|
@ -702,7 +718,7 @@ class PhaserOscillator:
|
||||||
def __init__(self, channel, index):
|
def __init__(self, channel, index):
|
||||||
self.channel = channel
|
self.channel = channel
|
||||||
self.base_addr = ((self.channel.phaser.channel_base + 1 +
|
self.base_addr = ((self.channel.phaser.channel_base + 1 +
|
||||||
self.channel.index) << 8) | (index << 1)
|
2*self.channel.index) << 8) | index
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_frequency_mu(self, ftw):
|
def set_frequency_mu(self, ftw):
|
||||||
|
@ -731,7 +747,7 @@ class PhaserOscillator:
|
||||||
:param clr: Clear the phase accumulator (persistent)
|
:param clr: Clear the phase accumulator (persistent)
|
||||||
"""
|
"""
|
||||||
data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16)
|
data = (asf & 0x7fff) | ((clr & 1) << 15) | (pow << 16)
|
||||||
rtio_output(self.base_addr | 1, data)
|
rtio_output(self.base_addr | (1 << 8), data)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set_amplitude_phase(self, amplitude, phase=0., clr=0):
|
def set_amplitude_phase(self, amplitude, phase=0., clr=0):
|
||||||
|
|
|
@ -652,6 +652,8 @@ class Phaser(_EEM):
|
||||||
target.submodules += phy
|
target.submodules += phy
|
||||||
target.rtio_channels.extend([
|
target.rtio_channels.extend([
|
||||||
rtio.Channel.from_phy(phy, ififo_depth=4),
|
rtio.Channel.from_phy(phy, ififo_depth=4),
|
||||||
rtio.Channel.from_phy(phy.ch0),
|
rtio.Channel.from_phy(phy.ch0.frequency),
|
||||||
rtio.Channel.from_phy(phy.ch1),
|
rtio.Channel.from_phy(phy.ch0.phase_amplitude),
|
||||||
|
rtio.Channel.from_phy(phy.ch1.frequency),
|
||||||
|
rtio.Channel.from_phy(phy.ch1.phase_amplitude),
|
||||||
])
|
])
|
||||||
|
|
|
@ -5,24 +5,28 @@ from artiq.gateware.rtio import rtlink
|
||||||
from .fastlink import SerDes, SerInterface
|
from .fastlink import SerDes, SerInterface
|
||||||
|
|
||||||
|
|
||||||
class DDSChannel(Module):
|
class Phy(Module):
|
||||||
def __init__(self, share_lut=None):
|
def __init__(self, regs):
|
||||||
self.rtlink = rtlink.Interface(
|
self.rtlink = rtlink.Interface(
|
||||||
rtlink.OInterface(data_width=32, address_width=4,
|
rtlink.OInterface(data_width=32, address_width=4,
|
||||||
enable_replace=True))
|
enable_replace=True))
|
||||||
to_rio_phy = ClockDomainsRenamer("rio_phy")
|
self.sync.rtio += [
|
||||||
self.submodules.dds = to_rio_phy(MultiDDS(
|
|
||||||
n=5, fwidth=32, xwidth=16, z=19, zl=10, share_lut=share_lut))
|
|
||||||
regs = []
|
|
||||||
for i in self.dds.i:
|
|
||||||
regs.extend([i.f, Cat(i.a, i.clr, i.p)])
|
|
||||||
self.sync.rio_phy += [
|
|
||||||
If(self.rtlink.o.stb,
|
If(self.rtlink.o.stb,
|
||||||
Array(regs)[self.rtlink.o.address].eq(self.rtlink.o.data)
|
Array(regs)[self.rtlink.o.address].eq(self.rtlink.o.data)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class DDSChannel(Module):
|
||||||
|
def __init__(self, share_lut=None):
|
||||||
|
to_rio_phy = ClockDomainsRenamer("rio_phy")
|
||||||
|
self.submodules.dds = to_rio_phy(MultiDDS(
|
||||||
|
n=5, fwidth=32, xwidth=16, z=19, zl=10, share_lut=share_lut))
|
||||||
|
self.submodules.frequency = Phy([i.f for i in self.dds.i])
|
||||||
|
self.submodules.phase_amplitude = Phy(
|
||||||
|
[Cat(i.a, i.clr, i.p) for i in self.dds.i])
|
||||||
|
|
||||||
|
|
||||||
class Phaser(Module):
|
class Phaser(Module):
|
||||||
def __init__(self, pins, pins_n):
|
def __init__(self, pins, pins_n):
|
||||||
self.rtlink = rtlink.Interface(
|
self.rtlink = rtlink.Interface(
|
||||||
|
|
Loading…
Reference in New Issue