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__ = [ __all__ = [
"AD9910", "AD9910",
"PHASE_MODE_CONTINUOUS", "PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", "PHASE_MODE_TRACKING",
"PHASE_MODE_ABSOLUTE", "RAM_DEST_FTW", "RAM_DEST_POW", "RAM_DEST_ASF", "RAM_DEST_POWASF",
"PHASE_MODE_TRACKING", "RAM_MODE_DIRECTSWITCH", "RAM_MODE_RAMPUP", "RAM_MODE_BIDIR_RAMP",
"RAM_DEST_FTW", "RAM_MODE_CONT_BIDIR_RAMP", "RAM_MODE_CONT_RAMPUP",
"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 _PHASE_MODE_DEFAULT = -1
@ -144,33 +136,13 @@ class AD9910:
to the same string value. to the same string value.
""" """
def __init__( def __init__(self, dmgr, chip_select, cpld_device, sw_device=None,
self, pll_n=40, pll_cp=7, pll_vco=5, sync_delay_seed=-1,
dmgr, io_update_delay=0, pll_en=1):
chip_select, self.kernel_invariants = {"cpld", "core", "bus", "chip_select",
cpld_device, "pll_en", "pll_n", "pll_vco", "pll_cp",
sw_device=None, "ftw_per_hz", "sysclk_per_mu", "sysclk",
pll_n=40, "sync_data"}
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.cpld = dmgr.get(cpld_device)
self.core = self.cpld.core self.core = self.cpld.core
self.bus = self.cpld.bus self.bus = self.cpld.bus
@ -189,14 +161,8 @@ class AD9910:
assert clk <= 60e6 assert clk <= 60e6
assert 12 <= pll_n <= 127 assert 12 <= pll_n <= 127
assert 0 <= pll_vco <= 5 assert 0 <= pll_vco <= 5
vco_min, vco_max = [ vco_min, vco_max = [(370, 510), (420, 590), (500, 700),
(370, 510), (600, 880), (700, 950), (820, 1150)][pll_vco]
(420, 590),
(500, 700),
(600, 880),
(700, 950),
(820, 1150),
][pll_vco]
assert vco_min <= sysclk / 1e6 <= vco_max assert vco_min <= sysclk / 1e6 <= vco_max
assert 0 <= pll_cp <= 7 assert 0 <= pll_cp <= 7
else: else:
@ -211,13 +177,12 @@ class AD9910:
if isinstance(sync_delay_seed, str) or isinstance(io_update_delay, str): if isinstance(sync_delay_seed, str) or isinstance(io_update_delay, str):
if sync_delay_seed != io_update_delay: if sync_delay_seed != io_update_delay:
raise ValueError( raise ValueError("When using EEPROM, sync_delay_seed must be "
"When using EEPROM, sync_delay_seed must be " "equal to io_update_delay")
"equal to io_update_delay"
)
self.sync_data = SyncDataEeprom(dmgr, self.core, sync_delay_seed) self.sync_data = SyncDataEeprom(dmgr, self.core, sync_delay_seed)
else: 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 self.phase_mode = PHASE_MODE_CONTINUOUS
@ -271,9 +236,8 @@ class AD9910:
:param addr: Register address :param addr: Register address
:param data: Data to be written :param data: Data to be written
""" """
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 24,
urukul.SPI_CONFIG | spi.SPI_END, 24, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write((addr << 24) | ((data & 0xFFFF) << 8)) self.bus.write((addr << 24) | ((data & 0xFFFF) << 8))
@kernel @kernel
@ -283,13 +247,11 @@ class AD9910:
:param addr: Register address :param addr: Register address
:param data: Data to be written :param data: Data to be written
""" """
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write(addr << 24) self.bus.write(addr << 24)
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPI_CONFIG | spi.SPI_END, 32, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write(data) self.bus.write(data)
@kernel @kernel
@ -298,16 +260,12 @@ class AD9910:
:param addr: Register address :param addr: Register address
""" """
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write((addr | 0x80) << 24) self.bus.write((addr | 0x80) << 24)
self.bus.set_config_mu( self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT,
16, 16, urukul.SPIT_DDS_RD, self.chip_select)
urukul.SPIT_DDS_RD,
self.chip_select,
)
self.bus.write(0) self.bus.write(0)
return self.bus.read() return self.bus.read()
@ -317,16 +275,12 @@ class AD9910:
:param addr: Register address :param addr: Register address
""" """
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write((addr | 0x80) << 24) self.bus.write((addr | 0x80) << 24)
self.bus.set_config_mu( self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT,
32, 32, urukul.SPIT_DDS_RD, self.chip_select)
urukul.SPIT_DDS_RD,
self.chip_select,
)
self.bus.write(0) self.bus.write(0)
return self.bus.read() return self.bus.read()
@ -338,19 +292,16 @@ class AD9910:
:return: 64-bit integer register value :return: 64-bit integer register value
""" """
self.bus.set_config_mu( 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.write((addr | 0x80) << 24)
self.bus.set_config_mu( 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.write(0)
self.bus.set_config_mu( self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, urukul.SPI_CONFIG | spi.SPI_END | spi.SPI_INPUT, 32,
32, urukul.SPIT_DDS_RD, self.chip_select)
urukul.SPIT_DDS_RD,
self.chip_select,
)
self.bus.write(0) self.bus.write(0)
hi = self.bus.read() hi = self.bus.read()
lo = self.bus.read() lo = self.bus.read()
@ -364,17 +315,14 @@ class AD9910:
:param data_high: High (MSB) 32 data bits :param data_high: High (MSB) 32 data bits
:param data_low: Low (LSB) 32 data bits :param data_low: Low (LSB) 32 data bits
""" """
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 8,
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write(addr << 24) self.bus.write(addr << 24)
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
urukul.SPI_CONFIG, 32, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write(data_high) self.bus.write(data_high)
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPI_CONFIG | spi.SPI_END, 32, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write(data_low) self.bus.write(data_low)
@kernel @kernel
@ -388,18 +336,15 @@ class AD9910:
:param data: Data to be written to RAM. :param data: Data to be written to RAM.
""" """
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write(_AD9910_REG_RAM << 24) self.bus.write(_AD9910_REG_RAM << 24)
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 32,
urukul.SPI_CONFIG, 32, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
for i in range(len(data) - 1): for i in range(len(data) - 1):
self.bus.write(data[i]) self.bus.write(data[i])
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_END, 32,
urukul.SPI_CONFIG | spi.SPI_END, 32, urukul.SPIT_DDS_WR, self.chip_select urukul.SPIT_DDS_WR, self.chip_select)
)
self.bus.write(data[len(data) - 1]) self.bus.write(data[len(data) - 1])
@kernel @kernel
@ -413,36 +358,27 @@ class AD9910:
:param data: List to be filled with data read from RAM. :param data: List to be filled with data read from RAM.
""" """
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR,
urukul.SPI_CONFIG, 8, urukul.SPIT_DDS_WR, self.chip_select self.chip_select)
)
self.bus.write((_AD9910_REG_RAM | 0x80) << 24) self.bus.write((_AD9910_REG_RAM | 0x80) << 24)
n = len(data) - 1 n = len(data) - 1
if n > 0: if n > 0:
self.bus.set_config_mu( self.bus.set_config_mu(urukul.SPI_CONFIG | spi.SPI_INPUT, 32,
urukul.SPI_CONFIG | spi.SPI_INPUT, urukul.SPIT_DDS_RD, self.chip_select)
32,
urukul.SPIT_DDS_RD,
self.chip_select,
)
preload = min(n, 8) preload = min(n, 8)
for i in range(n): for i in range(n):
self.bus.write(0) self.bus.write(0)
if i >= preload: if i >= preload:
data[i - preload] = self.bus.read() data[i - preload] = self.bus.read()
self.bus.set_config_mu( self.bus.set_config_mu(
urukul.SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, urukul.SPI_CONFIG | spi.SPI_INPUT | spi.SPI_END, 32,
32, urukul.SPIT_DDS_RD, self.chip_select)
urukul.SPIT_DDS_RD,
self.chip_select,
)
self.bus.write(0) self.bus.write(0)
for i in range(preload + 1): for i in range(preload + 1):
data[(n - preload) + i] = self.bus.read() data[(n - preload) + i] = self.bus.read()
@kernel @kernel
def set_cfr1( def set_cfr1(self,
self,
power_down: TInt32 = 0b0000, power_down: TInt32 = 0b0000,
phase_autoclear: TInt32 = 0, phase_autoclear: TInt32 = 0,
drg_load_lrr: TInt32 = 0, drg_load_lrr: TInt32 = 0,
@ -453,8 +389,7 @@ class AD9910:
ram_enable: TInt32 = 0, ram_enable: TInt32 = 0,
manual_osk_external: TInt32 = 0, manual_osk_external: TInt32 = 0,
osk_enable: TInt32 = 0, osk_enable: TInt32 = 0,
select_auto_osk: TInt32 = 0, select_auto_osk: TInt32 = 0):
):
"""Set CFR1. See the AD9910 datasheet for parameter meanings and sizes. """Set CFR1. See the AD9910 datasheet for parameter meanings and sizes.
This method does not pulse ``IO_UPDATE.`` This method does not pulse ``IO_UPDATE.``
@ -473,25 +408,22 @@ class AD9910:
:param osk_enable: Enable OSK mode. :param osk_enable: Enable OSK mode.
:param select_auto_osk: Select manual or automatic OSK mode. :param select_auto_osk: Select manual or automatic OSK mode.
""" """
self.write32( self.write32(_AD9910_REG_CFR1,
_AD9910_REG_CFR1, (ram_enable << 31) |
(ram_enable << 31) (ram_destination << 29) |
| (ram_destination << 29) (manual_osk_external << 23) |
| (manual_osk_external << 23) (internal_profile << 17) |
| (internal_profile << 17) (drg_load_lrr << 15) |
| (drg_load_lrr << 15) (drg_autoclear << 14) |
| (drg_autoclear << 14) (phase_autoclear << 13) |
| (phase_autoclear << 13) (phase_clear << 11) |
| (phase_clear << 11) (osk_enable << 9) |
| (osk_enable << 9) (select_auto_osk << 8) |
| (select_auto_osk << 8) (power_down << 4) |
| (power_down << 4) 2) # SDIO input only, MSB first
| 2,
) # SDIO input only, MSB first
@kernel @kernel
def set_cfr2( def set_cfr2(self,
self,
asf_profile_enable: TInt32 = 1, asf_profile_enable: TInt32 = 1,
drg_destination: TInt32 = 0, drg_destination: TInt32 = 0,
drg_enable: TInt32 = 0, drg_enable: TInt32 = 0,
@ -499,8 +431,7 @@ class AD9910:
drg_nodwell_low: TInt32 = 0, drg_nodwell_low: TInt32 = 0,
effective_ftw: TInt32 = 1, effective_ftw: TInt32 = 1,
sync_validation_disable: TInt32 = 0, sync_validation_disable: TInt32 = 0,
matched_latency_enable: TInt32 = 0, matched_latency_enable: TInt32 = 0):
):
"""Set CFR2. See the AD9910 datasheet for parameter meanings and sizes. """Set CFR2. See the AD9910 datasheet for parameter meanings and sizes.
This method does not pulse ``IO_UPDATE``. This method does not pulse ``IO_UPDATE``.
@ -519,17 +450,15 @@ class AD9910:
* matched_latency_enable = 0: in the order listed * matched_latency_enable = 0: in the order listed
* matched_latency_enable = 1: simultaneously. * matched_latency_enable = 1: simultaneously.
""" """
self.write32( self.write32(_AD9910_REG_CFR2,
_AD9910_REG_CFR2, (asf_profile_enable << 24) |
(asf_profile_enable << 24) (drg_destination << 20) |
| (drg_destination << 20) (drg_enable << 19) |
| (drg_enable << 19) (drg_nodwell_high << 18) |
| (drg_nodwell_high << 18) (drg_nodwell_low << 17) |
| (drg_nodwell_low << 17) (effective_ftw << 16) |
| (effective_ftw << 16) (matched_latency_enable << 7) |
| (matched_latency_enable << 7) (sync_validation_disable << 5))
| (sync_validation_disable << 5),
)
@kernel @kernel
def init(self, blind: TBool = False): def init(self, blind: TBool = False):
@ -565,13 +494,9 @@ class AD9910:
# sync timing validation disable (enabled later) # sync timing validation disable (enabled later)
self.set_cfr2(sync_validation_disable=1) self.set_cfr2(sync_validation_disable=1)
self.cpld.io_update.pulse(1 * us) self.cpld.io_update.pulse(1 * us)
cfr3 = ( cfr3 = (0x0807c000 | (self.pll_vco << 24) |
0x0807C000 (self.pll_cp << 19) | (self.pll_en << 8) |
| (self.pll_vco << 24) (self.pll_n << 1))
| (self.pll_cp << 19)
| (self.pll_en << 8)
| (self.pll_n << 1)
)
self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset self.write32(_AD9910_REG_CFR3, cfr3 | 0x400) # PFD reset
self.cpld.io_update.pulse(1 * us) self.cpld.io_update.pulse(1 * us)
if self.pll_en: if self.pll_en:
@ -604,16 +529,11 @@ class AD9910:
self.cpld.io_update.pulse(1 * us) self.cpld.io_update.pulse(1 * us)
@kernel @kernel
def set_mu( def set_mu(self, ftw: TInt32 = 0, pow_: TInt32 = 0, asf: TInt32 = 0x3FFF,
self,
ftw: TInt32 = 0,
pow_: TInt32 = 0,
asf: TInt32 = 0x3FFF,
phase_mode: TInt32 = _PHASE_MODE_DEFAULT, phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
ref_time_mu: TInt64 = int64(-1), ref_time_mu: TInt64 = int64(-1),
profile: TInt32 = DEFAULT_PROFILE, profile: TInt32 = DEFAULT_PROFILE,
ram_destination: TInt32 = -1, ram_destination: TInt32 = -1) -> TInt32:
) -> TInt32:
"""Set DDS data in machine units. """Set DDS data in machine units.
This uses machine units (FTW, POW, ASF). The frequency tuning word 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) dt = int32(now_mu()) - int32(ref_time_mu)
pow_ += dt * ftw * self.sysclk_per_mu >> 16 pow_ += dt * ftw * self.sysclk_per_mu >> 16
if ram_destination == -1: if ram_destination == -1:
self.write64( self.write64(_AD9910_REG_PROFILE0 + profile,
_AD9910_REG_PROFILE0 + profile, (asf << 16) | (pow_ & 0xFFFF), ftw (asf << 16) | (pow_ & 0xFFFF), ftw)
)
else: else:
if not ram_destination == RAM_DEST_FTW: if not ram_destination == RAM_DEST_FTW:
self.set_ftw(ftw) self.set_ftw(ftw)
@ -683,8 +602,7 @@ class AD9910:
return pow_ return pow_
@kernel @kernel
def get_mu( def get_mu(self, profile: TInt32 = DEFAULT_PROFILE
self, profile: TInt32 = DEFAULT_PROFILE
) -> TTuple([TInt32, TInt32, TInt32]): ) -> TTuple([TInt32, TInt32, TInt32]):
"""Get the frequency tuning word, phase offset word, """Get the frequency tuning word, phase offset word,
and amplitude scale factor. and amplitude scale factor.
@ -704,16 +622,10 @@ class AD9910:
return ftw, pow_, asf return ftw, pow_, asf
@kernel @kernel
def set_profile_ram( def set_profile_ram(self, start: TInt32, end: TInt32, step: TInt32 = 1,
self,
start: TInt32,
end: TInt32,
step: TInt32 = 1,
profile: TInt32 = _DEFAULT_PROFILE_RAM, profile: TInt32 = _DEFAULT_PROFILE_RAM,
nodwell_high: TInt32 = 0, nodwell_high: TInt32 = 0, zero_crossing: TInt32 = 0,
zero_crossing: TInt32 = 0, mode: TInt32 = 1):
mode: TInt32 = 1,
):
"""Set the RAM profile settings. See also AD9910 datasheet. """Set the RAM profile settings. See also AD9910 datasheet.
:param start: Profile start address in RAM (10-bit). :param start: Profile start address in RAM (10-bit).
@ -732,13 +644,8 @@ class AD9910:
:const:`RAM_MODE_RAMPUP`) :const:`RAM_MODE_RAMPUP`)
""" """
hi = (step << 8) | (end >> 2) hi = (step << 8) | (end >> 2)
lo = ( lo = ((end << 30) | (start << 14) | (nodwell_high << 5) |
(end << 30) (zero_crossing << 3) | mode)
| (start << 14)
| (nodwell_high << 5)
| (zero_crossing << 3)
| mode
)
self.write64(_AD9910_REG_PROFILE0 + profile, hi, lo) self.write64(_AD9910_REG_PROFILE0 + profile, hi, lo)
@kernel @kernel
@ -876,9 +783,8 @@ class AD9910:
ram[i] = self.amplitude_to_asf(amplitude[i]) << 18 ram[i] = self.amplitude_to_asf(amplitude[i]) << 18
@portable(flags={"fast-math"}) @portable(flags={"fast-math"})
def turns_amplitude_to_ram( def turns_amplitude_to_ram(self, turns: TList(TFloat),
self, turns: TList(TFloat), amplitude: TList(TFloat), ram: TList(TInt32) amplitude: TList(TFloat), ram: TList(TInt32)):
):
"""Convert phase and amplitude values to RAM profile data. """Convert phase and amplitude values to RAM profile data.
To be used with :const:`RAM_DEST_POWASF`. To be used with :const:`RAM_DEST_POWASF`.
@ -889,9 +795,8 @@ class AD9910:
Suitable for :meth:`write_ram`. Suitable for :meth:`write_ram`.
""" """
for i in range(len(ram)): for i in range(len(ram)):
ram[i] = (self.turns_to_pow(turns[i]) << 16) | self.amplitude_to_asf( ram[i] = ((self.turns_to_pow(turns[i]) << 16) |
amplitude[i] self.amplitude_to_asf(amplitude[i]) << 2)
) << 2
@kernel @kernel
def set_frequency(self, frequency: TFloat): def set_frequency(self, frequency: TFloat):
@ -948,16 +853,10 @@ class AD9910:
return self.pow_to_turns(self.get_pow()) return self.pow_to_turns(self.get_pow())
@kernel @kernel
def set( def set(self, frequency: TFloat = 0.0, phase: TFloat = 0.0,
self, amplitude: TFloat = 1.0, phase_mode: TInt32 = _PHASE_MODE_DEFAULT,
frequency: TFloat = 0.0, ref_time_mu: TInt64 = int64(-1), profile: TInt32 = DEFAULT_PROFILE,
phase: TFloat = 0.0, ram_destination: TInt32 = -1) -> TFloat:
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. """Set DDS data in SI units.
See also :meth:`AD9910.set_mu`. See also :meth:`AD9910.set_mu`.
@ -971,21 +870,13 @@ class AD9910:
:param ram_destination: RAM destination. :param ram_destination: RAM destination.
:return: Resulting phase offset in turns :return: Resulting phase offset in turns
""" """
return self.pow_to_turns( return self.pow_to_turns(self.set_mu(
self.set_mu( self.frequency_to_ftw(frequency), self.turns_to_pow(phase),
self.frequency_to_ftw(frequency), self.amplitude_to_asf(amplitude), phase_mode, ref_time_mu,
self.turns_to_pow(phase), profile, ram_destination))
self.amplitude_to_asf(amplitude),
phase_mode,
ref_time_mu,
profile,
ram_destination,
)
)
@kernel @kernel
def get( def get(self, profile: TInt32 = DEFAULT_PROFILE
self, profile: TInt32 = DEFAULT_PROFILE
) -> TTuple([TFloat, TFloat, TFloat]): ) -> TTuple([TFloat, TFloat, TFloat]):
"""Get the frequency, phase, and amplitude. """Get the frequency, phase, and amplitude.
@ -998,11 +889,8 @@ class AD9910:
# Get values # Get values
ftw, pow_, asf = self.get_mu(profile) ftw, pow_, asf = self.get_mu(profile)
# Convert and return # Convert and return
return ( return (self.ftw_to_frequency(ftw), self.pow_to_turns(pow_),
self.ftw_to_frequency(ftw), self.asf_to_amplitude(asf))
self.pow_to_turns(pow_),
self.asf_to_amplitude(asf),
)
@kernel @kernel
def set_att_mu(self, att: TInt32): def set_att_mu(self, att: TInt32):
@ -1104,7 +992,10 @@ class AD9910:
self.cpld.cfg_att_en(self.chip_select - 4, state) self.cpld.cfg_att_en(self.chip_select - 4, state)
@kernel @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 """Set the relevant parameters in the multi device synchronization
register. See the AD9910 datasheet for details. The ``SYNC`` clock register. See the AD9910 datasheet for details. The ``SYNC`` clock
generator preset value is set to zero, and the ``SYNC_OUT`` generator is 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 (``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. use case, where the ``SYNC`` clock is supplied by the core device.
""" """
self.write32( self.write32(_AD9910_REG_SYNC,
_AD9910_REG_SYNC, (window << 28) | # SYNC S/H validation delay
(window << 28) # SYNC S/H validation delay (1 << 27) | # SYNC receiver enable
| (1 << 27) # SYNC receiver enable (en_sync_gen << 26) | # SYNC generator enable
| (en_sync_gen << 26) # SYNC generator enable (0 << 25) | # SYNC generator SYS rising edge
| (0 << 25) # SYNC generator SYS rising edge (0 << 18) | # SYNC preset
| (0 << 18) # SYNC preset (0 << 11) | # SYNC output delay
| (0 << 11) # SYNC output delay (in_delay << 3)) # SYNC receiver delay
| (in_delay << 3),
) # SYNC receiver delay
@kernel @kernel
def clear_smp_err(self): def clear_smp_err(self):
@ -1145,7 +1034,8 @@ class AD9910:
self.cpld.io_update.pulse(1 * us) self.cpld.io_update.pulse(1 * us)
@kernel @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. """Find a stable ``SYNC_IN`` delay.
This method first locates a valid ``SYNC_IN`` delay at zero validation This method first locates a valid ``SYNC_IN`` delay at zero validation
@ -1201,9 +1091,8 @@ class AD9910:
raise ValueError("no valid window/delay") raise ValueError("no valid window/delay")
@kernel @kernel
def measure_io_update_alignment( def measure_io_update_alignment(self, delay_start: TInt64,
self, delay_start: TInt64, delay_stop: TInt64 delay_stop: TInt64) -> TInt32:
) -> TInt32:
"""Use the digital ramp generator to locate the alignment between """Use the digital ramp generator to locate the alignment between
``IO_UPDATE`` and ``SYNC_CLK``. ``IO_UPDATE`` and ``SYNC_CLK``.
@ -1275,9 +1164,11 @@ class AD9910:
for j in range(repeat): for j in range(repeat):
t1[0] += self.measure_io_update_alignment(i, i + 1) t1[0] += self.measure_io_update_alignment(i, i + 1)
t1[1] += self.measure_io_update_alignment(i + 1, i + 2) 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 # 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: else:
# the good delay is period//2 after the edge # the good delay is period//2 after the edge
return (i + 1 + period // 2) & (period - 1) 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.types import TBool, TFloat, TInt32, TInt64
from artiq.language.units import ms, us from artiq.language.units import ms, us
SPI_CONFIG = ( SPI_CONFIG = (0 * spi.SPI_OFFLINE | 0 * spi.SPI_END |
0 * spi.SPI_OFFLINE 0 * spi.SPI_INPUT | 1 * spi.SPI_CS_POLARITY |
| 0 * spi.SPI_END 0 * spi.SPI_CLK_POLARITY | 0 * spi.SPI_CLK_PHASE |
| 0 * spi.SPI_INPUT 0 * spi.SPI_LSB_FIRST | 0 * spi.SPI_HALF_DUPLEX)
| 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 # SPI clock write and read dividers
SPIT_CFG_WR = 2 SPIT_CFG_WR = 2
@ -693,23 +687,11 @@ class CPLD:
kernel_invariants = {"refclk", "bus", "core", "io_update", "clk_div"} kernel_invariants = {"refclk", "bus", "core", "io_update", "clk_div"}
def __init__( def __init__(self, dmgr, spi_device, io_update_device=None,
self, dds_reset_device=None, sync_device=None,
dmgr, sync_sel=0, clk_sel=0, clk_div=0, rf_sw=0,
spi_device, refclk=125e6, att=0x00000000, sync_div=None,
io_update_device=None, proto_rev=0x08, core_device="core"):
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.core = dmgr.get(core_device)
self.refclk = refclk self.refclk = refclk
@ -907,7 +889,8 @@ class CPLD:
:param att_reg: Attenuator setting string (32-bit) :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.bus.write(att_reg)
self.att_reg = att_reg self.att_reg = att_reg
@ -935,9 +918,11 @@ class CPLD:
:return: 32-bit attenuator settings :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.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) delay(10 * us)
self.att_reg = self.bus.read() self.att_reg = self.bus.read()
self.bus.write(self.att_reg) # shift in current value again and latch 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() t0 = self.core.get_rtio_counter_mu()
for i in range(n): for i in range(n):
self.dev.cfg_sw(2, bool(i & 1)) self.dev.cfg_sw(2, bool(i & 1))
self.set_dataset( self.set_dataset("dt", self.core.mu_to_seconds(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n self.core.get_rtio_counter_mu() - t0) / n)
)
@kernel @kernel
def switches_readback(self): def switches_readback(self):
@ -90,9 +89,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu() t0 = self.core.get_rtio_counter_mu()
for i in range(n): for i in range(n):
self.dev.cfg_att_en(1, bool(i & 1)) self.dev.cfg_att_en(1, bool(i & 1))
self.set_dataset( self.set_dataset("dt", self.core.mu_to_seconds(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n self.core.get_rtio_counter_mu() - t0) / n)
)
@kernel @kernel
def att(self): def att(self):
@ -135,7 +133,8 @@ class UrukulExp(EnvExperiment):
self.dev.init() self.dev.init()
# clear backing state # clear backing state
self.dev.att_reg = 0 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 # set individual attenuators
for i in range(len(att_set)): for i in range(len(att_set)):
self.dev.set_att_mu(i, att_set[i]) self.dev.set_att_mu(i, att_set[i])
@ -158,9 +157,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu() t0 = self.core.get_rtio_counter_mu()
for i in range(n): for i in range(n):
self.dev.set_att(3, 30 * dB) self.dev.set_att(3, 30 * dB)
self.set_dataset( self.set_dataset("dt", self.core.mu_to_seconds(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n self.core.get_rtio_counter_mu() - t0) / n)
)
@kernel @kernel
def osk(self): def osk(self):
@ -179,9 +177,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu() t0 = self.core.get_rtio_counter_mu()
for i in range(n): for i in range(n):
self.dev.cfg_osk(1, bool(i & 1)) self.dev.cfg_osk(1, bool(i & 1))
self.set_dataset( self.set_dataset("dt", self.core.mu_to_seconds(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n self.core.get_rtio_counter_mu() - t0) / n)
)
@kernel @kernel
def drctl(self): def drctl(self):
@ -200,9 +197,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu() t0 = self.core.get_rtio_counter_mu()
for i in range(n): for i in range(n):
self.dev.cfg_drctl(2, bool(i & 1)) self.dev.cfg_drctl(2, bool(i & 1))
self.set_dataset( self.set_dataset("dt", self.core.mu_to_seconds(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n self.core.get_rtio_counter_mu() - t0) / n)
)
@kernel @kernel
def drhold(self): def drhold(self):
@ -221,9 +217,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu() t0 = self.core.get_rtio_counter_mu()
for i in range(n): for i in range(n):
self.dev.cfg_drhold(1, bool(i & 1)) self.dev.cfg_drhold(1, bool(i & 1))
self.set_dataset( self.set_dataset("dt", self.core.mu_to_seconds(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n self.core.get_rtio_counter_mu() - t0) / n)
)
@kernel @kernel
def mask_nu(self): def mask_nu(self):
@ -242,9 +237,8 @@ class UrukulExp(EnvExperiment):
t0 = self.core.get_rtio_counter_mu() t0 = self.core.get_rtio_counter_mu()
for i in range(n): for i in range(n):
self.dev.cfg_mask_nu(2, bool(i & 1)) self.dev.cfg_mask_nu(2, bool(i & 1))
self.set_dataset( self.set_dataset("dt", self.core.mu_to_seconds(
"dt", self.core.mu_to_seconds(self.core.get_rtio_counter_mu() - t0) / n self.core.get_rtio_counter_mu() - t0) / n)
)
# Note, cfg_io_update is tested in test_ad9910.py # Note, cfg_io_update is tested in test_ad9910.py
@kernel @kernel
@ -339,7 +333,7 @@ class UrukulTest(ExperimentCase):
self.assertListEqual(att_set, self.dataset_mgr.get("att_get")) self.assertListEqual(att_set, self.dataset_mgr.get("att_get"))
att_reg = self.dataset_mgr.get("att_reg") att_reg = self.dataset_mgr.get("att_reg")
for att in att_set: for att in att_set:
self.assertEqual(att, att_reg & 0xFF) self.assertEqual(att, att_reg & 0xff)
att_reg >>= 8 att_reg >>= 8
def test_att_speed(self): def test_att_speed(self):