From 3027951dd85d642b235dec57b1309ea65a79c502 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Sun, 13 May 2018 23:29:35 +0800 Subject: [PATCH] integrate new AD9914 driver moninj, analyzer, docs, examples, tests. --- RELEASE_NOTES.rst | 3 + artiq/coredevice/__init__.py | 8 +- artiq/coredevice/comm_analyzer.py | 38 +- artiq/coredevice/dds.py | 401 ------------------ artiq/coredevice/exceptions.py | 7 - artiq/dashboard/moninj.py | 8 +- artiq/examples/kc705_nist_clock/device_db.py | 29 +- .../kc705_nist_clock/repository/dds_setter.py | 4 +- .../kc705_nist_clock/repository/dds_test.py | 7 +- .../repository/photon_histogram.py | 8 +- artiq/examples/master/device_db.py | 29 +- artiq/gateware/rtio/phy/dds.py | 13 +- artiq/test/coredevice/test_rtio.py | 10 +- doc/manual/core_drivers_reference.rst | 18 +- doc/manual/rtio.rst | 2 +- 15 files changed, 70 insertions(+), 515 deletions(-) delete mode 100644 artiq/coredevice/dds.py diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 0008a825a..f329d0c8d 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -32,6 +32,9 @@ ARTIQ-4 to the new bus. * The ``ad5360`` coredevice driver has been renamed to ``ad53xx`` and the API has changed to better support Zotino. +* ``artiq.coredevice.dds`` has been renamed to ``artiq.coredevice.ad9914`` and + simplified. DDS batch mode is no longer supported. The ``core_dds`` device + is no longer necessary. ARTIQ-3 diff --git a/artiq/coredevice/__init__.py b/artiq/coredevice/__init__.py index fbec3d901..dced6ef0a 100644 --- a/artiq/coredevice/__init__.py +++ b/artiq/coredevice/__init__.py @@ -1,9 +1,3 @@ -from artiq.coredevice import exceptions, dds, spi2 from artiq.coredevice.exceptions import (RTIOUnderflow, RTIOOverflow) -from artiq.coredevice.dds import (PHASE_MODE_CONTINUOUS, PHASE_MODE_ABSOLUTE, - PHASE_MODE_TRACKING) -__all__ = [] -__all__ += ["RTIOUnderflow", "RTIOOverflow"] -__all__ += ["PHASE_MODE_CONTINUOUS", "PHASE_MODE_ABSOLUTE", - "PHASE_MODE_TRACKING"] +__all__ = ["RTIOUnderflow", "RTIOOverflow"] diff --git a/artiq/coredevice/comm_analyzer.py b/artiq/coredevice/comm_analyzer.py index 1da425730..6f432ea77 100644 --- a/artiq/coredevice/comm_analyzer.py +++ b/artiq/coredevice/comm_analyzer.py @@ -211,9 +211,8 @@ class TTLClockGenHandler: class DDSHandler: - def __init__(self, vcd_manager, dds_type, onehot_sel, sysclk): + def __init__(self, vcd_manager, onehot_sel, sysclk): self.vcd_manager = vcd_manager - self.dds_type = dds_type self.onehot_sel = onehot_sel self.sysclk = sysclk @@ -227,9 +226,8 @@ class DDSHandler: self.vcd_manager.get_channel(name + "/frequency", 64) dds_channel["vcd_phase"] = \ self.vcd_manager.get_channel(name + "/phase", 64) - if self.dds_type == "DDSChannelAD9914": - dds_channel["ftw"] = [None, None] - dds_channel["pow"] = None + dds_channel["ftw"] = [None, None] + dds_channel["pow"] = None self.dds_channels[dds_channel_nr] = dds_channel def _gpio_to_channels(self, gpio): @@ -252,9 +250,9 @@ class DDSHandler: self.selected_dds_channels = self._gpio_to_channels(message.data) for dds_channel_nr in self.selected_dds_channels: dds_channel = self.dds_channels[dds_channel_nr] - if message.address == 0x2d: + if message.address == 0x11: dds_channel["ftw"][0] = message.data - elif message.address == 0x2f: + elif message.address == 0x13: dds_channel["ftw"][1] = message.data elif message.address == 0x31: dds_channel["pow"] = message.data @@ -273,8 +271,7 @@ class DDSHandler: logger.debug("DDS write @%d 0x%04x to 0x%02x, selected channels: %s", message.timestamp, message.data, message.address, self.selected_dds_channels) - if self.dds_type == "DDSChannelAD9914": - self._decode_ad9914_write(message) + self._decode_ad9914_write(message) class WishboneHandler: @@ -444,16 +441,17 @@ def get_vcd_log_channels(log_channel, messages): def get_single_device_argument(devices, module, cls, argument): - ref_period = None + found = None for desc in devices.values(): if isinstance(desc, dict) and desc["type"] == "local": if (desc["module"] == module and desc["class"] in cls): - if ref_period is None: - ref_period = desc["arguments"][argument] - else: - return None # more than one device found - return ref_period + value = desc["arguments"][argument] + if found is None: + found = value + elif value != found: + return None # more than one value/device found + return found def get_ref_period(devices): @@ -462,8 +460,8 @@ def get_ref_period(devices): def get_dds_sysclk(devices): - return get_single_device_argument(devices, "artiq.coredevice.dds", - ("DDSGroupAD9914",), "sysclk") + return get_single_device_argument(devices, "artiq.coredevice.ad9914", + ("ad9914",), "sysclk") def create_channel_handlers(vcd_manager, devices, ref_period, @@ -479,14 +477,12 @@ def create_channel_handlers(vcd_manager, devices, ref_period, and desc["class"] == "TTLClockGen"): channel = desc["arguments"]["channel"] channel_handlers[channel] = TTLClockGenHandler(vcd_manager, name, ref_period) - if (desc["module"] == "artiq.coredevice.dds" - and desc["class"] in {"DDSChannelAD9914"}): + if (desc["module"] == "artiq.coredevice.ad9914" + and desc["class"] == "AD9914"): dds_bus_channel = desc["arguments"]["bus_channel"] dds_channel = desc["arguments"]["channel"] if dds_bus_channel in channel_handlers: dds_handler = channel_handlers[dds_bus_channel] - if dds_handler.dds_type != desc["class"]: - raise ValueError("All DDS channels must have the same type") else: dds_handler = DDSHandler(vcd_manager, desc["class"], dds_onehot_sel, dds_sysclk) diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py deleted file mode 100644 index 5c7293edf..000000000 --- a/artiq/coredevice/dds.py +++ /dev/null @@ -1,401 +0,0 @@ -""" -Drivers for direct digital synthesis (DDS) chips on RTIO. - -Output event replacement is not supported and issuing commands at the same -time is an error. -""" - - -from artiq.language.core import * -from artiq.language.types import * -from artiq.language.units import * -from artiq.coredevice.rtio import rtio_output -from artiq.coredevice.exceptions import DDSError - -from numpy import int32, int64 - - -_PHASE_MODE_DEFAULT = -1 -PHASE_MODE_CONTINUOUS = 0 -PHASE_MODE_ABSOLUTE = 1 -PHASE_MODE_TRACKING = 2 - - -class DDSParams: - def __init__(self): - self.bus_channel = 0 - self.channel = 0 - self.ftw = 0 - self.pow = 0 - self.phase_mode = 0 - self.amplitude = 0 - - -class BatchContextManager: - kernel_invariants = {"core", "core_dds", "params"} - - def __init__(self, core_dds): - self.core_dds = core_dds - self.core = self.core_dds.core - self.active = False - self.params = [DDSParams() for _ in range(16)] - self.count = 0 - self.ref_time = int64(0) - - @kernel - def __enter__(self): - """Starts a DDS command batch. All DDS commands are buffered - after this call, until ``batch_exit`` is called. - - The time of execution of the DDS commands is the time cursor position - when the batch is entered.""" - if self.active: - raise DDSError("DDS batch entered twice") - - self.active = True - self.count = 0 - self.ref_time = now_mu() - - @kernel - def append(self, bus_channel, channel, ftw, pow, phase_mode, amplitude): - if self.count == len(self.params): - raise DDSError("Too many commands in DDS batch") - - params = self.params[self.count] - params.bus_channel = bus_channel - params.channel = channel - params.ftw = ftw - params.pow = pow - params.phase_mode = phase_mode - params.amplitude = amplitude - self.count += 1 - - @kernel - def __exit__(self, type, value, traceback): - """Ends a DDS command batch. All buffered DDS commands are issued - on the bus.""" - if not self.active: - raise DDSError("DDS batch exited twice") - - self.active = False - at_mu(self.ref_time - self.core_dds.batch_duration_mu()) - for i in range(self.count): - param = self.params[i] - self.core_dds.program(self.ref_time, - param.bus_channel, param.channel, param.ftw, - param.pow, param.phase_mode, param.amplitude) - - -class DDSGroup: - """Core device Direct Digital Synthesis (DDS) driver. - - Gives access to the DDS functionality of the core device. - - :param sysclk: DDS system frequency. The DDS system clock must be a - phase-locked multiple of the RTIO clock. - """ - - kernel_invariants = {"core", "sysclk", "batch"} - - def __init__(self, dmgr, sysclk, core_device="core"): - self.core = dmgr.get(core_device) - self.sysclk = sysclk - self.batch = BatchContextManager(self) - - @kernel - def batch_duration_mu(self): - raise NotImplementedError - - @kernel - def init(self, bus_channel, channel): - raise NotImplementedError - - @kernel - def program(self, ref_time, bus_channel, channel, ftw, pow, phase_mode, amplitude): - raise NotImplementedError - - @kernel - def set(self, bus_channel, channel, ftw, pow, phase_mode, amplitude): - if self.batch.active: - self.batch.append(bus_channel, channel, ftw, pow, phase_mode, amplitude) - else: - ref_time = now_mu() - at_mu(ref_time - self.program_duration_mu) - self.program(ref_time, - bus_channel, channel, ftw, pow, phase_mode, amplitude) - - @portable(flags={"fast-math"}) - def frequency_to_ftw(self, frequency): - """Returns the frequency tuning word corresponding to the given - frequency. - """ - return round(float(int64(2)**32*frequency/self.sysclk)) - - @portable(flags={"fast-math"}) - def ftw_to_frequency(self, ftw): - """Returns the frequency corresponding to the given frequency tuning - word. - """ - return ftw*self.sysclk/int64(2)**32 - - @portable(flags={"fast-math"}) - def turns_to_pow(self, turns): - """Returns the phase offset word corresponding to the given phase - in turns.""" - return round(float(turns*2**self.pow_width)) - - @portable(flags={"fast-math"}) - def pow_to_turns(self, pow): - """Returns the phase in turns corresponding to the given phase offset - word.""" - return pow/2**self.pow_width - - @portable(flags={"fast-math"}) - def amplitude_to_asf(self, amplitude): - """Returns amplitude scale factor corresponding to given amplitude.""" - return round(float(amplitude*0x0fff)) - - @portable(flags={"fast-math"}) - def asf_to_amplitude(self, asf): - """Returns the amplitude corresponding to the given amplitude scale - factor.""" - return asf/0x0fff - - -class DDSChannel: - """Core device Direct Digital Synthesis (DDS) channel driver. - - Controls one DDS channel managed directly by the core device's runtime. - - This class should not be used directly, instead, use the chip-specific - drivers such as ``DDSChannelAD9914``. - - The time cursor is not modified by any function in this class. - - :param bus: name of the DDS bus device that this DDS is connected to. - :param channel: channel number of the DDS device to control. - """ - - kernel_invariants = { - "core", "core_dds", "bus_channel", "channel", - } - - def __init__(self, dmgr, bus_channel, channel, core_dds_device="core_dds"): - self.core_dds = dmgr.get(core_dds_device) - self.core = self.core_dds.core - self.bus_channel = bus_channel - self.channel = channel - self.phase_mode = PHASE_MODE_CONTINUOUS - - @kernel - def init(self): - """Resets and initializes the DDS channel. - - This needs to be done for each DDS channel before it can be used, and - it is recommended to use the startup kernel for this. - - This function cannot be used in a batch; the correct way of - initializing multiple DDS channels is to call this function - sequentially with a delay between the calls. 2ms provides a good - timing margin.""" - self.core_dds.init(self.bus_channel, self.channel) - - @kernel - def set_phase_mode(self, phase_mode): - """Sets the phase mode of the DDS channel. Supported phase modes are: - - * ``PHASE_MODE_CONTINUOUS``: the phase accumulator is unchanged when - switching frequencies. The DDS phase is the sum of the phase - accumulator and the phase offset. The only discrete jumps in the - DDS output phase come from changes to the phase offset. - - * ``PHASE_MODE_ABSOLUTE``: the phase accumulator is reset when - switching frequencies. Thus, the phase of the DDS at the time of - the frequency change is equal to the phase offset. - - * ``PHASE_MODE_TRACKING``: when switching frequencies, the phase - accumulator is set to the value it would have if the DDS had been - running at the specified frequency since the start of the - experiment. - """ - self.phase_mode = phase_mode - - @kernel - def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT, - amplitude=0x0fff): - """Sets the DDS channel to the specified frequency and phase. - - This uses machine units (FTW and POW). The frequency tuning word width - is 32, whereas the phase offset word width depends on the type of DDS - chip and can be retrieved via the ``pow_width`` attribute. The amplitude - width is 12. - - The "frequency update" pulse is sent to the DDS with a fixed latency - with respect to the current position of the time cursor. - - :param frequency: frequency to generate. - :param phase: adds an offset, in turns, to the phase. - :param phase_mode: if specified, overrides the default phase mode set - by ``set_phase_mode`` for this call. - """ - if phase_mode == _PHASE_MODE_DEFAULT: - phase_mode = self.phase_mode - self.core_dds.set(self.bus_channel, self.channel, frequency, phase, phase_mode, amplitude) - - @kernel - def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, - amplitude=1.0): - """Like ``set_mu``, but uses Hz and turns.""" - self.set_mu(self.core_dds.frequency_to_ftw(frequency), - self.core_dds.turns_to_pow(phase), phase_mode, - self.core_dds.amplitude_to_asf(amplitude)) - - -AD9914_REG_CFR1L = 0x01 -AD9914_REG_CFR1H = 0x03 -AD9914_REG_CFR2L = 0x05 -AD9914_REG_CFR2H = 0x07 -AD9914_REG_CFR3L = 0x09 -AD9914_REG_CFR3H = 0x0b -AD9914_REG_CFR4L = 0x0d -AD9914_REG_CFR4H = 0x0f -AD9914_REG_FTWL = 0x2d -AD9914_REG_FTWH = 0x2f -AD9914_REG_POW = 0x31 -AD9914_REG_ASF = 0x33 -AD9914_REG_USR0 = 0x6d -AD9914_FUD = 0x80 -AD9914_GPIO = 0x81 - - -class DDSGroupAD9914(DDSGroup): - """Driver for AD9914 DDS chips. See ``DDSGroup`` for a description - of the functionality.""" - kernel_invariants = DDSGroup.kernel_invariants.union({ - "pow_width", "rtio_period_mu", "sysclk_per_mu", "write_duration_mu", "dac_cal_duration_mu", - "init_duration_mu", "init_sync_duration_mu", "program_duration_mu", - "first_dds_bus_channel", "dds_channel_count", "continuous_phase_comp" - }) - - pow_width = 16 - - def __init__(self, *args, first_dds_bus_channel, dds_bus_count, dds_channel_count, **kwargs): - super().__init__(*args, **kwargs) - - self.first_dds_bus_channel = first_dds_bus_channel - self.dds_bus_count = dds_bus_count - self.dds_channel_count = dds_channel_count - - self.rtio_period_mu = int64(8) - self.sysclk_per_mu = int32(self.sysclk * self.core.ref_period) - - self.write_duration_mu = 5 * self.rtio_period_mu - self.dac_cal_duration_mu = 147000 * self.rtio_period_mu - self.init_duration_mu = 8 * self.write_duration_mu + self.dac_cal_duration_mu - self.init_sync_duration_mu = 16 * self.write_duration_mu + 2 * self.dac_cal_duration_mu - self.program_duration_mu = 6 * self.write_duration_mu - - self.continuous_phase_comp = [0] * (self.dds_bus_count * self.dds_channel_count) - - @kernel - def batch_duration_mu(self): - return self.batch.count * (self.program_duration_mu + - self.write_duration_mu) # + FUD time - - @kernel - def write(self, bus_channel, addr, data): - rtio_output(now_mu(), bus_channel, addr, data) - delay_mu(self.write_duration_mu) - - @kernel - def init(self, bus_channel, channel): - delay_mu(-self.init_duration_mu) - self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1); - - self.write(bus_channel, AD9914_REG_CFR1H, 0x0000) # Enable cosine output - self.write(bus_channel, AD9914_REG_CFR2L, 0x8900) # Enable matched latency - self.write(bus_channel, AD9914_REG_CFR2H, 0x0080) # Enable profile mode - self.write(bus_channel, AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum - self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - delay_mu(self.dac_cal_duration_mu) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - - @kernel - def init_sync(self, bus_channel, channel, sync_delay): - delay_mu(-self.init_sync_duration_mu) - self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1) - - self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - delay_mu(self.dac_cal_duration_mu) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - self.write(bus_channel, AD9914_REG_CFR2L, 0x8b00) # Enable matched latency and sync_out - self.write(bus_channel, AD9914_FUD, 0) - # Set cal with sync and set sync_out and sync_in delay - self.write(bus_channel, AD9914_REG_USR0, 0x0840 | (sync_delay & 0x3f)) - self.write(bus_channel, AD9914_FUD, 0) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0105) # Enable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - delay_mu(self.dac_cal_duration_mu) - self.write(bus_channel, AD9914_REG_CFR4H, 0x0005) # Disable DAC calibration - self.write(bus_channel, AD9914_FUD, 0) - self.write(bus_channel, AD9914_REG_CFR1H, 0x0000) # Enable cosine output - self.write(bus_channel, AD9914_REG_CFR2H, 0x0080) # Enable profile mode - self.write(bus_channel, AD9914_REG_ASF, 0x0fff) # Set amplitude to maximum - self.write(bus_channel, AD9914_FUD, 0) - - @kernel - def program(self, ref_time, bus_channel, channel, ftw, pow, phase_mode, amplitude): - self.write(bus_channel, AD9914_GPIO, (1 << channel) << 1) - - self.write(bus_channel, AD9914_REG_FTWL, ftw & 0xffff) - self.write(bus_channel, AD9914_REG_FTWH, (ftw >> 16) & 0xffff) - - # We need the RTIO fine timestamp clock to be phase-locked - # to DDS SYSCLK, and divided by an integer self.sysclk_per_mu. - dds_bus_index = bus_channel - self.first_dds_bus_channel - phase_comp_index = dds_bus_index * self.dds_channel_count + channel - if phase_mode == PHASE_MODE_CONTINUOUS: - # Do not clear phase accumulator on FUD - # Disable autoclear phase accumulator and enables OSK. - self.write(bus_channel, AD9914_REG_CFR1L, 0x0108) - pow += self.continuous_phase_comp[phase_comp_index] - else: - # Clear phase accumulator on FUD - # Enable autoclear phase accumulator and enables OSK. - self.write(bus_channel, AD9914_REG_CFR1L, 0x2108) - fud_time = now_mu() + 2 * self.write_duration_mu - pow -= int32((ref_time - fud_time) * self.sysclk_per_mu * ftw >> (32 - self.pow_width)) - if phase_mode == PHASE_MODE_TRACKING: - pow += int32(ref_time * self.sysclk_per_mu * ftw >> (32 - self.pow_width)) - self.continuous_phase_comp[phase_comp_index] = pow - - self.write(bus_channel, AD9914_REG_POW, pow) - self.write(bus_channel, AD9914_REG_ASF, amplitude) - self.write(bus_channel, AD9914_FUD, 0) - - -class DDSChannelAD9914(DDSChannel): - """Driver for AD9914 DDS chips. See ``DDSChannel`` for a description - of the functionality.""" - @kernel - def init_sync(self, sync_delay=0): - """Resets and initializes the DDS channel as well as configures - the AD9914 DDS for synchronisation. The synchronisation procedure - follows the steps outlined in the AN-1254 application note. - - This needs to be done for each DDS channel before it can be used, and - it is recommended to use the startup kernel for this. - - This function cannot be used in a batch; the correct way of - initializing multiple DDS channels is to call this function - sequentially with a delay between the calls. 10ms provides a good - timing margin. - - :param sync_delay: integer from 0 to 0x3f that sets the value of - SYNC_OUT (bits 3-5) and SYNC_IN (bits 0-2) delay ADJ bits. - """ - self.core_dds.init_sync(self.bus_channel, self.channel, sync_delay) diff --git a/artiq/coredevice/exceptions.py b/artiq/coredevice/exceptions.py index f0ce65291..8264c7a55 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -102,13 +102,6 @@ class DMAError(Exception): artiq_builtin = True -class DDSError(Exception): - """Raised when attempting to start a DDS batch while already in a batch, - when too many commands are batched, and when DDS channel settings are - incorrect. - """ - - class WatchdogExpired(Exception): """Raised when a watchdog expires.""" diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 476be6b6a..d36807da3 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -215,13 +215,11 @@ def setup_from_ddb(ddb): force_out = v["class"] == "TTLOut" widget = _WidgetDesc(k, comment, _TTLWidget, (channel, force_out, k)) description.add(widget) - elif (v["module"] == "artiq.coredevice.dds" - and v["class"] == "DDSGroupAD9914"): - dds_sysclk = v["arguments"]["sysclk"] - elif (v["module"] == "artiq.coredevice.dds" - and v["class"] == "DDSChannelAD9914"): + elif (v["module"] == "artiq.coredevice.ad9914" + and v["class"] == "AD9914"): bus_channel = v["arguments"]["bus_channel"] channel = v["arguments"]["channel"] + dds_sysclk = v["arguments"]["sysclk"] widget = _WidgetDesc(k, comment, _DDSWidget, (bus_channel, channel, k)) description.add(widget) elif ( (v["module"] == "artiq.coredevice.ad53xx" and v["class"] == "AD53XX") diff --git a/artiq/examples/kc705_nist_clock/device_db.py b/artiq/examples/kc705_nist_clock/device_db.py index b51a330c9..78b21e82d 100644 --- a/artiq/examples/kc705_nist_clock/device_db.py +++ b/artiq/examples/kc705_nist_clock/device_db.py @@ -27,17 +27,6 @@ device_db = { "module": "artiq.coredevice.dma", "class": "CoreDMA" }, - "core_dds": { - "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSGroupAD9914", - "arguments": { - "sysclk": 3e9, - "first_dds_bus_channel": 39, - "dds_bus_count": 2, - "dds_channel_count": 3 - } - }, "i2c_switch": { "type": "local", @@ -333,22 +322,22 @@ device_db = { # AD9914 DDS "dds0": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 0}, + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 1} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 1} }, "dds2": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 2} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 2} }, # Aliases diff --git a/artiq/examples/kc705_nist_clock/repository/dds_setter.py b/artiq/examples/kc705_nist_clock/repository/dds_setter.py index ef13b1bd3..c5490d6b2 100644 --- a/artiq/examples/kc705_nist_clock/repository/dds_setter.py +++ b/artiq/examples/kc705_nist_clock/repository/dds_setter.py @@ -14,8 +14,8 @@ class DDSSetter(EnvExperiment): for k, v in sorted(device_db.items(), key=itemgetter(0)): if (isinstance(v, dict) and v["type"] == "local" - and v["module"] == "artiq.coredevice.dds" - and v["class"] in {"DDSChannelAD9914"}): + and v["module"] == "artiq.coredevice.ad9914" + and v["class"] == "AD9914"): self.dds[k] = { "driver": self.get_device(k), "frequency": self.get_argument( diff --git a/artiq/examples/kc705_nist_clock/repository/dds_test.py b/artiq/examples/kc705_nist_clock/repository/dds_test.py index ec57f9e52..5f93b2bc1 100644 --- a/artiq/examples/kc705_nist_clock/repository/dds_test.py +++ b/artiq/examples/kc705_nist_clock/repository/dds_test.py @@ -6,7 +6,6 @@ class DDSTest(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("core_dds") self.setattr_device("dds0") self.setattr_device("dds1") self.setattr_device("dds2") @@ -19,9 +18,9 @@ class DDSTest(EnvExperiment): def run(self): self.core.reset() delay(200*us) - with self.core_dds.batch: - self.dds1.set(120*MHz) - self.dds2.set(200*MHz) + self.dds1.set(120*MHz) + delay(10*us) + self.dds2.set(200*MHz) delay(1*us) for i in range(10000): diff --git a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py index f58a59a10..6d860db0e 100644 --- a/artiq/examples/kc705_nist_clock/repository/photon_histogram.py +++ b/artiq/examples/kc705_nist_clock/repository/photon_histogram.py @@ -6,7 +6,6 @@ class PhotonHistogram(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("core_dds") self.setattr_device("bd_dds") self.setattr_device("bd_sw") self.setattr_device("bdd_dds") @@ -22,9 +21,10 @@ class PhotonHistogram(EnvExperiment): @kernel def program_cooling(self): - with self.core_dds.batch: - self.bd_dds.set(200*MHz) - self.bdd_dds.set(300*MHz) + delay_mu(-self.bd_dds.set_duration_mu) + self.bd_dds.set(200*MHz) + delay_mu(self.bd_dds.set_duration_mu) + self.bdd_dds.set(300*MHz) @kernel def cool_detect(self): diff --git a/artiq/examples/master/device_db.py b/artiq/examples/master/device_db.py index 9150e2b0a..69ed74c8f 100644 --- a/artiq/examples/master/device_db.py +++ b/artiq/examples/master/device_db.py @@ -28,17 +28,6 @@ device_db = { "module": "artiq.coredevice.dma", "class": "CoreDMA" }, - "core_dds": { - "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSGroupAD9914", - "arguments": { - "sysclk": 3e9, - "first_dds_bus_channel": 39, - "dds_bus_count": 2, - "dds_channel_count": 3 - } - }, "i2c_switch": { "type": "local", @@ -334,22 +323,22 @@ device_db = { # AD9914 DDS "dds0": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 0}, + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 1} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 1} }, "dds2": { "type": "local", - "module": "artiq.coredevice.dds", - "class": "DDSChannelAD9914", - "arguments": {"bus_channel": 39, "channel": 2} + "module": "artiq.coredevice.ad9914", + "class": "AD9914", + "arguments": {"sysclk": 3e9, "bus_channel": 39, "channel": 2} }, # Aliases diff --git a/artiq/gateware/rtio/phy/dds.py b/artiq/gateware/rtio/phy/dds.py index d0c58ccfa..7e5011bd4 100644 --- a/artiq/gateware/rtio/phy/dds.py +++ b/artiq/gateware/rtio/phy/dds.py @@ -4,8 +4,8 @@ from artiq.gateware import ad9_dds from artiq.gateware.rtio.phy.wishbone import RT2WB -class _AD9_DDS(Module): - def __init__(self, ftw_base, pads, nchannels, onehot=False, **kwargs): +class AD9914(Module): + def __init__(self, pads, nchannels, onehot=False, **kwargs): self.submodules._ll = ClockDomainsRenamer("rio_phy")( ad9_dds.AD9_DDS(pads, **kwargs)) self.submodules._rt2wb = RT2WB(len(pads.a)+1, self._ll.bus) @@ -38,13 +38,13 @@ class _AD9_DDS(Module): if len(pads.d) == 8: self.sync.rio_phy += \ If(selected(c), [ - If(current_address == ftw_base+i, + If(current_address == 0x11+i, ftw[i*8:(i+1)*8].eq(current_data)) for i in range(4)]) elif len(pads.d) == 16: self.sync.rio_phy += \ If(selected(c), [ - If(current_address == ftw_base+2*i, + If(current_address == 0x11+2*i, ftw[i*16:(i+1)*16].eq(current_data)) for i in range(2)]) else: @@ -54,8 +54,3 @@ class _AD9_DDS(Module): self.sync.rio_phy += If(current_address == 2**len(pads.a), [ If(selected(c), probe.eq(ftw)) for c, (probe, ftw) in enumerate(zip(self.probes, ftws))]) - - -class AD9914(_AD9_DDS): - def __init__(self, *args, **kwargs): - _AD9_DDS.__init__(self, 0x2d, *args, **kwargs) diff --git a/artiq/test/coredevice/test_rtio.py b/artiq/test/coredevice/test_rtio.py index 371c5eb18..4069e046a 100644 --- a/artiq/test/coredevice/test_rtio.py +++ b/artiq/test/coredevice/test_rtio.py @@ -127,7 +127,6 @@ class PulseRate(EnvExperiment): class PulseRateDDS(EnvExperiment): def build(self): self.setattr_device("core") - self.setattr_device("core_dds") self.setattr_device("dds0") self.setattr_device("dds1") @@ -135,14 +134,15 @@ class PulseRateDDS(EnvExperiment): def run(self): self.core.reset() dt = self.core.seconds_to_mu(5*us) - freq = self.core_dds.frequency_to_ftw(100*MHz) + freq = self.dds0.frequency_to_ftw(100*MHz) while True: delay(10*ms) for i in range(1250): try: - with self.core_dds.batch: - self.dds0.set_mu(freq) - self.dds1.set_mu(freq) + delay_mu(-self.dds0.set_duration_mu) + self.dds0.set_mu(freq) + delay_mu(self.dds0.set_duration_mu) + self.dds1.set_mu(freq) delay_mu(dt) except RTIOUnderflow: dt += 100 diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index c54a44c0d..6bce75560 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -75,16 +75,22 @@ RF generation drivers .. automodule:: artiq.coredevice.urukul :members: +:mod:`artiq.coredevice.ad9910` module ++++++++++++++++++++++++++++++++++++++ + +.. automodule:: artiq.coredevice.ad9910 + :members: + :mod:`artiq.coredevice.ad9912` module +++++++++++++++++++++++++++++++++++++ .. automodule:: artiq.coredevice.ad9912 :members: -:mod:`artiq.coredevice.ad9910` module -+++++++++++++++++++++++++++++++++++++ +:mod:`artiq.coredevice.ad9914` module +++++++++++++++++++++++++++++++++++ -.. automodule:: artiq.coredevice.ad9910 +.. automodule:: artiq.coredevice.ad9914 :members: :mod:`artiq.coredevice.spline` module @@ -99,12 +105,6 @@ RF generation drivers .. automodule:: artiq.coredevice.sawg :members: -:mod:`artiq.coredevice.dds` module -++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.dds - :members: - DAC/ADC drivers --------------- diff --git a/doc/manual/rtio.rst b/doc/manual/rtio.rst index 33c03c10f..1abdd25a3 100644 --- a/doc/manual/rtio.rst +++ b/doc/manual/rtio.rst @@ -76,7 +76,7 @@ The sequence is exactly equivalent to:: ttl.pulse(2*us) -The :meth:`artiq.coredevice.ttl.TTLOut.pulse` method advances the timeline cursor (using ``delay()``) while other methods such as :meth:`artiq.coredevice.ttl.TTLOut.on`, :meth:`artiq.coredevice.ttl.TTLOut.off`, :meth:`artiq.coredevice.dds._DDSGeneric.set`. The latter are called *zero-duration* methods. +The :meth:`artiq.coredevice.ttl.TTLOut.pulse` method advances the timeline cursor (using ``delay()``) while other methods such as :meth:`artiq.coredevice.ttl.TTLOut.on`, :meth:`artiq.coredevice.ttl.TTLOut.off`, :meth:`artiq.coredevice.ad9914.set`. The latter are called *zero-duration* methods. Underflow exceptions --------------------