From f4b76667689dee7c593bed0252f27b76f2e88c7b Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 21 Nov 2016 11:55:44 +0000 Subject: [PATCH] coredevice.dds: reimplement fully in ARTIQ Python. This commit also drops AD9858 support from software. --- artiq/coredevice/analyzer.py | 37 +- artiq/coredevice/dds.py | 359 +++++++++++++----- artiq/coredevice/exceptions.py | 1 - artiq/dashboard/moninj.py | 4 +- artiq/examples/master/device_db.pyon | 15 +- .../master/repository/utilities/dds_setter.py | 2 +- artiq/gateware/targets/kc705.py | 1 - artiq/gateware/targets/pipistrello.py | 1 - artiq/runtime/Makefile | 2 +- artiq/runtime/dds.c | 263 ------------- artiq/runtime/dds.h | 70 ---- 11 files changed, 276 insertions(+), 479 deletions(-) delete mode 100644 artiq/runtime/dds.c delete mode 100644 artiq/runtime/dds.h diff --git a/artiq/coredevice/analyzer.py b/artiq/coredevice/analyzer.py index 6540a4acc..d98016a5b 100644 --- a/artiq/coredevice/analyzer.py +++ b/artiq/coredevice/analyzer.py @@ -182,10 +182,7 @@ class DDSHandler: self.vcd_manager.get_channel("dds/" + name + "/frequency", 64) dds_channel["vcd_phase"] = \ self.vcd_manager.get_channel("dds/" + name + "/phase", 64) - if self.dds_type == "AD9858": - dds_channel["ftw"] = [None, None, None, None] - dds_channel["pow"] = [None, None] - elif self.dds_type == "AD9914": + if self.dds_type == "DDSChannelAD9914": dds_channel["ftw"] = [None, None] dds_channel["pow"] = None self.dds_channels[dds_channel_nr] = dds_channel @@ -205,26 +202,6 @@ class DDSHandler: else: return {gpio} - def _decode_ad9858_write(self, message): - if message.address == 0x41: - 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 in range(0x0a, 0x0e): - dds_channel["ftw"][message.address - 0x0a] = message.data - elif message.address in range(0x0e, 0x10): - dds_channel["pow"][message.address - 0x0e] = message.data - elif message.address == 0x40: # FUD - if None not in dds_channel["ftw"]: - ftw = sum(x << i*8 - for i, x in enumerate(dds_channel["ftw"])) - frequency = ftw*self.sysclk/2**32 - dds_channel["vcd_frequency"].set_value_double(frequency) - if None not in dds_channel["pow"]: - pow = dds_channel["pow"][0] | (dds_channel["pow"][1] & 0x3f) << 8 - phase = pow/2**14 - dds_channel["vcd_phase"].set_value_double(phase) - def _decode_ad9914_write(self, message): if message.address == 0x81: self.selected_dds_channels = self._gpio_to_channels(message.data) @@ -251,9 +228,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 == "AD9858": - self._decode_ad9858_write(message) - elif self.dds_type == "AD9914": + if self.dds_type == "DDSChannelAD9914": self._decode_ad9914_write(message) @@ -312,7 +287,7 @@ def get_single_device_argument(devices, module, cls, argument): for desc in devices.values(): if isinstance(desc, dict) and desc["type"] == "local": if (desc["module"] == module - and desc["class"] == cls): + and desc["class"] in cls): if ref_period is None: ref_period = desc["arguments"][argument] else: @@ -322,12 +297,12 @@ def get_single_device_argument(devices, module, cls, argument): def get_ref_period(devices): return get_single_device_argument(devices, "artiq.coredevice.core", - "Core", "ref_period") + ("Core",), "ref_period") def get_dds_sysclk(devices): return get_single_device_argument(devices, "artiq.coredevice.dds", - "CoreDDS", "sysclk") + ("DDSGroupAD9914",), "sysclk") def create_channel_handlers(vcd_manager, devices, ref_period, @@ -344,7 +319,7 @@ def create_channel_handlers(vcd_manager, devices, ref_period, channel = desc["arguments"]["channel"] channel_handlers[channel] = TTLClockGenHandler(vcd_manager, name, ref_period) if (desc["module"] == "artiq.coredevice.dds" - and desc["class"] in {"AD9858", "AD9914"}): + and desc["class"] in {"DDSChannelAD9914"}): dds_bus_channel = desc["arguments"]["bus_channel"] dds_channel = desc["arguments"]["channel"] if dds_bus_channel in channel_handlers: diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index 1437ff2df..a6d9c2dd1 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -1,56 +1,84 @@ from artiq.language.core import * from artiq.language.types import * from artiq.language.units import * -from numpy import int64 +from artiq.coredevice.rtio import rtio_output +from artiq.coredevice.exceptions import DDSError + +from numpy import int32, int64 -_PHASE_MODE_DEFAULT = -1 -# keep in sync with dds.h +_PHASE_MODE_DEFAULT = -1 PHASE_MODE_CONTINUOUS = 0 -PHASE_MODE_ABSOLUTE = 1 -PHASE_MODE_TRACKING = 2 +PHASE_MODE_ABSOLUTE = 1 +PHASE_MODE_TRACKING = 2 -@syscall(flags={"nowrite"}) -def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_init_sync(time_mu: TInt64, bus_channel: TInt32, - channel: TInt32, sync_delay: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32, - pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_batch_enter(time_mu: TInt64) -> TNone: - raise NotImplementedError("syscall not simulated") - -@syscall(flags={"nowrite"}) -def dds_batch_exit() -> TNone: - raise NotImplementedError("syscall not simulated") +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"} +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.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): - self.core_dds.dds_batch_enter() + """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): - self.core_dds.dds_batch_exit() + """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 CoreDDS: +class DDSGroup: """Core device Direct Digital Synthesis (DDS) driver. Gives access to the DDS functionality of the core device. @@ -62,33 +90,77 @@ class CoreDDS: kernel_invariants = {"core", "sysclk", "batch"} def __init__(self, dmgr, sysclk, core_device="core"): - self.core = dmgr.get(core_device) + self.core = dmgr.get(core_device) self.sysclk = sysclk - self.batch = _BatchContextManager(self) + self.batch = BatchContextManager(self) @kernel - def dds_batch_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.""" - dds_batch_enter(now_mu()) + def batch_duration_mu(self): + raise NotImplementedError @kernel - def dds_batch_exit(self): - """Ends a DDS command batch. All buffered DDS commands are issued - on the bus.""" - dds_batch_exit() + 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 _DDSGeneric: +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 ``AD9858`` and ``AD9914``. + drivers such as ``DDSChannelAD9914``. The time cursor is not modified by any function in this class. @@ -97,52 +169,15 @@ class _DDSGeneric: """ kernel_invariants = { - "core", "core_dds", "bus_channel", "channel", "pow_width" + "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.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 - - @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.core_dds.sysclk)) - - @portable(flags=["fast-math"]) - def ftw_to_frequency(self, ftw): - """Returns the frequency corresponding to the given frequency tuning - word. - """ - return ftw*self.core_dds.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 + self.channel = channel + self.phase_mode = PHASE_MODE_CONTINUOUS @kernel def init(self): @@ -155,7 +190,7 @@ class _DDSGeneric: initializing multiple DDS channels is to call this function sequentially with a delay between the calls. 2ms provides a good timing margin.""" - dds_init(now_mu(), self.bus_channel, self.channel) + self.core_dds.init(self.bus_channel, self.channel) @kernel def set_phase_mode(self, phase_mode): @@ -197,29 +232,147 @@ class _DDSGeneric: """ if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode - dds_set(now_mu(), self.bus_channel, self.channel, - frequency, phase, phase_mode, amplitude) + 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.frequency_to_ftw(frequency), - self.turns_to_pow(phase), phase_mode, - self.amplitude_to_asf(amplitude)) + 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)) -class AD9858(_DDSGeneric): - """Driver for AD9858 DDS chips. See ``_DDSGeneric`` for a description +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.""" - pow_width = 14 + 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" + }) - -class AD9914(_DDSGeneric): - """Driver for AD9914 DDS chips. See ``_DDSGeneric`` for a description - of the functionality.""" 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 @@ -237,4 +390,4 @@ class AD9914(_DDSGeneric): :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. """ - dds_init_sync(now_mu(), self.bus_channel, self.channel, sync_delay) + 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 9137a7ffe..5ba1c5f43 100644 --- a/artiq/coredevice/exceptions.py +++ b/artiq/coredevice/exceptions.py @@ -125,7 +125,6 @@ class DDSError(Exception): when too many commands are batched, and when DDS channel settings are incorrect. """ - artiq_builtin = True class I2CError(Exception): """Raised with a I2C transaction fails.""" diff --git a/artiq/dashboard/moninj.py b/artiq/dashboard/moninj.py index 22c0bb963..6baa31ade 100644 --- a/artiq/dashboard/moninj.py +++ b/artiq/dashboard/moninj.py @@ -219,10 +219,10 @@ class _DeviceManager: self.ttl_widgets[k] = widget self.ttl_cb() if (v["module"] == "artiq.coredevice.dds" - and v["class"] == "CoreDDS"): + and v["class"] == "DDSGroupAD9914"): self.dds_sysclk = v["arguments"]["sysclk"] if (v["module"] == "artiq.coredevice.dds" - and v["class"] in {"AD9858", "AD9914"}): + and v["class"] in {"DDSChannelAD9914"}): bus_channel = v["arguments"]["bus_channel"] channel = v["arguments"]["channel"] widget = _DDSWidget( diff --git a/artiq/examples/master/device_db.pyon b/artiq/examples/master/device_db.pyon index f5811ee34..5803a3e80 100644 --- a/artiq/examples/master/device_db.pyon +++ b/artiq/examples/master/device_db.pyon @@ -23,8 +23,13 @@ "core_dds": { "type": "local", "module": "artiq.coredevice.dds", - "class": "CoreDDS", - "arguments": {"sysclk": 3e9} + "class": "DDSGroupAD9914", + "arguments": { + "sysclk": 3e9, + "first_dds_bus_channel": 26, + "dds_bus_count": 2, + "dds_channel_count": 3 + } }, "i2c_switch": { @@ -136,20 +141,20 @@ "dds0": { "type": "local", "module": "artiq.coredevice.dds", - "class": "AD9914", + "class": "DDSChannelAD9914", "arguments": {"bus_channel": 26, "channel": 0}, "comment": "Comments work in DDS panel as well" }, "dds1": { "type": "local", "module": "artiq.coredevice.dds", - "class": "AD9914", + "class": "DDSChannelAD9914", "arguments": {"bus_channel": 26, "channel": 1} }, "dds2": { "type": "local", "module": "artiq.coredevice.dds", - "class": "AD9914", + "class": "DDSChannelAD9914", "arguments": {"bus_channel": 26, "channel": 2} }, diff --git a/artiq/examples/master/repository/utilities/dds_setter.py b/artiq/examples/master/repository/utilities/dds_setter.py index 1e8f4066d..ef13b1bd3 100644 --- a/artiq/examples/master/repository/utilities/dds_setter.py +++ b/artiq/examples/master/repository/utilities/dds_setter.py @@ -15,7 +15,7 @@ class DDSSetter(EnvExperiment): if (isinstance(v, dict) and v["type"] == "local" and v["module"] == "artiq.coredevice.dds" - and v["class"] in {"AD9858", "AD9914"}): + and v["class"] in {"DDSChannelAD9914"}): self.dds[k] = { "driver": self.get_device(k), "frequency": self.get_argument( diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py index b6b04461b..a70e33814 100755 --- a/artiq/gateware/targets/kc705.py +++ b/artiq/gateware/targets/kc705.py @@ -144,7 +144,6 @@ class _NIST_Ions(MiniSoC, AMPSoC): self.csr_devices.append("rtio_crg") self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") - self.config["RTIO_FINE_TS_WIDTH"] = self.rtio.fine_ts_width self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") diff --git a/artiq/gateware/targets/pipistrello.py b/artiq/gateware/targets/pipistrello.py index a0a5f0134..88c5fa017 100755 --- a/artiq/gateware/targets/pipistrello.py +++ b/artiq/gateware/targets/pipistrello.py @@ -225,7 +225,6 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd # RTIO logic self.submodules.rtio = rtio.RTIO(rtio_channels) self.register_kernel_cpu_csrdevice("rtio") - self.config["RTIO_FINE_TS_WIDTH"] = self.rtio.fine_ts_width self.config["DDS_RTIO_CLK_RATIO"] = 8 >> self.rtio.fine_ts_width self.submodules.rtio_moninj = rtio.MonInj(rtio_channels) self.csr_devices.append("rtio_moninj") diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index e8936fdf4..797123c2c 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -4,7 +4,7 @@ include $(MISOC_DIRECTORY)/software/common.mak PYTHON ?= python3.5 OBJECTS := flash_storage.o main.o -OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o dds.o i2c.o +OBJECTS_KSUPPORT := ksupport_glue.o artiq_personality.o rtio.o i2c.o RUSTOUT_DIRECTORY := cargo/or1k-unknown-none/debug CORE_IO_COMMIT := d40c593f42fafbac1ff3d827f6df96338b5b7d8b diff --git a/artiq/runtime/dds.c b/artiq/runtime/dds.c deleted file mode 100644 index 5b221ecf9..000000000 --- a/artiq/runtime/dds.c +++ /dev/null @@ -1,263 +0,0 @@ -#include - -#if ((defined CONFIG_RTIO_DDS_COUNT) && (CONFIG_RTIO_DDS_COUNT > 0)) - -#include - -#include "artiq_personality.h" -#include "rtio.h" -#include "dds.h" - -#define DURATION_WRITE (5 << CONFIG_RTIO_FINE_TS_WIDTH) - -#if defined CONFIG_DDS_AD9858 -/* Assume 8-bit bus */ -#define DURATION_INIT (7*DURATION_WRITE) /* not counting FUD */ -#define DURATION_PROGRAM (8*DURATION_WRITE) /* not counting FUD */ - -#elif defined CONFIG_DDS_AD9914 -/* Assume 16-bit bus */ -/* DAC calibration takes max. 1ms as per datasheet */ -#define DURATION_DAC_CAL (147000 << CONFIG_RTIO_FINE_TS_WIDTH) -/* not counting final FUD */ -#define DURATION_INIT (8*DURATION_WRITE + DURATION_DAC_CAL) -#define DURATION_INIT_SYNC (16*DURATION_WRITE + 2*DURATION_DAC_CAL) -#define DURATION_PROGRAM (6*DURATION_WRITE) /* not counting FUD */ - -#else -#error Unknown DDS configuration -#endif - -#define DDS_WRITE(addr, data) do { \ - rtio_output(now, bus_channel, addr, data); \ - now += DURATION_WRITE; \ - } while(0) - -void dds_init(long long int timestamp, int bus_channel, int channel) -{ - long long int now; - - now = timestamp - DURATION_INIT; - -#ifdef CONFIG_DDS_ONEHOT_SEL - channel = 1 << channel; -#endif - channel <<= 1; - DDS_WRITE(DDS_GPIO, channel); -#ifndef CONFIG_DDS_AD9914 - /* - * Resetting a AD9914 intermittently crashes it. It does not produce any - * output until power-cycled. - * Increasing the reset pulse length and the delay until the first write - * to 300ns do not solve the problem. - * The chips seem fine without a reset. - */ - DDS_WRITE(DDS_GPIO, channel | 1); /* reset */ - DDS_WRITE(DDS_GPIO, channel); -#endif - -#ifdef CONFIG_DDS_AD9858 - /* - * 2GHz divider disable - * SYNCLK disable - * Mixer power-down - * Phase detect power down - */ - DDS_WRITE(DDS_CFR0, 0x78); - DDS_WRITE(DDS_CFR1, 0x00); - DDS_WRITE(DDS_CFR2, 0x00); - DDS_WRITE(DDS_CFR3, 0x00); - DDS_WRITE(DDS_FUD, 0); -#endif - -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_CFR1H, 0x0000); /* Enable cosine output */ - DDS_WRITE(DDS_CFR2L, 0x8900); /* Enable matched latency */ - DDS_WRITE(DDS_CFR2H, 0x0080); /* Enable profile mode */ - DDS_WRITE(DDS_ASF, 0x0fff); /* Set amplitude to maximum */ - DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - now += DURATION_DAC_CAL; - DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); -#endif -} - -void dds_init_sync(long long int timestamp, int bus_channel, int channel, int sync_delay) -{ -#ifdef CONFIG_DDS_AD9914 - long long int now; - - now = timestamp - DURATION_INIT_SYNC; - -#ifdef CONFIG_DDS_ONEHOT_SEL - channel = 1 << channel; -#endif - channel <<= 1; - DDS_WRITE(DDS_GPIO, channel); - - DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - now += DURATION_DAC_CAL; - DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - DDS_WRITE(DDS_CFR2L, 0x8b00); /* Enable matched latency and sync_out*/ - DDS_WRITE(DDS_FUD, 0); - /* Set cal with sync and set sync_out and sync_in delay */ - DDS_WRITE(DDS_USR0, 0x0840 | (sync_delay & 0x3f)); - DDS_WRITE(DDS_FUD, 0); - DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - now += DURATION_DAC_CAL; - DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ - DDS_WRITE(DDS_FUD, 0); - DDS_WRITE(DDS_CFR1H, 0x0000); /* Enable cosine output */ - DDS_WRITE(DDS_CFR2H, 0x0080); /* Enable profile mode */ - DDS_WRITE(DDS_ASF, 0x0fff); /* Set amplitude to maximum */ - DDS_WRITE(DDS_FUD, 0); -#endif -} - -/* Compensation to keep phase continuity when switching from absolute or tracking - * to continuous phase mode. */ -static unsigned int continuous_phase_comp[CONFIG_RTIO_DDS_COUNT][CONFIG_DDS_CHANNELS_PER_BUS]; - -static void dds_set_one(long long int now, long long int ref_time, - int bus_channel, int channel, - unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude) -{ - unsigned int channel_enc; - - if((channel < 0) || (channel >= CONFIG_DDS_CHANNELS_PER_BUS)) - artiq_raise_from_c("DDSError", "Attempted to set invalid DDS channel", 0, 0, 0); - if((bus_channel < CONFIG_RTIO_FIRST_DDS_CHANNEL) - || (bus_channel >= (CONFIG_RTIO_FIRST_DDS_CHANNEL+CONFIG_RTIO_DDS_COUNT))) - artiq_raise_from_c("DDSError", "Attempted to use invalid DDS bus", 0, 0, 0); - -#ifdef CONFIG_DDS_ONEHOT_SEL - channel_enc = 1 << channel; -#else - channel_enc = channel; -#endif - DDS_WRITE(DDS_GPIO, channel_enc << 1); - -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_FTW0, ftw & 0xff); - DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff); - DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff); - DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff); -#endif - -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_FTWL, ftw & 0xffff); - DDS_WRITE(DDS_FTWH, (ftw >> 16) & 0xffff); -#endif - - /* We need the RTIO fine timestamp clock to be phase-locked - * to DDS SYSCLK, and divided by an integer CONFIG_DDS_RTIO_CLK_RATIO. - */ - if(phase_mode == PHASE_MODE_CONTINUOUS) { - /* Do not clear phase accumulator on FUD */ -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_CFR2, 0x00); -#endif -#ifdef CONFIG_DDS_AD9914 - /* Disable autoclear phase accumulator and enables OSK. */ - DDS_WRITE(DDS_CFR1L, 0x0108); -#endif - pow += continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel]; - } else { - long long int fud_time; - - /* Clear phase accumulator on FUD */ -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_CFR2, 0x40); -#endif -#ifdef CONFIG_DDS_AD9914 - /* Enable autoclear phase accumulator and enables OSK. */ - DDS_WRITE(DDS_CFR1L, 0x2108); -#endif - fud_time = now + 2*DURATION_WRITE; - pow -= (ref_time - fud_time)*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH); - if(phase_mode == PHASE_MODE_TRACKING) - pow += ref_time*CONFIG_DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH); - continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel] = pow; - } - -#ifdef CONFIG_DDS_AD9858 - DDS_WRITE(DDS_POW0, pow & 0xff); - DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f); -#endif -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_POW, pow); -#endif -#ifdef CONFIG_DDS_AD9914 - DDS_WRITE(DDS_ASF, amplitude); -#endif - DDS_WRITE(DDS_FUD, 0); -} - -struct dds_set_params { - int bus_channel; - int channel; - unsigned int ftw; - unsigned int pow; - int phase_mode; - unsigned int amplitude; -}; - -static int batch_mode; -static int batch_count; -static long long int batch_ref_time; -static struct dds_set_params batch[DDS_MAX_BATCH]; - -void dds_batch_enter(long long int timestamp) -{ - if(batch_mode) - artiq_raise_from_c("DDSError", "DDS batch entered twice", 0, 0, 0); - batch_mode = 1; - batch_count = 0; - batch_ref_time = timestamp; -} - -void dds_batch_exit(void) -{ - long long int now; - int i; - - if(!batch_mode) - artiq_raise_from_c("DDSError", "DDS batch exited twice", 0, 0, 0); - batch_mode = 0; - /* + FUD time */ - now = batch_ref_time - batch_count*(DURATION_PROGRAM + DURATION_WRITE); - for(i=0;i= DDS_MAX_BATCH) - artiq_raise_from_c("DDSError", "Too many commands in DDS batch", 0, 0, 0); - /* timestamp parameter ignored (determined by batch) */ - batch[batch_count].bus_channel = bus_channel; - batch[batch_count].channel = channel; - batch[batch_count].ftw = ftw; - batch[batch_count].pow = pow; - batch[batch_count].phase_mode = phase_mode; - batch[batch_count].amplitude = amplitude; - batch_count++; - } else { - dds_set_one(timestamp - DURATION_PROGRAM, timestamp, - bus_channel, channel, - ftw, pow, phase_mode, amplitude); - } -} - -#endif /* CONFIG_RTIO_DDS_COUNT */ diff --git a/artiq/runtime/dds.h b/artiq/runtime/dds.h deleted file mode 100644 index 8cca5cb74..000000000 --- a/artiq/runtime/dds.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef __DDS_H -#define __DDS_H - -#include -#include -#include - -#if ((defined CONFIG_RTIO_DDS_COUNT) && (CONFIG_RTIO_DDS_COUNT > 0)) - -/* Maximum number of commands in a batch */ -#define DDS_MAX_BATCH 16 - -#ifdef CONFIG_DDS_AD9858 -#define DDS_CFR0 0x00 -#define DDS_CFR1 0x01 -#define DDS_CFR2 0x02 -#define DDS_CFR3 0x03 -#define DDS_FTW0 0x0a -#define DDS_FTW1 0x0b -#define DDS_FTW2 0x0c -#define DDS_FTW3 0x0d -#define DDS_POW0 0x0e -#define DDS_POW1 0x0f -#define DDS_FUD 0x40 -#define DDS_GPIO 0x41 -#endif - -#ifdef CONFIG_DDS_AD9914 -#define DDS_CFR1L 0x01 -#define DDS_CFR1H 0x03 -#define DDS_CFR2L 0x05 -#define DDS_CFR2H 0x07 -#define DDS_CFR3L 0x09 -#define DDS_CFR3H 0x0b -#define DDS_CFR4L 0x0d -#define DDS_CFR4H 0x0f -#define DDS_FTWL 0x2d -#define DDS_FTWH 0x2f -#define DDS_POW 0x31 -#define DDS_ASF 0x33 -#define DDS_USR0 0x6d -#define DDS_FUD 0x80 -#define DDS_GPIO 0x81 -#endif - -#ifdef CONFIG_DDS_AD9858 -#define DDS_POW_WIDTH 14 -#endif - -#ifdef CONFIG_DDS_AD9914 -#define DDS_POW_WIDTH 16 -#endif - -enum { - PHASE_MODE_CONTINUOUS = 0, - PHASE_MODE_ABSOLUTE = 1, - PHASE_MODE_TRACKING = 2 -}; - -void dds_init(long long int timestamp, int bus_channel, int channel); -void dds_init_sync(long long int timestamp, int bus_channel, int channel, - int sync_delay); -void dds_batch_enter(long long int timestamp); -void dds_batch_exit(void); -void dds_set(long long int timestamp, int bus_channel, int channel, - unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude); - -#endif /* CONFIG_RTIO_DDS_COUNT */ - -#endif /* __DDS_H */