mirror of https://github.com/m-labs/artiq.git
Merge branch 'master' into new
This commit is contained in:
commit
1b841805f6
|
@ -26,22 +26,22 @@ _AD9910_REG_CFR1 = 0x00
|
|||
_AD9910_REG_CFR2 = 0x01
|
||||
_AD9910_REG_CFR3 = 0x02
|
||||
_AD9910_REG_AUX_DAC = 0x03
|
||||
_AD9910_REG_IO_UPD = 0x04
|
||||
_AD9910_REG_IO_UPDATE = 0x04
|
||||
_AD9910_REG_FTW = 0x07
|
||||
_AD9910_REG_POW = 0x08
|
||||
_AD9910_REG_ASF = 0x09
|
||||
_AD9910_REG_MSYNC = 0x0A
|
||||
_AD9910_REG_DRAMPL = 0x0B
|
||||
_AD9910_REG_DRAMPS = 0x0C
|
||||
_AD9910_REG_DRAMPR = 0x0D
|
||||
_AD9910_REG_PR0 = 0x0E
|
||||
_AD9910_REG_PR1 = 0x0F
|
||||
_AD9910_REG_PR2 = 0x10
|
||||
_AD9910_REG_PR3 = 0x11
|
||||
_AD9910_REG_PR4 = 0x12
|
||||
_AD9910_REG_PR5 = 0x13
|
||||
_AD9910_REG_PR6 = 0x14
|
||||
_AD9910_REG_PR7 = 0x15
|
||||
_AD9910_REG_SYNC = 0x0a
|
||||
_AD9910_REG_RAMP_LIMIT = 0x0b
|
||||
_AD9910_REG_RAMP_STEP = 0x0c
|
||||
_AD9910_REG_RAMP_RATE = 0x0d
|
||||
_AD9910_REG_PROFILE0 = 0x0e
|
||||
_AD9910_REG_PROFILE1 = 0x0f
|
||||
_AD9910_REG_PROFILE2 = 0x10
|
||||
_AD9910_REG_PROFILE3 = 0x11
|
||||
_AD9910_REG_PROFILE4 = 0x12
|
||||
_AD9910_REG_PROFILE5 = 0x13
|
||||
_AD9910_REG_PROFILE6 = 0x14
|
||||
_AD9910_REG_PROFILE7 = 0x15
|
||||
_AD9910_REG_RAM = 0x16
|
||||
|
||||
|
||||
|
@ -256,7 +256,7 @@ class AD9910:
|
|||
|
||||
@kernel
|
||||
def set_mu(self, ftw, pow=0, asf=0x3fff, phase_mode=_PHASE_MODE_DEFAULT,
|
||||
ref_time=-1):
|
||||
ref_time=-1, profile=0):
|
||||
"""Set profile 0 data in machine units.
|
||||
|
||||
This uses machine units (FTW, POW, ASF). The frequency tuning word
|
||||
|
@ -276,6 +276,7 @@ class AD9910:
|
|||
by :meth:`set_phase_mode` for this call.
|
||||
:param ref_time: Fiducial time used to compute absolute or tracking
|
||||
phase updates. In machine units as obtained by `now_mu()`.
|
||||
:param profile: Profile number to set (0-7, default: 0).
|
||||
:return: Resulting phase offset word after application of phase
|
||||
tracking offset. When using :const:`PHASE_MODE_CONTINUOUS` in
|
||||
subsequent calls, use this value as the "current" phase.
|
||||
|
@ -297,7 +298,7 @@ class AD9910:
|
|||
# is equivalent to an output pipeline latency.
|
||||
dt = int32(now_mu()) - int32(ref_time)
|
||||
pow += dt*ftw*self.sysclk_per_mu >> 16
|
||||
self.write64(_AD9910_REG_PR0, (asf << 16) | pow, ftw)
|
||||
self.write64(_AD9910_REG_PROFILE0 + profile, (asf << 16) | pow, ftw)
|
||||
delay_mu(int64(self.io_update_delay))
|
||||
self.cpld.io_update.pulse_mu(8) # assumes 8 mu > t_SYSCLK
|
||||
at_mu(now_mu() & ~0xf)
|
||||
|
@ -332,7 +333,7 @@ class AD9910:
|
|||
|
||||
@kernel
|
||||
def set(self, frequency, phase=0.0, amplitude=1.0,
|
||||
phase_mode=_PHASE_MODE_DEFAULT, ref_time=-1):
|
||||
phase_mode=_PHASE_MODE_DEFAULT, ref_time=-1, profile=0):
|
||||
"""Set profile 0 data in SI units.
|
||||
|
||||
.. seealso:: :meth:`set_mu`
|
||||
|
@ -342,11 +343,12 @@ class AD9910:
|
|||
:param asf: Amplitude in units of full scale
|
||||
:param phase_mode: Phase mode constant
|
||||
:param ref_time: Fiducial time stamp in machine units
|
||||
:param profile: Profile to affect
|
||||
:return: Resulting phase offset in turns
|
||||
"""
|
||||
return self.pow_to_turns(self.set_mu(
|
||||
self.frequency_to_ftw(frequency), self.turns_to_pow(phase),
|
||||
self.amplitude_to_asf(amplitude), phase_mode, ref_time))
|
||||
self.amplitude_to_asf(amplitude), phase_mode, ref_time, profile))
|
||||
|
||||
@kernel
|
||||
def set_att_mu(self, att):
|
||||
|
@ -389,7 +391,7 @@ class AD9910:
|
|||
:param window: Symmetric SYNC_IN validation window (0-15) in
|
||||
steps of ~75ps for both hold and setup margin.
|
||||
"""
|
||||
self.write32(_AD9910_REG_MSYNC,
|
||||
self.write32(_AD9910_REG_SYNC,
|
||||
(window << 28) | # SYNC S/H validation delay
|
||||
(1 << 27) | # SYNC receiver enable
|
||||
(0 << 26) | # SYNC generator disable
|
||||
|
@ -466,17 +468,18 @@ class AD9910:
|
|||
raise ValueError("no valid window/delay")
|
||||
|
||||
@kernel
|
||||
def measure_io_update_alignment(self, io_up_delay):
|
||||
def measure_io_update_alignment(self, delay_start, delay_stop):
|
||||
"""Use the digital ramp generator to locate the alignment between
|
||||
IO_UPDATE and SYNC_CLK.
|
||||
|
||||
The ramp generator is set up to a linear frequency ramp
|
||||
(dFTW/t_SYNC_CLK=1) and started at a RTIO time stamp.
|
||||
(dFTW/t_SYNC_CLK=1) and started at a coarse RTIO time stamp plus
|
||||
`delay_start` and stopped at a coarse RTIO time stamp plus
|
||||
`delay_stop`.
|
||||
|
||||
After scanning the alignment, an IO_UPDATE delay midway between two
|
||||
edges should be chosen.
|
||||
|
||||
:return: odd/even SYNC_CLK cycle indicator
|
||||
:param delay_start: Start IO_UPDATE delay in machine units.
|
||||
:param delay_stop: Stop IO_UPDATE delay in machine units.
|
||||
:return: Odd/even SYNC_CLK cycle indicator.
|
||||
"""
|
||||
# set up DRG
|
||||
# DRG ACC autoclear and LRR on io update
|
||||
|
@ -484,19 +487,21 @@ class AD9910:
|
|||
# DRG -> FTW, DRG enable
|
||||
self.write32(_AD9910_REG_CFR2, 0x01090000)
|
||||
# no limits
|
||||
self.write64(_AD9910_REG_DRAMPL, -1, 0)
|
||||
self.write64(_AD9910_REG_RAMP_LIMIT, -1, 0)
|
||||
# DRCTL=0, dt=1 t_SYNC_CLK
|
||||
self.write32(_AD9910_REG_DRAMPR, 0x00010000)
|
||||
self.write32(_AD9910_REG_RAMP_RATE, 0x00010000)
|
||||
# dFTW = 1, (work around negative slope)
|
||||
self.write64(_AD9910_REG_DRAMPS, -1, 0)
|
||||
at_mu(now_mu() + 0x10 & ~0xf) # align to RTIO/2
|
||||
self.cpld.io_update.pulse_mu(8)
|
||||
self.write64(_AD9910_REG_RAMP_STEP, -1, 0)
|
||||
# delay io_update after RTIO/2 edge
|
||||
t = now_mu() + 0x10 & ~0xf
|
||||
at_mu(t + delay_start)
|
||||
self.cpld.io_update.pulse_mu(32 - delay_start) # realign
|
||||
# disable DRG autoclear and LRR on io_update
|
||||
self.write32(_AD9910_REG_CFR1, 0x00000002)
|
||||
# stop DRG
|
||||
self.write64(_AD9910_REG_DRAMPS, 0, 0)
|
||||
at_mu((now_mu() + 0x10 & ~0xf) + io_up_delay) # delay
|
||||
self.cpld.io_update.pulse_mu(32 - io_up_delay) # realign
|
||||
self.write64(_AD9910_REG_RAMP_STEP, 0, 0)
|
||||
at_mu(t + 0x1000 + delay_stop)
|
||||
self.cpld.io_update.pulse_mu(32 - delay_stop) # realign
|
||||
ftw = self.read32(_AD9910_REG_FTW) # read out effective FTW
|
||||
delay(100*us) # slack
|
||||
# disable DRG
|
||||
|
@ -510,22 +515,35 @@ class AD9910:
|
|||
|
||||
Scan through increasing IO_UPDATE delays until a delay is found that
|
||||
lets IO_UPDATE be registered in the next SYNC_CLK cycle. Return a
|
||||
IO_UPDATE delay that is midway between two such SYNC_CLK transitions.
|
||||
IO_UPDATE delay that is as far away from that SYNC_CLK edge
|
||||
as possible.
|
||||
|
||||
This method assumes that the IO_UPDATE TTLOut device has one machine
|
||||
unit resolution (SERDES) and that the ratio between fine RTIO frequency
|
||||
(RTIO time machine units) and SYNC_CLK is 4.
|
||||
unit resolution (SERDES).
|
||||
|
||||
:return: Stable IO_UPDATE delay to be passed to the constructor
|
||||
:class:`AD9910` via the device database.
|
||||
"""
|
||||
period = 4 # f_RTIO/f_SYNC = 4
|
||||
max_delay = 8 # mu, 1 ns
|
||||
d0 = self.io_update_delay
|
||||
t0 = int32(self.measure_io_update_alignment(d0))
|
||||
for i in range(max_delay - 1):
|
||||
t = self.measure_io_update_alignment(
|
||||
(d0 + i + 1) & (max_delay - 1))
|
||||
if t != t0:
|
||||
return (d0 + i + period//2) & (period - 1)
|
||||
period = self.sysclk_per_mu * 4 # SYNC_CLK period
|
||||
repeat = 100
|
||||
for i in range(period):
|
||||
t = 0
|
||||
# check whether the sync edge is strictly between i, i+2
|
||||
for j in range(repeat):
|
||||
t += self.measure_io_update_alignment(i, i + 2)
|
||||
if t != 0: # no certain edge
|
||||
continue
|
||||
# check left/right half: i,i+1 and i+1,i+2
|
||||
t1 = [0, 0]
|
||||
for j in range(repeat):
|
||||
t1[0] += self.measure_io_update_alignment(i, i + 1)
|
||||
t1[1] += self.measure_io_update_alignment(i + 1, i + 2)
|
||||
if ((t1[0] == 0 and t1[1] == 0) or
|
||||
(t1[0] == repeat and t1[1] == repeat)):
|
||||
# edge is not close to i + 1, can't interpret result
|
||||
raise ValueError(
|
||||
"no clear IO_UPDATE-SYNC_CLK alignment edge found")
|
||||
else:
|
||||
# the good delay is period//2 after the edge
|
||||
return (i + 1 + period//2) & (period - 1)
|
||||
raise ValueError("no IO_UPDATE-SYNC_CLK alignment edge found")
|
||||
|
|
|
@ -14,7 +14,8 @@ SPI_CONFIG = (0*spi.SPI_OFFLINE | 0*spi.SPI_END |
|
|||
# SPI clock write and read dividers
|
||||
SPIT_CFG_WR = 2
|
||||
SPIT_CFG_RD = 16
|
||||
SPIT_ATT_WR = 2
|
||||
# 30 MHz fmax, 20 ns setup, 40 ns shift to latch (limiting)
|
||||
SPIT_ATT_WR = 6
|
||||
SPIT_ATT_RD = 16
|
||||
SPIT_DDS_WR = 2
|
||||
SPIT_DDS_RD = 16
|
||||
|
@ -174,7 +175,7 @@ class CPLD:
|
|||
self.cfg_reg = urukul_cfg(rf_sw=rf_sw, led=0, profile=0,
|
||||
io_update=0, mask_nu=0, clk_sel=clk_sel,
|
||||
sync_sel=sync_sel, rst=0, io_rst=0)
|
||||
self.att_reg = att
|
||||
self.att_reg = int32(att)
|
||||
self.sync_div = sync_div
|
||||
|
||||
@kernel
|
||||
|
@ -299,7 +300,8 @@ class CPLD:
|
|||
|
||||
:param channel: Attenuator channel (0-3).
|
||||
:param att: Attenuation setting in dB. Higher value is more
|
||||
attenuation.
|
||||
attenuation. Minimum attenuation is 0*dB, maximum attenuation is
|
||||
31.5*dB.
|
||||
"""
|
||||
self.set_att_mu(channel, 255 - int32(round(att*8)))
|
||||
|
||||
|
@ -333,3 +335,15 @@ class CPLD:
|
|||
ftw = ftw_max//div
|
||||
assert ftw*div == ftw_max
|
||||
self.sync.set_mu(ftw)
|
||||
|
||||
@kernel
|
||||
def set_profile(self, profile):
|
||||
"""Set the PROFILE pins.
|
||||
|
||||
The PROFILE pins are common to all four DDS channels.
|
||||
|
||||
:param profile: PROFILE pins in numeric representation (0-7).
|
||||
"""
|
||||
cfg = self.cfg_reg & ~(7 << CFG_PROFILE)
|
||||
cfg |= (profile & 7) << CFG_PROFILE
|
||||
self.cfg_write(cfg)
|
||||
|
|
|
@ -242,6 +242,12 @@ mod ddr {
|
|||
ddrphy::dly_sel_write(1 << (DQS_SIGNAL_COUNT - n - 1));
|
||||
|
||||
ddrphy::rdly_dq_rst_write(1);
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
{
|
||||
for _ in 0..3 {
|
||||
ddrphy::rdly_dq_bitslip_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..DDRPHY_MAX_DELAY {
|
||||
let mut working = true;
|
||||
|
@ -327,6 +333,12 @@ mod ddr {
|
|||
let mut max_seen_valid = 0;
|
||||
|
||||
ddrphy::rdly_dq_rst_write(1);
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
{
|
||||
for _ in 0..3 {
|
||||
ddrphy::rdly_dq_bitslip_write(1);
|
||||
}
|
||||
}
|
||||
|
||||
for delay in 0..DDRPHY_MAX_DELAY {
|
||||
let mut valid = true;
|
||||
|
@ -384,6 +396,12 @@ mod ddr {
|
|||
|
||||
// Set delay to the middle
|
||||
ddrphy::rdly_dq_rst_write(1);
|
||||
#[cfg(soc_platform = "kasli")]
|
||||
{
|
||||
for _ in 0..3 {
|
||||
ddrphy::rdly_dq_bitslip_write(1);
|
||||
}
|
||||
}
|
||||
for _ in 0..mean_delay {
|
||||
ddrphy::rdly_dq_inc_write(1);
|
||||
}
|
||||
|
|
|
@ -541,7 +541,7 @@ class SUServo(_EEM):
|
|||
target.submodules += phy
|
||||
target.rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||
|
||||
pads = target.platform.request("{}_dds_reset".format(eem_urukul1))
|
||||
pads = target.platform.request("{}_dds_reset_sync_in".format(eem_urukul1))
|
||||
target.specials += DifferentialOutput(0, pads.p, pads.n)
|
||||
|
||||
for i, signal in enumerate("sw0 sw1 sw2 sw3".split()):
|
||||
|
|
|
@ -275,6 +275,78 @@ class _RangeScan(LayoutWidget):
|
|||
randomize.setChecked(state["randomize"])
|
||||
|
||||
|
||||
class _CenterScan(LayoutWidget):
|
||||
def __init__(self, procdesc, state):
|
||||
LayoutWidget.__init__(self)
|
||||
|
||||
scale = procdesc["scale"]
|
||||
|
||||
def apply_properties(widget):
|
||||
widget.setDecimals(procdesc["ndecimals"])
|
||||
if procdesc["global_min"] is not None:
|
||||
widget.setMinimum(procdesc["global_min"]/scale)
|
||||
else:
|
||||
widget.setMinimum(float("-inf"))
|
||||
if procdesc["global_max"] is not None:
|
||||
widget.setMaximum(procdesc["global_max"]/scale)
|
||||
else:
|
||||
widget.setMaximum(float("inf"))
|
||||
if procdesc["global_step"] is not None:
|
||||
widget.setSingleStep(procdesc["global_step"]/scale)
|
||||
if procdesc["unit"]:
|
||||
widget.setSuffix(" " + procdesc["unit"])
|
||||
|
||||
center = ScientificSpinBox()
|
||||
disable_scroll_wheel(center)
|
||||
apply_properties(center)
|
||||
center.setPrecision()
|
||||
center.setRelativeStep()
|
||||
center.setValue(state["center"])
|
||||
self.addWidget(center, 0, 1)
|
||||
self.addWidget(QtWidgets.QLabel("Center:"), 0, 0)
|
||||
|
||||
span = ScientificSpinBox()
|
||||
disable_scroll_wheel(span)
|
||||
apply_properties(span)
|
||||
span.setPrecision()
|
||||
span.setRelativeStep()
|
||||
span.setMinimum(0)
|
||||
span.setValue(state["span"])
|
||||
self.addWidget(span, 1, 1)
|
||||
self.addWidget(QtWidgets.QLabel("Span:"), 1, 0)
|
||||
|
||||
step = ScientificSpinBox()
|
||||
disable_scroll_wheel(step)
|
||||
apply_properties(step)
|
||||
step.setPrecision()
|
||||
step.setRelativeStep()
|
||||
step.setMinimum(0)
|
||||
step.setValue(state["step"])
|
||||
self.addWidget(step, 2, 1)
|
||||
self.addWidget(QtWidgets.QLabel("Step:"), 2, 0)
|
||||
|
||||
randomize = QtWidgets.QCheckBox("Randomize")
|
||||
self.addWidget(randomize, 3, 1)
|
||||
randomize.setChecked(state["randomize"])
|
||||
|
||||
def update_center(value):
|
||||
state["center"] = value*scale
|
||||
|
||||
def update_span(value):
|
||||
state["span"] = value*scale
|
||||
|
||||
def update_step(value):
|
||||
state["step"] = value*scale
|
||||
|
||||
def update_randomize(value):
|
||||
state["randomize"] = value
|
||||
|
||||
center.valueChanged.connect(update_center)
|
||||
span.valueChanged.connect(update_span)
|
||||
step.valueChanged.connect(update_step)
|
||||
randomize.stateChanged.connect(update_randomize)
|
||||
|
||||
|
||||
class _ExplicitScan(LayoutWidget):
|
||||
def __init__(self, state):
|
||||
LayoutWidget.__init__(self)
|
||||
|
@ -307,6 +379,7 @@ class ScanEntry(LayoutWidget):
|
|||
self.widgets = OrderedDict()
|
||||
self.widgets["NoScan"] = _NoScan(procdesc, state["NoScan"])
|
||||
self.widgets["RangeScan"] = _RangeScan(procdesc, state["RangeScan"])
|
||||
self.widgets["CenterScan"] = _CenterScan(procdesc, state["CenterScan"])
|
||||
self.widgets["ExplicitScan"] = _ExplicitScan(state["ExplicitScan"])
|
||||
for widget in self.widgets.values():
|
||||
self.stack.addWidget(widget)
|
||||
|
@ -314,6 +387,7 @@ class ScanEntry(LayoutWidget):
|
|||
self.radiobuttons = OrderedDict()
|
||||
self.radiobuttons["NoScan"] = QtWidgets.QRadioButton("No scan")
|
||||
self.radiobuttons["RangeScan"] = QtWidgets.QRadioButton("Range")
|
||||
self.radiobuttons["CenterScan"] = QtWidgets.QRadioButton("Center")
|
||||
self.radiobuttons["ExplicitScan"] = QtWidgets.QRadioButton("Explicit")
|
||||
scan_type = QtWidgets.QButtonGroup()
|
||||
for n, b in enumerate(self.radiobuttons.values()):
|
||||
|
@ -343,6 +417,8 @@ class ScanEntry(LayoutWidget):
|
|||
"NoScan": {"value": 0.0, "repetitions": 1},
|
||||
"RangeScan": {"start": 0.0, "stop": 100.0*scale, "npoints": 10,
|
||||
"randomize": False},
|
||||
"CenterScan": {"center": 0.*scale, "span": 100.*scale,
|
||||
"step": 10.*scale, "randomize": False},
|
||||
"ExplicitScan": {"sequence": []}
|
||||
}
|
||||
if "default" in procdesc:
|
||||
|
@ -361,6 +437,9 @@ class ScanEntry(LayoutWidget):
|
|||
state[ty]["npoints"] = default["npoints"]
|
||||
state[ty]["randomize"] = default["randomize"]
|
||||
state[ty]["seed"] = default["seed"]
|
||||
elif ty == "CenterScan":
|
||||
for key in "center span step randomize seed".split():
|
||||
state[ty][key] = default[key]
|
||||
elif ty == "ExplicitScan":
|
||||
state[ty]["sequence"] = default["sequence"]
|
||||
else:
|
||||
|
|
|
@ -27,7 +27,7 @@ from artiq.language import units
|
|||
|
||||
|
||||
__all__ = ["ScanObject",
|
||||
"NoScan", "RangeScan", "ExplicitScan",
|
||||
"NoScan", "RangeScan", "CenterScan", "ExplicitScan",
|
||||
"Scannable", "MultiScanManager"]
|
||||
|
||||
|
||||
|
@ -93,6 +93,43 @@ class RangeScan(ScanObject):
|
|||
"seed": self.seed}
|
||||
|
||||
|
||||
class CenterScan(ScanObject):
|
||||
"""A scan object that yields evenly spaced values within a span around a
|
||||
center. If ``step`` is finite, then ``center`` is always included.
|
||||
Values outside ``span`` around center are never included.
|
||||
If ``randomize`` is True the points are randomly ordered."""
|
||||
def __init__(self, center, span, step, randomize=False, seed=None):
|
||||
self.center = center
|
||||
self.span = span
|
||||
self.step = step
|
||||
self.randomize = randomize
|
||||
self.seed = seed
|
||||
|
||||
if step == 0.:
|
||||
self.sequence = []
|
||||
else:
|
||||
n = 1 + int(span/(2.*step))
|
||||
self.sequence = [center + sign*i*step
|
||||
for i in range(n) for sign in [-1, 1]][1:]
|
||||
|
||||
if randomize:
|
||||
rng = random.Random(seed)
|
||||
random.shuffle(self.sequence, rng.random)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.sequence)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.sequence)
|
||||
|
||||
def describe(self):
|
||||
return {"ty": "CenterScan",
|
||||
"center": self.center, "step": self.step,
|
||||
"span": self.span,
|
||||
"randomize": self.randomize,
|
||||
"seed": self.seed}
|
||||
|
||||
|
||||
class ExplicitScan(ScanObject):
|
||||
"""A scan object that yields values from an explicitly defined sequence."""
|
||||
def __init__(self, sequence):
|
||||
|
@ -111,6 +148,7 @@ class ExplicitScan(ScanObject):
|
|||
_ty_to_scan = {
|
||||
"NoScan": NoScan,
|
||||
"RangeScan": RangeScan,
|
||||
"CenterScan": CenterScan,
|
||||
"ExplicitScan": ExplicitScan
|
||||
}
|
||||
|
||||
|
|
|
@ -104,18 +104,21 @@ class AD9910Exp(EnvExperiment):
|
|||
self.core.break_realtime()
|
||||
self.dev.cpld.init()
|
||||
self.dev.init()
|
||||
bins = [0]*8
|
||||
self.scan_io_delay(bins)
|
||||
self.set_dataset("bins", bins)
|
||||
self.set_dataset("dly", self.dev.io_update_delay)
|
||||
bins1 = [0]*4
|
||||
bins2 = [0]*4
|
||||
self.scan_io_delay(bins1, bins2)
|
||||
self.set_dataset("bins1", bins1)
|
||||
self.set_dataset("bins2", bins2)
|
||||
self.set_dataset("dly", self.dev.tune_io_update_delay())
|
||||
|
||||
@kernel
|
||||
def scan_io_delay(self, bins):
|
||||
def scan_io_delay(self, bins1, bins2):
|
||||
delay(100*us)
|
||||
n = 100
|
||||
for i in range(n):
|
||||
for phase in range(len(bins)):
|
||||
bins[phase] += self.dev.measure_io_update_alignment(phase)
|
||||
for j in range(len(bins1)):
|
||||
bins1[j] += self.dev.measure_io_update_alignment(j, j + 1)
|
||||
bins2[j] += self.dev.measure_io_update_alignment(j, j + 2)
|
||||
delay(10*ms)
|
||||
|
||||
@kernel
|
||||
|
@ -131,6 +134,24 @@ class AD9910Exp(EnvExperiment):
|
|||
sw_off = (self.dev.cpld.sta_read() >> (self.dev.chip_select - 4)) & 1
|
||||
self.set_dataset("sw", (sw_on, sw_off))
|
||||
|
||||
@kernel
|
||||
def profile_readback(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.cpld.init()
|
||||
self.dev.init()
|
||||
for i in range(8):
|
||||
self.dev.set_mu(ftw=i, profile=i)
|
||||
ftw = [0] * 8
|
||||
for i in range(8):
|
||||
self.dev.cpld.set_profile(i)
|
||||
# If PROFILE is not alligned to SYNC_CLK a multi-bit change
|
||||
# doesn't transfer cleanly. Use IO_UPDATE to load the profile
|
||||
# again.
|
||||
self.dev.cpld.io_update.pulse_mu(8)
|
||||
ftw[i] = self.dev.read32(_AD9910_REG_FTW)
|
||||
delay(100*us)
|
||||
self.set_dataset("ftw", ftw)
|
||||
|
||||
|
||||
class AD9910Test(ExperimentCase):
|
||||
def test_instantiate(self):
|
||||
|
@ -174,13 +195,19 @@ class AD9910Test(ExperimentCase):
|
|||
def test_io_update_delay(self):
|
||||
self.execute(AD9910Exp, "io_update_delay")
|
||||
dly = self.dataset_mgr.get("dly")
|
||||
bins = self.dataset_mgr.get("bins")
|
||||
print(dly, bins)
|
||||
n = max(bins)
|
||||
# test for 4-periodicity (SYNC_CLK) and maximal contrast
|
||||
for i in range(len(bins)):
|
||||
self.assertEqual(abs(bins[i] - bins[(i + 4) % 8]), n)
|
||||
bins1 = self.dataset_mgr.get("bins1")
|
||||
bins2 = self.dataset_mgr.get("bins2")
|
||||
print(dly, bins1, bins2)
|
||||
n = max(bins2)
|
||||
# no edge at optimal delay
|
||||
self.assertEqual(bins2[(dly + 1) & 3], 0)
|
||||
# edge at expected position
|
||||
self.assertEqual(bins2[(dly + 3) & 3], n)
|
||||
|
||||
def test_sw_readback(self):
|
||||
self.execute(AD9910Exp, "sw_readback")
|
||||
self.assertEqual(self.dataset_mgr.get("sw"), (1, 0))
|
||||
|
||||
def test_profile_readback(self):
|
||||
self.execute(AD9910Exp, "profile_readback")
|
||||
self.assertEqual(self.dataset_mgr.get("ftw"), list(range(8)))
|
||||
|
|
|
@ -98,6 +98,13 @@ class UrukulExp(EnvExperiment):
|
|||
self.dev.init()
|
||||
self.dev.set_sync_div(2)
|
||||
|
||||
@kernel
|
||||
def profile(self):
|
||||
self.core.break_realtime()
|
||||
self.dev.init()
|
||||
self.dev.set_profile(7)
|
||||
self.dev.set_profile(0)
|
||||
|
||||
|
||||
class UrukulTest(ExperimentCase):
|
||||
def test_instantiate(self):
|
||||
|
@ -147,3 +154,6 @@ class UrukulTest(ExperimentCase):
|
|||
|
||||
def test_sync(self):
|
||||
self.execute(UrukulExp, "sync")
|
||||
|
||||
def test_profile(self):
|
||||
self.execute(UrukulExp, "profile")
|
||||
|
|
|
@ -15,7 +15,7 @@ requirements:
|
|||
- python >=3.5.3,<3.6
|
||||
- setuptools 33.1.1
|
||||
- migen 0.8 py35_0+git2d62c0c
|
||||
- misoc 0.11 py35_31+git5ce139dd
|
||||
- misoc 0.11 py35_33+git128750aa
|
||||
- jesd204b 0.10
|
||||
- microscope
|
||||
- binutils-or1k-linux >=2.27
|
||||
|
|
|
@ -46,4 +46,6 @@ Default network ports
|
|||
+---------------------------------+--------------+
|
||||
| TOPTICA Laser SDK (out-of-tree) | 3272 |
|
||||
+---------------------------------+--------------+
|
||||
| HighFinesse (out-of-tree) | 3273 |
|
||||
+---------------------------------+--------------+
|
||||
|
||||
|
|
|
@ -131,7 +131,8 @@ On Windows, a third-party tool, `Zadig <http://zadig.akeo.ie/>`_, is necessary.
|
|||
|
||||
1. Make sure the FPGA board's JTAG USB port is connected to your computer.
|
||||
2. Activate Options → List All Devices.
|
||||
3. Select the "Digilent Adept USB Device (Interface 0)" device from the drop-down list.
|
||||
3. Select the "Digilent Adept USB Device (Interface 0)" or "FTDI Quad-RS232 HS" (or similar)
|
||||
device from the drop-down list.
|
||||
4. Select WinUSB from the spinner list.
|
||||
5. Click "Install Driver" or "Replace Driver".
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
{ stdenv, fetchgit, llvm-or1k, makeWrapper, python3, ncurses, zlib, python3Packages }:
|
||||
{ stdenv, fetchFromGitHub, llvm-or1k, makeWrapper, python3, ncurses, zlib, python3Packages }:
|
||||
let
|
||||
version = "0f4ebae";
|
||||
in
|
||||
stdenv.mkDerivation rec {
|
||||
name = "llvmlite-${version}";
|
||||
src = fetchgit {
|
||||
url = "https://github.com/m-labs/llvmlite";
|
||||
src = fetchFromGitHub {
|
||||
rev = "401dfb713166bdd2bc0d3ab2b7ebf12e7a434130";
|
||||
sha256 = "1ci1pnpspv1pqz712yix1nmplq7568vpsr6gzzl3a33w9s0sw2nq";
|
||||
leaveDotGit = true;
|
||||
owner = "m-labs";
|
||||
repo = "llvmlite";
|
||||
sha256 = "1hqahd87ihwgjsaxv0y2iywldi1zgyjxjfy3sy3rr1gnwvxb47xw";
|
||||
};
|
||||
|
||||
buildInputs = [ makeWrapper python3 ncurses zlib llvm-or1k python3Packages.setuptools ];
|
||||
|
|
Loading…
Reference in New Issue