2
0
mirror of https://github.com/m-labs/artiq.git synced 2025-02-03 06:10:18 +08:00

Un-format for clearer review

This commit is contained in:
newell 2024-12-26 14:05:19 -08:00
parent 4dcc492382
commit 18dab3aace
3 changed files with 188 additions and 318 deletions

View File

@ -13,18 +13,10 @@ urukul_sta_smp_err = urukul.urukul_sta_smp_err
__all__ = [
"AD9910",
"PHASE_MODE_CONTINUOUS",
"PHASE_MODE_ABSOLUTE",
"PHASE_MODE_TRACKING",
"RAM_DEST_FTW",
"RAM_DEST_POW",
"RAM_DEST_ASF",
"RAM_DEST_POWASF",
"RAM_MODE_DIRECTSWITCH",
"RAM_MODE_RAMPUP",
"RAM_MODE_BIDIR_RAMP",
"RAM_MODE_CONT_BIDIR_RAMP",
"RAM_MODE_CONT_RAMPUP",
"PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING",
"RAM_DEST_FTW", "RAM_DEST_POW", "RAM_DEST_ASF", "RAM_DEST_POWASF",
"RAM_MODE_DIRECTSWITCH", "RAM_MODE_RAMPUP", "RAM_MODE_BIDIR_RAMP",
"RAM_MODE_CONT_BIDIR_RAMP", "RAM_MODE_CONT_RAMPUP",
]
_PHASE_MODE_DEFAULT = -1
@ -144,33 +136,13 @@ class AD9910:
to the same string value.
"""
def __init__(
self,
dmgr,
chip_select,
cpld_device,
sw_device=None,
pll_n=40,
pll_cp=7,
pll_vco=5,
sync_delay_seed=-1,
io_update_delay=0,
pll_en=1,
):
self.kernel_invariants = {
"cpld",
"core",
"bus",
"chip_select",
"pll_en",
"pll_n",
"pll_vco",
"pll_cp",
"ftw_per_hz",
"sysclk_per_mu",
"sysclk",
"sync_data",
}
def __init__(self, dmgr, chip_select, cpld_device, sw_device=None,
pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1,
io_update_delay=0, pll_en=1):
self.kernel_invariants = {"cpld", "core", "bus", "chip_select",
"pll_en", "pll_n", "pll_vco", "pll_cp",
"ftw_per_hz", "sysclk_per_mu", "sysclk",
"sync_data"}
self.cpld = dmgr.get(cpld_device)
self.core = self.cpld.core
self.bus = self.cpld.bus
@ -189,14 +161,8 @@ class AD9910:
assert clk <= 60e6
assert 12 <= pll_n <= 127
assert 0 <= pll_vco <= 5
vco_min, vco_max = [
(370, 510),
(420, 590),
(500, 700),
(600, 880),
(700, 950),
(820, 1150),
][pll_vco]
vco_min, vco_max = [(370, 510), (420, 590), (500, 700),
(600, 880), (700, 950), (820, 1150)][pll_vco]
assert vco_min <= sysclk / 1e6 <= vco_max
assert 0 <= pll_cp <= 7
else:
@ -211,13 +177,12 @@ class AD9910:
if isinstance(sync_delay_seed, str) or isinstance(io_update_delay, str):
if sync_delay_seed != io_update_delay:
raise ValueError(
"When using EEPROM, sync_delay_seed must be "
"equal to io_update_delay"
)
raise ValueError("When using EEPROM, sync_delay_seed must be "
"equal to io_update_delay")
self.sync_data = SyncDataEeprom(dmgr, self.core, sync_delay_seed)
else:
self.sync_data = SyncDataUser(self.core, sync_delay_seed, io_update_delay)
self.sync_data = SyncDataUser(self.core, sync_delay_seed,
io_update_delay)
self.phase_mode = PHASE_MODE_CONTINUOUS
@ -271,10 +236,9 @@ class AD9910:
:param addr: Register address
:param data: Data to be written
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END, 24, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.write((addr << 24) | ((data & 0xFFFF) << 8))
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 24,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((addr << 24) | ((data & 0xFFFF) << 8))
@kernel
def write32(self, addr: TInt32, data: TInt32):
@ -283,13 +247,11 @@ class AD9910:
:param addr: Register address
:param data: Data to be written
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(addr << 24)
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END, 32, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(data)
@kernel
@ -298,16 +260,12 @@ class AD9910:
:param addr: Register address
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((addr | 0x80) << 24)
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT,
16,
urukul.SPIT_DDS_RD,
self.chip_select,
)
16, urukul.SPIT_DDS_RD, self.chip_select)
self.bus.write(0)
return self.bus.read()
@ -317,16 +275,12 @@ class AD9910:
:param addr: Register address
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((addr | 0x80) << 24)
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT,
32,
urukul.SPIT_DDS_RD,
self.chip_select,
)
32, urukul.SPIT_DDS_RD, self.chip_select)
self.bus.write(0)
return self.bus.read()
@ -338,19 +292,16 @@ class AD9910:
:return: 64-bit integer register value
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select
)
urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write((addr | 0x80) << 24)
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_INPUT, 32, urukul.SPIT_DDS_RD, self.chip_select
)
urukul.SPI_CONFIG | spi.SPI_INPUT, 32,
urukul.SPIT_DDS_RD, self.chip_select)
self.bus.write(0)
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT,
32,
urukul.SPIT_DDS_RD,
self.chip_select,
)
urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32,
urukul.SPIT_DDS_RD, self.chip_select)
self.bus.write(0)
hi = self.bus.read()
lo = self.bus.read()
@ -361,20 +312,17 @@ class AD9910:
"""Write to 64-bit register.
:param addr: Register address
:param data_high: High (MSB) 32 data bits
:param data_high: High (MSB) 32 data bits
:param data_low: Low (LSB) 32 data bits
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(addr << 24)
self.bus.set_config_mu(
urukul.SPI_CONFIG, 32, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(data_high)
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END, 32, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(data_low)
@kernel
@ -388,18 +336,15 @@ class AD9910:
:param data: Data to be written to RAM.
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(_AD9910_REG_RAM << 24)
self.bus.set_config_mu(
urukul.SPI_CONFIG, 32, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
urukul.SPIT_DDS_WR, self.chip_select)
for i in range(len(data) - 1):
self.bus.write(data[i])
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END, 32, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPIT_DDS_WR, self.chip_select)
self.bus.write(data[len(data) - 1])
@kernel
@ -408,53 +353,43 @@ class AD9910:
The profile to read from and the step, start, and end address
need to be configured before and separately using
:meth:`set_profile_ram` and the parent CPLD
:meth:`set_profile_ram` and the parent CPLD
:meth:`~artiq.coredevice.urukul.CPLD.set_profile`.
:param data: List to be filled with data read from RAM.
"""
self.bus.set_config_mu(
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select
)
self.bus.set_config_mu(urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR,
self.chip_select)
self.bus.write((_AD9910_REG_RAM | 0x80) << 24)
n = len(data) - 1
if n > 0:
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_INPUT,
32,
urukul.SPIT_DDS_RD,
self.chip_select,
)
self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_INPUT, 32,
urukul.SPIT_DDS_RD, self.chip_select)
preload = min(n, 8)
for i in range(n):
self.bus.write(0)
if i >= preload:
data[i - preload] = self.bus.read()
self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END,
32,
urukul.SPIT_DDS_RD,
self.chip_select,
)
urukul.SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 32,
urukul.SPIT_DDS_RD, self.chip_select)
self.bus.write(0)
for i in range(preload + 1):
data[(n - preload) + i] = self.bus.read()
@kernel
def set_cfr1(
self,
power_down: TInt32 = 0b0000,
phase_autoclear: TInt32 = 0,
drg_load_lrr: TInt32 = 0,
drg_autoclear: TInt32 = 0,
phase_clear: TInt32 = 0,
internal_profile: TInt32 = 0,
ram_destination: TInt32 = 0,
ram_enable: TInt32 = 0,
manual_osk_external: TInt32 = 0,
osk_enable: TInt32 = 0,
select_auto_osk: TInt32 = 0,
):
def set_cfr1(self,
power_down: TInt32 = 0b0000,
phase_autoclear: TInt32 = 0,
drg_load_lrr: TInt32 = 0,
drg_autoclear: TInt32 = 0,
phase_clear: TInt32 = 0,
internal_profile: TInt32 = 0,
ram_destination: TInt32 = 0,
ram_enable: TInt32 = 0,
manual_osk_external: TInt32 = 0,
osk_enable: TInt32 = 0,
select_auto_osk: TInt32 = 0):
"""Set CFR1. See the AD9910 datasheet for parameter meanings and sizes.
This method does not pulse ``IO_UPDATE.``
@ -473,34 +408,30 @@ class AD9910:
:param osk_enable: Enable OSK mode.
:param select_auto_osk: Select manual or automatic OSK mode.
"""
self.write32(
_AD9910_REG_CFR1,
(ram_enable << 31)
| (ram_destination << 29)
| (manual_osk_external << 23)
| (internal_profile << 17)
| (drg_load_lrr << 15)
| (drg_autoclear << 14)
| (phase_autoclear << 13)
| (phase_clear << 11)
| (osk_enable << 9)
| (select_auto_osk << 8)
| (power_down << 4)
| 2,
) # SDIO input only, MSB first
self.write32(_AD9910_REG_CFR1,
(ram_enable << 31) |
(ram_destination << 29) |
(manual_osk_external << 23) |
(internal_profile << 17) |
(drg_load_lrr << 15) |
(drg_autoclear << 14) |
(phase_autoclear << 13) |
(phase_clear << 11) |
(osk_enable << 9) |
(select_auto_osk << 8) |
(power_down << 4) |
2) # SDIO input only, MSB first
@kernel
def set_cfr2(
self,
asf_profile_enable: TInt32 = 1,
drg_destination: TInt32 = 0,
drg_enable: TInt32 = 0,
drg_nodwell_high: TInt32 = 0,
drg_nodwell_low: TInt32 = 0,
effective_ftw: TInt32 = 1,
sync_validation_disable: TInt32 = 0,
matched_latency_enable: TInt32 = 0,
):
def set_cfr2(self,
asf_profile_enable: TInt32 = 1,
drg_destination: TInt32 = 0,
drg_enable: TInt32 = 0,
drg_nodwell_high: TInt32 = 0,
drg_nodwell_low: TInt32 = 0,
effective_ftw: TInt32 = 1,
sync_validation_disable: TInt32 = 0,
matched_latency_enable: TInt32 = 0):
"""Set CFR2. See the AD9910 datasheet for parameter meanings and sizes.
This method does not pulse ``IO_UPDATE``.
@ -519,24 +450,22 @@ class AD9910:
* matched_latency_enable = 0: in the order listed
* matched_latency_enable = 1: simultaneously.
"""
self.write32(
_AD9910_REG_CFR2,
(asf_profile_enable << 24)
| (drg_destination << 20)
| (drg_enable << 19)
| (drg_nodwell_high << 18)
| (drg_nodwell_low << 17)
| (effective_ftw << 16)
| (matched_latency_enable << 7)
| (sync_validation_disable << 5),
)
self.write32(_AD9910_REG_CFR2,
(asf_profile_enable << 24) |
(drg_destination << 20) |
(drg_enable << 19) |
(drg_nodwell_high << 18) |
(drg_nodwell_low << 17) |
(effective_ftw << 16) |
(matched_latency_enable << 7) |
(sync_validation_disable << 5))
@kernel
def init(self, blind: TBool = False):
"""Initialize and configure the DDS.
Sets up SPI mode, confirms chip presence, powers down unused blocks,
configures the PLL, waits for PLL lock. Uses the ``IO_UPDATE``
configures the PLL, waits for PLL lock. Uses the ``IO_UPDATE``
signal multiple times.
:param blind: Do not read back DDS identity and do not wait for lock.
@ -565,13 +494,9 @@ class AD9910:
# sync timing validation disable (enabled later)
self.set_cfr2(sync_validation_disable=1)
self.cpld.io_update.pulse(1 * us)
cfr3 = (
0x0807C000
| (self.pll_vco << 24)
| (self.pll_cp << 19)
| (self.pll_en << 8)
| (self.pll_n << 1)
)
cfr3 = (0x0807c000 | (self.pll_vco << 24) |
(self.pll_cp << 19) | (self.pll_en << 8) |
(self.pll_n << 1))
self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset
self.cpld.io_update.pulse(1 * us)
if self.pll_en:
@ -604,16 +529,11 @@ class AD9910:
self.cpld.io_update.pulse(1 * us)
@kernel
def set_mu(
self,
ftw: TInt32 = 0,
pow_: TInt32 = 0,
asf: TInt32 = 0x3FFF,
phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
ref_time_mu: TInt64 = int64(-1),
profile: TInt32 = DEFAULT_PROFILE,
ram_destination: TInt32 = -1,
) -> TInt32:
def set_mu(self, ftw: TInt32 = 0, pow_: TInt32 = 0, asf: TInt32 = 0x3FFF,
phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
ref_time_mu: TInt64 = int64(-1),
profile: TInt32 = DEFAULT_PROFILE,
ram_destination: TInt32 = -1) -> TInt32:
"""Set DDS data in machine units.
This uses machine units (FTW, POW, ASF). The frequency tuning word
@ -663,9 +583,8 @@ class AD9910:
dt = int32(now_mu()) - int32(ref_time_mu)
pow_ += dt * ftw * self.sysclk_per_mu >> 16
if ram_destination == -1:
self.write64(
_AD9910_REG_PROFILE0 + profile, (asf << 16) | (pow_ & 0xFFFF), ftw
)
self.write64(_AD9910_REG_PROFILE0 + profile,
(asf << 16) | (pow_ & 0xFFFF), ftw)
else:
if not ram_destination == RAM_DEST_FTW:
self.set_ftw(ftw)
@ -683,9 +602,8 @@ class AD9910:
return pow_
@kernel
def get_mu(
self, profile: TInt32 = DEFAULT_PROFILE
) -> TTuple([TInt32, TInt32, TInt32]):
def get_mu(self, profile: TInt32 = DEFAULT_PROFILE
) -> TTuple([TInt32, TInt32, TInt32]):
"""Get the frequency tuning word, phase offset word,
and amplitude scale factor.
@ -704,16 +622,10 @@ class AD9910:
return ftw, pow_, asf
@kernel
def set_profile_ram(
self,
start: TInt32,
end: TInt32,
step: TInt32 = 1,
profile: TInt32 = _DEFAULT_PROFILE_RAM,
nodwell_high: TInt32 = 0,
zero_crossing: TInt32 = 0,
mode: TInt32 = 1,
):
def set_profile_ram(self, start: TInt32, end: TInt32, step: TInt32 = 1,
profile: TInt32 = _DEFAULT_PROFILE_RAM,
nodwell_high: TInt32 = 0, zero_crossing: TInt32 = 0,
mode: TInt32 = 1):
"""Set the RAM profile settings. See also AD9910 datasheet.
:param start: Profile start address in RAM (10-bit).
@ -732,13 +644,8 @@ class AD9910:
:const:`RAM_MODE_RAMPUP`)
"""
hi = (step << 8) | (end >> 2)
lo = (
(end << 30)
| (start << 14)
| (nodwell_high << 5)
| (zero_crossing << 3)
| mode
)
lo = ((end << 30) | (start << 14) | (nodwell_high << 5) |
(zero_crossing << 3) | mode)
self.write64(_AD9910_REG_PROFILE0 + profile, hi, lo)
@kernel
@ -876,9 +783,8 @@ class AD9910:
ram[i] = self.amplitude_to_asf(amplitude[i]) << 18
@portable(flags={"fast-math"})
def turns_amplitude_to_ram(
self, turns: TList(TFloat), amplitude: TList(TFloat), ram: TList(TInt32)
):
def turns_amplitude_to_ram(self, turns: TList(TFloat),
amplitude: TList(TFloat), ram: TList(TInt32)):
"""Convert phase and amplitude values to RAM profile data.
To be used with :const:`RAM_DEST_POWASF`.
@ -889,9 +795,8 @@ class AD9910:
Suitable for :meth:`write_ram`.
"""
for i in range(len(ram)):
ram[i] = (self.turns_to_pow(turns[i]) << 16) | self.amplitude_to_asf(
amplitude[i]
) << 2
ram[i] = ((self.turns_to_pow(turns[i]) << 16) |
self.amplitude_to_asf(amplitude[i]) << 2)
@kernel
def set_frequency(self, frequency: TFloat):
@ -948,16 +853,10 @@ class AD9910:
return self.pow_to_turns(self.get_pow())
@kernel
def set(
self,
frequency: TFloat = 0.0,
phase: TFloat = 0.0,
amplitude: TFloat = 1.0,
phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
ref_time_mu: TInt64 = int64(-1),
profile: TInt32 = DEFAULT_PROFILE,
ram_destination: TInt32 = -1,
) -> TFloat:
def set(self, frequency: TFloat = 0.0, phase: TFloat = 0.0,
amplitude: TFloat = 1.0, phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
ref_time_mu: TInt64 = int64(-1), profile: TInt32 = DEFAULT_PROFILE,
ram_destination: TInt32 = -1) -> TFloat:
"""Set DDS data in SI units.
See also :meth:`AD9910.set_mu`.
@ -971,22 +870,14 @@ class AD9910:
:param ram_destination: RAM destination.
: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_mu,
profile,
ram_destination,
)
)
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_mu,
profile, ram_destination))
@kernel
def get(
self, profile: TInt32 = DEFAULT_PROFILE
) -> TTuple([TFloat, TFloat, TFloat]):
def get(self, profile: TInt32 = DEFAULT_PROFILE
) -> TTuple([TFloat, TFloat, TFloat]):
"""Get the frequency, phase, and amplitude.
See also :meth:`AD9910.get_mu`.
@ -998,11 +889,8 @@ class AD9910:
# Get values
ftw, pow_, asf = self.get_mu(profile)
# Convert and return
return (
self.ftw_to_frequency(ftw),
self.pow_to_turns(pow_),
self.asf_to_amplitude(asf),
)
return (self.ftw_to_frequency(ftw), self.pow_to_turns(pow_),
self.asf_to_amplitude(asf))
@kernel
def set_att_mu(self, att: TInt32):
@ -1041,7 +929,7 @@ class AD9910:
@kernel
def get_att(self) -> TFloat:
"""Get digital step attenuator value in SI units. See also
"""Get digital step attenuator value in SI units. See also
:meth:`CPLD.get_channel_att <artiq.coredevice.urukul.CPLD.get_channel_att>`.
:return: Attenuation in dB.
@ -1104,7 +992,10 @@ class AD9910:
self.cpld.cfg_att_en(self.chip_select - 4, state)
@kernel
def set_sync(self, in_delay: TInt32, window: TInt32, en_sync_gen: TInt32 = 0):
def set_sync(self,
in_delay: TInt32,
window: TInt32,
en_sync_gen: TInt32 = 0):
"""Set the relevant parameters in the multi device synchronization
register. See the AD9910 datasheet for details. The ``SYNC`` clock
generator preset value is set to zero, and the ``SYNC_OUT`` generator is
@ -1117,16 +1008,14 @@ class AD9910:
(``SYNC_OUT``, cf. ``sync_sel == 1``). Should be left off for the normal
use case, where the ``SYNC`` clock is supplied by the core device.
"""
self.write32(
_AD9910_REG_SYNC,
(window << 28) # SYNC S/H validation delay
| (1 << 27) # SYNC receiver enable
| (en_sync_gen << 26) # SYNC generator enable
| (0 << 25) # SYNC generator SYS rising edge
| (0 << 18) # SYNC preset
| (0 << 11) # SYNC output delay
| (in_delay << 3),
) # SYNC receiver delay
self.write32(_AD9910_REG_SYNC,
(window << 28) | # SYNC S/H validation delay
(1 << 27) | # SYNC receiver enable
(en_sync_gen << 26) | # SYNC generator enable
(0 << 25) | # SYNC generator SYS rising edge
(0 << 18) | # SYNC preset
(0 << 11) | # SYNC output delay
(in_delay << 3)) # SYNC receiver delay
@kernel
def clear_smp_err(self):
@ -1145,7 +1034,8 @@ class AD9910:
self.cpld.io_update.pulse(1 * us)
@kernel
def tune_sync_delay(self, search_seed: TInt32 = 15) -> TTuple([TInt32, TInt32]):
def tune_sync_delay(self,
search_seed: TInt32 = 15) -> TTuple([TInt32, TInt32]):
"""Find a stable ``SYNC_IN`` delay.
This method first locates a valid ``SYNC_IN`` delay at zero validation
@ -1201,9 +1091,8 @@ class AD9910:
raise ValueError("no valid window/delay")
@kernel
def measure_io_update_alignment(
self, delay_start: TInt64, delay_stop: TInt64
) -> TInt32:
def measure_io_update_alignment(self, delay_start: TInt64,
delay_stop: TInt64) -> TInt32:
"""Use the digital ramp generator to locate the alignment between
``IO_UPDATE`` and ``SYNC_CLK``.
@ -1275,9 +1164,11 @@ class AD9910:
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):
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")
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)

View File

@ -8,16 +8,10 @@ from artiq.language.core import at_mu, delay, kernel, now_mu, portable
from artiq.language.types import TBool, TFloat, TInt32, TInt64
from artiq.language.units import ms, us
SPI_CONFIG = (
0 * spi.SPI_OFFLINE
| 0 * spi.SPI_END
| 0 * spi.SPI_INPUT
| 1 * spi.SPI_CS_POLARITY
| 0 * spi.SPI_CLK_POLARITY
| 0 * spi.SPI_CLK_PHASE
| 0 * spi.SPI_LSB_FIRST
| 0 * spi.SPI_HALF_DUPLEX
)
SPI_CONFIG = (0 * spi.SPI_OFFLINE | 0 * spi.SPI_END |
0 * spi.SPI_INPUT | 1 * spi.SPI_CS_POLARITY |
0 * spi.SPI_CLK_POLARITY | 0 * spi.SPI_CLK_PHASE |
0 * spi.SPI_LSB_FIRST | 0 * spi.SPI_HALF_DUPLEX)
# SPI clock write and read dividers
SPIT_CFG_WR = 2
@ -693,23 +687,11 @@ class CPLD:
kernel_invariants = {"refclk", "bus", "core", "io_update", "clk_div"}
def __init__(
self,
dmgr,
spi_device,
io_update_device=None,
dds_reset_device=None,
sync_device=None,
sync_sel=0,
clk_sel=0,
clk_div=0,
rf_sw=0,
refclk=125e6,
att=0x00000000,
sync_div=None,
proto_rev=0x08,
core_device="core",
):
def __init__(self, dmgr, spi_device, io_update_device=None,
dds_reset_device=None, sync_device=None,
sync_sel=0, clk_sel=0, clk_div=0, rf_sw=0,
refclk=125e6, att=0x00000000, sync_div=None,
proto_rev=0x08, core_device="core"):
self.core = dmgr.get(core_device)
self.refclk = refclk
@ -901,13 +883,14 @@ class CPLD:
self.set_all_att_mu(a)
@kernel
def set_all_att_mu(self, att_reg: TInt32):
def set_all_att_mu(self, att_reg: TInt32):
"""Set all four digital step attenuators (in machine units).
See also :meth:`set_att_mu`.
:param att_reg: Attenuator setting string (32-bit)
"""
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, SPIT_ATT_WR, CS_ATT)
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32,
SPIT_ATT_WR, CS_ATT)
self.bus.write(att_reg)
self.att_reg = att_reg
@ -935,9 +918,11 @@ class CPLD:
:return: 32-bit attenuator settings
"""
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT, 32, SPIT_ATT_RD, CS_ATT)
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_INPUT, 32,
SPIT_ATT_RD, CS_ATT)
self.bus.write(0) # shift in zeros, shift out current value
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32, SPIT_ATT_WR, CS_ATT)
self.bus.set_config_mu(SPI_CONFIG | spi.SPI_END, 32,
SPIT_ATT_WR, CS_ATT)
delay(10 * us)
self.att_reg = self.bus.read()
self.bus.write(self.att_reg) # shift in current value again and latch

View File

@ -59,9 +59,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu()
for i in range(n):
self.dev.cfg_sw(2, bool(i & 1))
self.set_dataset(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n
)
self.set_dataset("dt", self.core.mu_to_seconds(
self.core.get_rtio_counter_mu() - t0) / n)
@kernel
def switches_readback(self):
@ -90,9 +89,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu()
for i in range(n):
self.dev.cfg_att_en(1, bool(i & 1))
self.set_dataset(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n
)
self.set_dataset("dt", self.core.mu_to_seconds(
self.core.get_rtio_counter_mu() - t0) / n)
@kernel
def att(self):
@ -135,7 +133,8 @@ class UrukulExp(EnvExperiment):
self.dev.init()
# clear backing state
self.dev.att_reg = 0
att_set = [int32(0x21), int32(0x43), int32(0x65), int32(0x87)]
att_set = [int32(0x21), int32(0x43),
int32(0x65), int32(0x87)]
# set individual attenuators
for i in range(len(att_set)):
self.dev.set_att_mu(i, att_set[i])
@ -158,9 +157,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu()
for i in range(n):
self.dev.set_att(3, 30 * dB)
self.set_dataset(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n
)
self.set_dataset("dt", self.core.mu_to_seconds(
self.core.get_rtio_counter_mu() - t0) / n)
@kernel
def osk(self):
@ -179,9 +177,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu()
for i in range(n):
self.dev.cfg_osk(1, bool(i & 1))
self.set_dataset(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n
)
self.set_dataset("dt", self.core.mu_to_seconds(
self.core.get_rtio_counter_mu() - t0) / n)
@kernel
def drctl(self):
@ -200,9 +197,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu()
for i in range(n):
self.dev.cfg_drctl(2, bool(i & 1))
self.set_dataset(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n
)
self.set_dataset("dt", self.core.mu_to_seconds(
self.core.get_rtio_counter_mu() - t0) / n)
@kernel
def drhold(self):
@ -221,9 +217,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu()
for i in range(n):
self.dev.cfg_drhold(1, bool(i & 1))
self.set_dataset(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n
)
self.set_dataset("dt", self.core.mu_to_seconds(
self.core.get_rtio_counter_mu() - t0) / n)
@kernel
def mask_nu(self):
@ -242,9 +237,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu()
for i in range(n):
self.dev.cfg_mask_nu(2, bool(i & 1))
self.set_dataset(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n
)
self.set_dataset("dt", self.core.mu_to_seconds(
self.core.get_rtio_counter_mu() - t0) / n)
# Note, cfg_io_update is tested in test_ad9910.py
@kernel
@ -339,7 +333,7 @@ class UrukulTest(ExperimentCase):
self.assertListEqual(att_set, self.dataset_mgr.get("att_get"))
att_reg = self.dataset_mgr.get("att_reg")
for att in att_set:
self.assertEqual(att, att_reg & 0xFF)
self.assertEqual(att, att_reg & 0xff)
att_reg >>= 8
def test_att_speed(self):