diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst
index 4c905ea5a..d675623d8 100644
--- a/RELEASE_NOTES.rst
+++ b/RELEASE_NOTES.rst
@@ -11,4 +11,8 @@ Release notes
This requires reflashing the runtime and the flash storage filesystem image
or erase and rewrite its entries.
* RTIOCollisionError has been renamed to RTIOCollision
-
\ No newline at end of file
+* the new API for DDS batches is:
+ with self.core_dds.batch:
+ ...
+ with core_dds a device of type artiq.coredevice.dds.CoreDDS.
+ The dds_bus device should not be used anymore.
diff --git a/artiq/coredevice/analyzer.py b/artiq/coredevice/analyzer.py
index b2b458bff..f526bb2ec 100644
--- a/artiq/coredevice/analyzer.py
+++ b/artiq/coredevice/analyzer.py
@@ -40,16 +40,19 @@ def decode_message(data):
DecodedDump = namedtuple(
- "DecodedDump", "log_channel dds_channel dds_onehot_sel messages")
+ "DecodedDump", "log_channel dds_onehot_sel messages")
def decode_dump(data):
- parts = struct.unpack(">IQbbbb", data[:16])
+ parts = struct.unpack(">IQbbb", data[:15])
(sent_bytes, total_byte_count,
- overflow_occured, log_channel, dds_channel, dds_onehot_sel) = parts
+ overflow_occured, log_channel, dds_onehot_sel) = parts
- if sent_bytes + 16 != len(data):
- raise ValueError("analyzer dump has incorrect length")
+ expected_len = sent_bytes + 15
+ if expected_len != len(data):
+ raise ValueError("analyzer dump has incorrect length "
+ "(got {}, expected {})".format(
+ len(data), expected_len))
if overflow_occured:
logger.warning("analyzer FIFO overflow occured, "
"some messages have been lost")
@@ -57,14 +60,12 @@ def decode_dump(data):
logger.info("analyzer ring buffer has wrapped %d times",
total_byte_count//sent_bytes)
- position = 16
+ position = 15
messages = []
for _ in range(sent_bytes//32):
messages.append(decode_message(data[position:position+32]))
position += 32
- return DecodedDump(log_channel,
- dds_channel, bool(dds_onehot_sel),
- messages)
+ return DecodedDump(log_channel, bool(dds_onehot_sel), messages)
def vcd_codes():
@@ -299,21 +300,31 @@ def get_vcd_log_channels(log_channel, messages):
return vcd_log_channels
-def get_ref_period(devices):
+def get_single_device_argument(devices, module, cls, argument):
ref_period = None
for desc in devices.values():
if isinstance(desc, dict) and desc["type"] == "local":
- if (desc["module"] == "artiq.coredevice.core"
- and desc["class"] == "Core"):
+ if (desc["module"] == module
+ and desc["class"] == cls):
if ref_period is None:
- ref_period = desc["arguments"]["ref_period"]
+ ref_period = desc["arguments"][argument]
else:
- return None # more than one core device found
+ return None # more than one device found
return ref_period
+def get_ref_period(devices):
+ return get_single_device_argument(devices, "artiq.coredevice.core",
+ "Core", "ref_period")
+
+
+def get_dds_sysclk(devices):
+ return get_single_device_argument(devices, "artiq.coredevice.core",
+ "CoreDDS", "sysclk")
+
+
def create_channel_handlers(vcd_manager, devices, ref_period,
- dds_channel, dds_onehot_sel):
+ dds_sysclk, dds_onehot_sel):
channel_handlers = dict()
for name, desc in sorted(devices.items(), key=itemgetter(0)):
if isinstance(desc, dict) and desc["type"] == "local":
@@ -327,19 +338,17 @@ def create_channel_handlers(vcd_manager, devices, ref_period,
channel_handlers[channel] = TTLClockGenHandler(vcd_manager, name, ref_period)
if (desc["module"] == "artiq.coredevice.dds"
and desc["class"] in {"AD9858", "AD9914"}):
- sysclk = desc["arguments"]["sysclk"]
- dds_channel_ddsbus = desc["arguments"]["channel"]
- if dds_channel in channel_handlers:
- dds_handler = channel_handlers[dds_channel]
+ 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")
- if dds_handler.sysclk != sysclk:
- raise ValueError("All DDS channels must have the same sysclk")
else:
dds_handler = DDSHandler(vcd_manager, desc["class"],
- dds_onehot_sel, sysclk)
- channel_handlers[dds_channel] = dds_handler
- dds_handler.add_dds_channel(name, dds_channel_ddsbus)
+ dds_sysclk, dds_onehot_sel)
+ channel_handlers[dds_bus_channel] = dds_handler
+ dds_handler.add_dds_channel(name, dds_channel)
return channel_handlers
@@ -355,12 +364,16 @@ def decoded_dump_to_vcd(fileobj, devices, dump):
else:
logger.warning("unable to determine core device ref_period")
ref_period = 1e-9 # guess
+ dds_sysclk = get_dds_sysclk(devices)
+ if dds_sysclk is None:
+ logger.warning("unable to determine DDS sysclk")
+ dds_sysclk = 3e9 # guess
messages = sorted(dump.messages, key=get_message_time)
channel_handlers = create_channel_handlers(
vcd_manager, devices, ref_period,
- dump.dds_channel, dump.dds_onehot_sel)
+ dds_sysclk, dump.dds_onehot_sel)
vcd_log_channels = get_vcd_log_channels(dump.log_channel, messages)
channel_handlers[dump.log_channel] = LogHandler(vcd_manager, vcd_log_channels)
slack = vcd_manager.get_channel("rtio_slack", 64)
diff --git a/artiq/coredevice/core.py b/artiq/coredevice/core.py
index 32c2501bd..7aa17fa9b 100644
--- a/artiq/coredevice/core.py
+++ b/artiq/coredevice/core.py
@@ -22,7 +22,7 @@ def _render_diagnostic(diagnostic, colored):
lines = [shorten_path(path) for path in diagnostic.render(colored=colored)]
return "\n".join(lines)
-colors_supported = (os.name == 'posix')
+colors_supported = os.name == "posix"
class _DiagnosticEngine(diagnostic.Engine):
def render_diagnostic(self, diagnostic):
sys.stderr.write(_render_diagnostic(diagnostic, colored=colors_supported) + "\n")
@@ -49,6 +49,7 @@ def cache_get(key: TStr) -> TList(TInt32):
def cache_put(key: TStr, value: TList(TInt32)) -> TNone:
raise NotImplementedError("syscall not simulated")
+
class Core:
"""Core device driver.
diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py
index 99cbc72af..622292476 100644
--- a/artiq/coredevice/dds.py
+++ b/artiq/coredevice/dds.py
@@ -11,7 +11,12 @@ PHASE_MODE_TRACKING = 2
@syscall
-def dds_init(time_mu: TInt64, channel: TInt32) -> TNone:
+def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone:
+ raise NotImplementedError("syscall not simulated")
+
+@syscall
+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
@@ -22,35 +27,36 @@ def dds_batch_enter(time_mu: TInt64) -> TNone:
def dds_batch_exit() -> TNone:
raise NotImplementedError("syscall not simulated")
-@syscall
-def dds_set(time_mu: TInt64, channel: TInt32, ftw: TInt32,
- pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone:
- raise NotImplementedError("syscall not simulated")
-
class _BatchContextManager:
- def __init__(self, dds_bus):
- self.dds_bus = dds_bus
+ def __init__(self, core_dds):
+ self.core_dds = core_dds
+ self.core = self.core_dds.core
@kernel
def __enter__(self):
- self.dds_bus.batch_enter()
+ self.core_dds.dds_batch_enter()
@kernel
def __exit__(self, type, value, traceback):
- self.dds_bus.batch_exit()
+ self.core_dds.dds_batch_exit()
-class DDSBus:
- """Core device Direct Digital Synthesis (DDS) bus batching driver.
+class CoreDDS:
+ """Core device Direct Digital Synthesis (DDS) driver.
- Manages batching of DDS commands on a DDS shared bus."""
- def __init__(self, dmgr):
- self.core = dmgr.get("core")
+ 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.
+ """
+ def __init__(self, dmgr, sysclk, core_device="core"):
+ self.core = dmgr.get(core_device)
+ self.sysclk = sysclk
self.batch = _BatchContextManager(self)
@kernel
- def batch_enter(self):
+ def dds_batch_enter(self):
"""Starts a DDS command batch. All DDS commands are buffered
after this call, until ``batch_exit`` is called.
@@ -59,26 +65,27 @@ class DDSBus:
dds_batch_enter(now_mu())
@kernel
- def batch_exit(self):
+ def dds_batch_exit(self):
"""Ends a DDS command batch. All buffered DDS commands are issued
on the bus."""
dds_batch_exit()
class _DDSGeneric:
- """Core device Direct Digital Synthesis (DDS) driver.
+ """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``.
- :param sysclk: DDS system frequency.
+ :param bus: name of the DDS bus device that this DDS is connected to.
:param channel: channel number of the DDS device to control.
"""
- def __init__(self, dmgr, sysclk, channel):
- self.core = dmgr.get("core")
- self.sysclk = sysclk
+ 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
@@ -87,14 +94,14 @@ class _DDSGeneric:
"""Returns the frequency tuning word corresponding to the given
frequency.
"""
- return round(int(2, width=64)**32*frequency/self.sysclk)
+ return round(int(2, width=64)**32*frequency/self.core_dds.sysclk)
@portable
def ftw_to_frequency(self, ftw):
"""Returns the frequency corresponding to the given frequency tuning
word.
"""
- return ftw*self.sysclk/int(2, width=64)**32
+ return ftw*self.core_dds.sysclk/int(2, width=64)**32
@portable
def turns_to_pow(self, turns):
@@ -124,7 +131,7 @@ class _DDSGeneric:
"""Resets and initializes the DDS channel.
The runtime does this for all channels upon core device startup."""
- dds_init(now_mu(), self.channel)
+ dds_init(now_mu(), self.bus_channel, self.channel)
@kernel
def set_phase_mode(self, phase_mode):
@@ -163,7 +170,8 @@ class _DDSGeneric:
"""
if phase_mode == _PHASE_MODE_DEFAULT:
phase_mode = self.phase_mode
- dds_set(now_mu(), self.channel, frequency, phase, phase_mode, amplitude)
+ dds_set(now_mu(), self.bus_channel, self.channel,
+ frequency, phase, phase_mode, amplitude)
@kernel
def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT,
diff --git a/artiq/gateware/rtio/core.py b/artiq/gateware/rtio/core.py
index cdc36598d..0ceccab4a 100644
--- a/artiq/gateware/rtio/core.py
+++ b/artiq/gateware/rtio/core.py
@@ -130,24 +130,27 @@ class _OutputManager(Module):
collision = Signal()
any_error = Signal()
nop = Signal()
- self.sync.rsys += [
+ if interface.enable_replace:
# Note: replace may be asserted at the same time as collision
# when addresses are different. In that case, it is a collision.
- replace.eq(self.ev.timestamp == buf.timestamp),
+ self.sync.rsys += replace.eq(self.ev.timestamp == buf.timestamp)
# Detect sequence errors on coarse timestamps only
# so that they are mutually exclusive with collision errors.
- sequence_error.eq(self.ev.timestamp[fine_ts_width:]
- < buf.timestamp[fine_ts_width:])
- ]
- if hasattr(self.ev, "a"):
- different_addresses = self.ev.a != buf.a
+ self.sync.rsys += sequence_error.eq(self.ev.timestamp[fine_ts_width:] <
+ buf.timestamp[fine_ts_width:])
+ if interface.enable_replace:
+ if hasattr(self.ev, "a"):
+ different_addresses = self.ev.a != buf.a
+ else:
+ different_addresses = 0
+ if fine_ts_width:
+ self.sync.rsys += collision.eq(
+ (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
+ & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
+ |different_addresses))
else:
- different_addresses = 0
- if fine_ts_width:
self.sync.rsys += collision.eq(
- (self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
- & ((self.ev.timestamp[:fine_ts_width] != buf.timestamp[:fine_ts_width])
- |different_addresses))
+ self.ev.timestamp[fine_ts_width:] == buf.timestamp[fine_ts_width:])
self.comb += any_error.eq(sequence_error | collision)
if interface.suppress_nop:
# disable NOP at reset: do not suppress a first write with all 0s
diff --git a/artiq/gateware/rtio/phy/wishbone.py b/artiq/gateware/rtio/phy/wishbone.py
index 1b58525f6..2e9d6bc4a 100644
--- a/artiq/gateware/rtio/phy/wishbone.py
+++ b/artiq/gateware/rtio/phy/wishbone.py
@@ -13,7 +13,8 @@ class RT2WB(Module):
rtlink.OInterface(
len(wb.dat_w),
address_width + 1,
- suppress_nop=False),
+ suppress_nop=False,
+ enable_replace=False),
rtlink.IInterface(
len(wb.dat_r),
timestamped=False)
diff --git a/artiq/gateware/rtio/rtlink.py b/artiq/gateware/rtio/rtlink.py
index c9d281ceb..b8bda7aac 100644
--- a/artiq/gateware/rtio/rtlink.py
+++ b/artiq/gateware/rtio/rtlink.py
@@ -3,7 +3,8 @@ from migen import *
class OInterface:
def __init__(self, data_width, address_width=0,
- fine_ts_width=0, suppress_nop=True):
+ fine_ts_width=0, suppress_nop=True,
+ enable_replace=True):
self.stb = Signal()
self.busy = Signal()
@@ -15,6 +16,7 @@ class OInterface:
self.fine_ts = Signal(fine_ts_width)
self.suppress_nop = suppress_nop
+ self.enable_replace = enable_replace
@classmethod
def like(cls, other):
diff --git a/artiq/gateware/targets/kc705.py b/artiq/gateware/targets/kc705.py
index 8f766ecce..ae15ec179 100755
--- a/artiq/gateware/targets/kc705.py
+++ b/artiq/gateware/targets/kc705.py
@@ -204,8 +204,9 @@ class NIST_QC1(_NIST_Ions):
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
- self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels)
- self.config["DDS_CHANNEL_COUNT"] = 8
+ self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
+ self.config["RTIO_DDS_COUNT"] = 1
+ self.config["DDS_CHANNELS_PER_BUS"] = 8
self.config["DDS_AD9858"] = True
phy = dds.AD9858(platform.request("dds"), 8)
self.submodules += phy
@@ -277,8 +278,9 @@ class NIST_CLOCK(_NIST_Ions):
rtio_channels.append(rtio.Channel.from_phy(
phy, ofifo_depth=128, ififo_depth=128))
- self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels)
- self.config["DDS_CHANNEL_COUNT"] = 11
+ self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
+ self.config["RTIO_DDS_COUNT"] = 1
+ self.config["DDS_CHANNELS_PER_BUS"] = 11
self.config["DDS_AD9914"] = True
self.config["DDS_ONEHOT_SEL"] = True
phy = dds.AD9914(platform.request("dds"), 11, onehot=True)
@@ -331,8 +333,9 @@ class NIST_QC2(_NIST_Ions):
self.submodules += phy
rtio_channels.append(rtio.Channel.from_phy(phy))
- self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels)
- self.config["DDS_CHANNEL_COUNT"] = 12
+ self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
+ self.config["RTIO_DDS_COUNT"] = 1
+ self.config["DDS_CHANNELS_PER_BUS"] = 12
self.config["DDS_AD9914"] = True
self.config["DDS_ONEHOT_SEL"] = True
phy = dds.AD9914(platform.request("dds"), 12, onehot=True)
diff --git a/artiq/gateware/targets/pipistrello.py b/artiq/gateware/targets/pipistrello.py
index 620810b60..2b2c7de65 100755
--- a/artiq/gateware/targets/pipistrello.py
+++ b/artiq/gateware/targets/pipistrello.py
@@ -215,8 +215,9 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
rtio_channels.append(rtio.Channel.from_phy(
phy, ofifo_depth=256, ififo_depth=256))
- self.config["RTIO_DDS_CHANNEL"] = len(rtio_channels)
- self.config["DDS_CHANNEL_COUNT"] = 8
+ self.config["RTIO_FIRST_DDS_CHANNEL"] = len(rtio_channels)
+ self.config["RTIO_DDS_COUNT"] = 1
+ self.config["DDS_CHANNELS_PER_BUS"] = 8
self.config["DDS_AD9858"] = True
dds_pins = platform.request("dds")
self.comb += dds_pins.p.eq(0)
diff --git a/artiq/gui/moninj.py b/artiq/gui/moninj.py
index 43892876a..818c148f6 100644
--- a/artiq/gui/moninj.py
+++ b/artiq/gui/moninj.py
@@ -118,7 +118,8 @@ class _TTLWidget(QtWidgets.QFrame):
class _DDSWidget(QtWidgets.QFrame):
- def __init__(self, channel, sysclk, title):
+ def __init__(self, bus_channel, channel, sysclk, title):
+ self.bus_channel = bus_channel
self.channel = channel
self.sysclk = sysclk
@@ -146,13 +147,14 @@ class _DDSWidget(QtWidgets.QFrame):
self.set_value(0)
def set_value(self, ftw):
- frequency = ftw*self.sysclk/2**32
+ frequency = ftw*self.sysclk()/2**32
self._value.setText("{:.7f} MHz"
.format(float(frequency)/1e6))
class _DeviceManager:
def __init__(self, send_to_device, init):
+ self.dds_sysclk = 0
self.send_to_device = send_to_device
self.ddb = dict()
self.ttl_cb = lambda: None
@@ -162,6 +164,9 @@ class _DeviceManager:
for k, v in init.items():
self[k] = v
+ def get_dds_sysclk(self):
+ return self.dds_sysclk
+
def __setitem__(self, k, v):
if k in self.ttl_widgets:
del self[k]
@@ -181,12 +186,15 @@ class _DeviceManager:
self.ttl_widgets[k] = _TTLWidget(
channel, self.send_to_device, force_out, title)
self.ttl_cb()
+ if (v["module"] == "artiq.coredevice.dds"
+ and v["class"] == "CoreDDS"):
+ self.dds_sysclk = v["arguments"]["sysclk"]
if (v["module"] == "artiq.coredevice.dds"
and v["class"] in {"AD9858", "AD9914"}):
+ bus_channel = v["arguments"]["bus_channel"]
channel = v["arguments"]["channel"]
- sysclk = v["arguments"]["sysclk"]
self.dds_widgets[channel] = _DDSWidget(
- channel, sysclk, title)
+ bus_channel, channel, self.get_dds_sysclk, title)
self.dds_cb()
except KeyError:
pass
@@ -275,19 +283,23 @@ class MonInj(TaskObject):
"is not present yet")
return
try:
- ttl_levels, ttl_oes, ttl_overrides = \
- struct.unpack(">QQQ", data[:8*3])
+ hlen = 8*3+4
+ (ttl_levels, ttl_oes, ttl_overrides,
+ dds_rtio_first_channel, dds_channels_per_bus) = \
+ struct.unpack(">QQQHH", data[:hlen])
for w in self.dm.ttl_widgets.values():
channel = w.channel
w.set_value(ttl_levels & (1 << channel),
ttl_oes & (1 << channel),
ttl_overrides & (1 << channel))
- dds_data = data[8*3:]
+ dds_data = data[hlen:]
ndds = len(dds_data)//4
ftws = struct.unpack(">" + "I"*ndds, dds_data)
for w in self.dm.dds_widgets.values():
+ offset = (dds_channels_per_bus*w.bus_channel
+ + w.channel-dds_rtio_first_channel)
try:
- ftw = ftws[w.channel]
+ ftw = ftws[offset]
except KeyError:
pass
else:
diff --git a/artiq/runtime/analyzer.c b/artiq/runtime/analyzer.c
index a1b71b428..23f77c98d 100644
--- a/artiq/runtime/analyzer.c
+++ b/artiq/runtime/analyzer.c
@@ -12,7 +12,6 @@ struct analyzer_header {
unsigned long long int total_byte_count;
unsigned char overflow_occured;
unsigned char log_channel;
- unsigned char dds_channel;
unsigned char dds_onehot_sel;
} __attribute__((packed));
@@ -72,7 +71,6 @@ void analyzer_start(void)
analyzer_header.overflow_occured = rtio_analyzer_message_encoder_overflow_read();
analyzer_header.log_channel = CONFIG_RTIO_LOG_CHANNEL;
- analyzer_header.dds_channel = CONFIG_RTIO_DDS_CHANNEL;
#ifdef CONFIG_DDS_ONEHOT_SEL
analyzer_header.dds_onehot_sel = 1;
#else
diff --git a/artiq/runtime/bridge.c b/artiq/runtime/bridge.c
index d1157cf65..bfe3e1fcf 100644
--- a/artiq/runtime/bridge.c
+++ b/artiq/runtime/bridge.c
@@ -16,12 +16,12 @@ static void rtio_output_blind(int channel, int addr, int data)
rtio_o_we_write(1);
}
-static void dds_write(int addr, int data)
+static void dds_write(int bus_channel, int addr, int data)
{
- rtio_output_blind(CONFIG_RTIO_DDS_CHANNEL, addr, data);
+ rtio_output_blind(bus_channel, addr, data);
}
-static int dds_read(int addr)
+static int dds_read(int bus_channel, int addr)
{
int r;
@@ -31,7 +31,7 @@ static int dds_read(int addr)
#ifdef CONFIG_DDS_AD9914
#define DDS_READ_FLAG 256
#endif
- dds_write(addr | DDS_READ_FLAG, 0);
+ dds_write(bus_channel, addr | DDS_READ_FLAG, 0);
while(rtio_i_status_read() & RTIO_I_STATUS_EMPTY);
r = rtio_i_data_read();
rtio_i_re_write(1);
@@ -75,16 +75,18 @@ void bridge_main(void)
struct msg_brg_dds_sel *msg;
msg = (struct msg_brg_dds_sel *)umsg;
- dds_write(DDS_GPIO, msg->channel << 1);
+ dds_write(msg->bus_channel, DDS_GPIO, msg->channel << 1);
mailbox_acknowledge();
break;
}
case MESSAGE_TYPE_BRG_DDS_RESET: {
unsigned int g;
+ struct msg_brg_dds_reset *msg;
- g = dds_read(DDS_GPIO);
- dds_write(DDS_GPIO, g | 1);
- dds_write(DDS_GPIO, g);
+ msg = (struct msg_brg_dds_reset *)umsg;
+ g = dds_read(msg->bus_channel, DDS_GPIO);
+ dds_write(msg->bus_channel, DDS_GPIO, g | 1);
+ dds_write(msg->bus_channel, DDS_GPIO, g);
mailbox_acknowledge();
break;
@@ -95,7 +97,7 @@ void bridge_main(void)
msg = (struct msg_brg_dds_read_request *)umsg;
rmsg.type = MESSAGE_TYPE_BRG_DDS_READ_REPLY;
- rmsg.data = dds_read(msg->address);
+ rmsg.data = dds_read(msg->bus_channel, msg->address);
mailbox_send_and_wait(&rmsg);
break;
}
@@ -103,14 +105,18 @@ void bridge_main(void)
struct msg_brg_dds_write *msg;
msg = (struct msg_brg_dds_write *)umsg;
- dds_write(msg->address, msg->data);
+ dds_write(msg->bus_channel, msg->address, msg->data);
mailbox_acknowledge();
break;
}
- case MESSAGE_TYPE_BRG_DDS_FUD:
- dds_write(DDS_FUD, 0);
+ case MESSAGE_TYPE_BRG_DDS_FUD: {
+ struct msg_brg_dds_fud *msg;
+
+ msg = (struct msg_brg_dds_fud *)umsg;
+ dds_write(msg->bus_channel, DDS_FUD, 0);
mailbox_acknowledge();
break;
+ }
default:
mailbox_acknowledge();
break;
diff --git a/artiq/runtime/bridge_ctl.c b/artiq/runtime/bridge_ctl.c
index 11182efb9..1ebc4b0bc 100644
--- a/artiq/runtime/bridge_ctl.c
+++ b/artiq/runtime/bridge_ctl.c
@@ -43,30 +43,33 @@ void brg_ttlo(int n, int value)
mailbox_send_and_wait(&msg);
}
-void brg_ddssel(int channel)
+void brg_ddssel(int bus_channel, int channel)
{
struct msg_brg_dds_sel msg;
msg.type = MESSAGE_TYPE_BRG_DDS_SEL;
+ msg.bus_channel = bus_channel;
msg.channel = channel;
mailbox_send_and_wait(&msg);
}
-void brg_ddsreset(void)
+void brg_ddsreset(int bus_channel)
{
- struct msg_base msg;
+ struct msg_brg_dds_reset msg;
msg.type = MESSAGE_TYPE_BRG_DDS_RESET;
+ msg.bus_channel = bus_channel;
mailbox_send_and_wait(&msg);
}
-unsigned int brg_ddsread(unsigned int address)
+unsigned int brg_ddsread(int bus_channel, unsigned int address)
{
struct msg_brg_dds_read_request msg;
struct msg_brg_dds_read_reply *rmsg;
unsigned int r;
msg.type = MESSAGE_TYPE_BRG_DDS_READ_REQUEST;
+ msg.bus_channel = bus_channel;
msg.address = address;
mailbox_send(&msg);
while(1) {
@@ -82,20 +85,22 @@ unsigned int brg_ddsread(unsigned int address)
}
}
-void brg_ddswrite(unsigned int address, unsigned int data)
+void brg_ddswrite(int bus_channel, unsigned int address, unsigned int data)
{
struct msg_brg_dds_write msg;
msg.type = MESSAGE_TYPE_BRG_DDS_WRITE;
+ msg.bus_channel = bus_channel;
msg.address = address;
msg.data = data;
mailbox_send_and_wait(&msg);
}
-void brg_ddsfud(void)
+void brg_ddsfud(int bus_channel)
{
- struct msg_base msg;
+ struct msg_brg_dds_fud msg;
msg.type = MESSAGE_TYPE_BRG_DDS_FUD;
+ msg.bus_channel = bus_channel;
mailbox_send_and_wait(&msg);
}
diff --git a/artiq/runtime/bridge_ctl.h b/artiq/runtime/bridge_ctl.h
index e6d2b7306..2929ee8f0 100644
--- a/artiq/runtime/bridge_ctl.h
+++ b/artiq/runtime/bridge_ctl.h
@@ -6,10 +6,10 @@ void brg_start(void);
void brg_ttloe(int n, int value);
void brg_ttlo(int n, int value);
-void brg_ddssel(int channel);
-void brg_ddsreset(void);
-unsigned int brg_ddsread(unsigned int address);
-void brg_ddswrite(unsigned int address, unsigned int data);
-void brg_ddsfud(void);
+void brg_ddssel(int bus_channel, int channel);
+void brg_ddsreset(int bus_channel);
+unsigned int brg_ddsread(int bus_channel, unsigned int address);
+void brg_ddswrite(int bus_channel, unsigned int address, unsigned int data);
+void brg_ddsfud(int bus_channel);
#endif /* __BRIDGE_CTL_H */
diff --git a/artiq/runtime/dds.c b/artiq/runtime/dds.c
index 3f8e728c1..b9b07bde7 100644
--- a/artiq/runtime/dds.c
+++ b/artiq/runtime/dds.c
@@ -26,11 +26,11 @@
#endif
#define DDS_WRITE(addr, data) do { \
- rtio_output(now, CONFIG_RTIO_DDS_CHANNEL, addr, data); \
+ rtio_output(now, bus_channel, addr, data); \
now += DURATION_WRITE; \
} while(0)
-void dds_init(long long int timestamp, int channel)
+void dds_init(long long int timestamp, int bus_channel, int channel)
{
long long int now;
@@ -82,17 +82,23 @@ void dds_init(long long int timestamp, int channel)
/* Compensation to keep phase continuity when switching from absolute or tracking
* to continuous phase mode. */
-static unsigned int continuous_phase_comp[CONFIG_DDS_CHANNEL_COUNT];
+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, unsigned int channel,
+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 >= CONFIG_DDS_CHANNEL_COUNT) {
+ if((channel < 0) || (channel >= CONFIG_DDS_CHANNELS_PER_BUS)) {
core_log("Attempted to set invalid DDS channel\n");
return;
}
+ if((bus_channel < CONFIG_RTIO_FIRST_DDS_CHANNEL)
+ || (bus_channel >= (CONFIG_RTIO_FIRST_DDS_CHANNEL+CONFIG_RTIO_DDS_COUNT))) {
+ core_log("Attempted to use invalid DDS bus\n");
+ return;
+ }
#ifdef CONFIG_DDS_ONEHOT_SEL
channel_enc = 1 << channel;
#else
@@ -124,7 +130,7 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int
/* Disable autoclear phase accumulator and enables OSK. */
DDS_WRITE(DDS_CFR1L, 0x0108);
#endif
- pow += continuous_phase_comp[channel];
+ pow += continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel];
} else {
long long int fud_time;
@@ -140,7 +146,7 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int
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[channel] = pow;
+ continuous_phase_comp[bus_channel-CONFIG_RTIO_FIRST_DDS_CHANNEL][channel] = pow;
}
#ifdef CONFIG_DDS_AD9858
@@ -157,6 +163,7 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int
}
struct dds_set_params {
+ int bus_channel;
int channel;
unsigned int ftw;
unsigned int pow;
@@ -189,20 +196,22 @@ void dds_batch_exit(void)
now = batch_ref_time - batch_count*(DURATION_PROGRAM + DURATION_WRITE);
for(i=0;i= DDS_MAX_BATCH)
artiq_raise_from_c("DDSBatchError", "DDS batch error", 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;
@@ -210,7 +219,8 @@ void dds_set(long long int timestamp, int channel,
batch[batch_count].amplitude = amplitude;
batch_count++;
} else {
- dds_set_one(timestamp - DURATION_PROGRAM, timestamp, channel, ftw, pow, phase_mode,
- amplitude);
+ dds_set_one(timestamp - DURATION_PROGRAM, timestamp,
+ bus_channel, channel,
+ ftw, pow, phase_mode, amplitude);
}
}
diff --git a/artiq/runtime/dds.h b/artiq/runtime/dds.h
index 6d4e5d972..10fa3fffc 100644
--- a/artiq/runtime/dds.h
+++ b/artiq/runtime/dds.h
@@ -54,10 +54,10 @@ enum {
PHASE_MODE_TRACKING = 2
};
-void dds_init(long long int timestamp, int channel);
+void dds_init(long long int timestamp, int bus_channel, int channel);
void dds_batch_enter(long long int timestamp);
void dds_batch_exit(void);
-void dds_set(long long int timestamp, int channel,
+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 /* __DDS_H */
diff --git a/artiq/runtime/messages.h b/artiq/runtime/messages.h
index bd2adc912..49df62319 100644
--- a/artiq/runtime/messages.h
+++ b/artiq/runtime/messages.h
@@ -150,23 +150,37 @@ struct msg_brg_ttl_out {
struct msg_brg_dds_sel {
int type;
+ int bus_channel;
int channel;
};
+struct msg_brg_dds_reset {
+ int type;
+ int bus_channel;
+};
+
struct msg_brg_dds_read_request {
int type;
+ int bus_channel;
unsigned int address;
};
struct msg_brg_dds_read_reply {
int type;
+ int bus_channel;
unsigned int data;
};
struct msg_brg_dds_write {
int type;
+ int bus_channel;
unsigned int address;
unsigned int data;
};
+struct msg_brg_dds_fud {
+ int type;
+ int bus_channel;
+};
+
#endif /* __MESSAGES_H */
diff --git a/artiq/runtime/moninj.c b/artiq/runtime/moninj.c
index aea5bfd69..4a7c14205 100644
--- a/artiq/runtime/moninj.c
+++ b/artiq/runtime/moninj.c
@@ -36,13 +36,15 @@ struct monitor_reply {
long long int ttl_levels;
long long int ttl_oes;
long long int ttl_overrides;
- unsigned int dds_ftws[CONFIG_DDS_CHANNEL_COUNT];
-};
+ unsigned short int dds_rtio_first_channel;
+ unsigned short int dds_channels_per_bus;
+ unsigned int dds_ftws[CONFIG_RTIO_DDS_COUNT*CONFIG_DDS_CHANNELS_PER_BUS];
+} __attribute__((packed));
static void moninj_monitor(const ip_addr_t *addr, u16_t port)
{
struct monitor_reply reply;
- int i;
+ int i, j;
struct pbuf *reply_p;
reply.ttl_levels = 0;
@@ -64,11 +66,15 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
reply.ttl_overrides |= 1LL << i;
}
- rtio_moninj_mon_chan_sel_write(CONFIG_RTIO_DDS_CHANNEL);
- for(i=0;i\n");
+ return;
+ }
+
+ n2 = strtoul(n, &c, 0);
+ if(*c != 0) {
+ printf("incorrect bus channel\n");
+ return;
+ }
+
+ bus_channel = n2;
+}
+
+
static void ddssel(char *n)
{
char *c;
@@ -123,7 +145,7 @@ static void ddssel(char *n)
#ifdef CONFIG_DDS_ONEHOT_SEL
n2 = 1 << n2;
#endif
- brg_ddssel(n2);
+ brg_ddssel(bus_channel, n2);
}
static void ddsw(char *addr, char *value)
@@ -147,7 +169,7 @@ static void ddsw(char *addr, char *value)
return;
}
- brg_ddswrite(addr2, value2);
+ brg_ddswrite(bus_channel, addr2, value2);
}
static void ddsr(char *addr)
@@ -167,16 +189,16 @@ static void ddsr(char *addr)
}
#ifdef CONFIG_DDS_AD9858
- printf("0x%02x\n", brg_ddsread(addr2));
+ printf("0x%02x\n", brg_ddsread(bus_channel, addr2));
#endif
#ifdef CONFIG_DDS_AD9914
- printf("0x%04x\n", brg_ddsread(addr2));
+ printf("0x%04x\n", brg_ddsread(bus_channel, addr2));
#endif
}
static void ddsfud(void)
{
- brg_ddsfud();
+ brg_ddsfud(bus_channel);
}
static void ddsftw(char *n, char *ftw)
@@ -203,36 +225,36 @@ static void ddsftw(char *n, char *ftw)
#ifdef CONFIG_DDS_ONEHOT_SEL
n2 = 1 << n2;
#endif
- brg_ddssel(n2);
+ brg_ddssel(bus_channel, n2);
#ifdef CONFIG_DDS_AD9858
- brg_ddswrite(DDS_FTW0, ftw2 & 0xff);
- brg_ddswrite(DDS_FTW1, (ftw2 >> 8) & 0xff);
- brg_ddswrite(DDS_FTW2, (ftw2 >> 16) & 0xff);
- brg_ddswrite(DDS_FTW3, (ftw2 >> 24) & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW0, ftw2 & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW1, (ftw2 >> 8) & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW2, (ftw2 >> 16) & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW3, (ftw2 >> 24) & 0xff);
#endif
#ifdef CONFIG_DDS_AD9914
- brg_ddswrite(DDS_FTWL, ftw2 & 0xffff);
- brg_ddswrite(DDS_FTWH, (ftw2 >> 16) & 0xffff);
+ brg_ddswrite(bus_channel, DDS_FTWL, ftw2 & 0xffff);
+ brg_ddswrite(bus_channel, DDS_FTWH, (ftw2 >> 16) & 0xffff);
#endif
- brg_ddsfud();
+ brg_ddsfud(bus_channel);
}
static void ddsreset(void)
{
- brg_ddsreset();
+ brg_ddsreset(bus_channel);
}
#ifdef CONFIG_DDS_AD9858
static void ddsinit(void)
{
- brg_ddsreset();
- brg_ddswrite(DDS_CFR0, 0x78);
- brg_ddswrite(DDS_CFR1, 0x00);
- brg_ddswrite(DDS_CFR2, 0x00);
- brg_ddswrite(DDS_CFR3, 0x00);
- brg_ddsfud();
+ brg_ddsreset(bus_channel);
+ brg_ddswrite(bus_channel, DDS_CFR0, 0x78);
+ brg_ddswrite(bus_channel, DDS_CFR1, 0x00);
+ brg_ddswrite(bus_channel, DDS_CFR2, 0x00);
+ brg_ddswrite(bus_channel, DDS_CFR3, 0x00);
+ brg_ddsfud(bus_channel);
}
#endif
@@ -241,17 +263,17 @@ static void ddsinit(void)
{
long long int t;
- brg_ddsreset();
- brg_ddswrite(DDS_CFR1H, 0x0000); /* Enable cosine output */
- brg_ddswrite(DDS_CFR2L, 0x8900); /* Enable matched latency */
- brg_ddswrite(DDS_CFR2H, 0x0080); /* Enable profile mode */
- brg_ddswrite(DDS_ASF, 0x0fff); /* Set amplitude to maximum */
- brg_ddswrite(DDS_CFR4H, 0x0105); /* Enable DAC calibration */
- brg_ddswrite(DDS_FUD, 0);
+ brg_ddsreset(bus_channel);
+ brg_ddswrite(bus_channel, DDS_CFR1H, 0x0000); /* Enable cosine output */
+ brg_ddswrite(bus_channel, DDS_CFR2L, 0x8900); /* Enable matched latency */
+ brg_ddswrite(bus_channel, DDS_CFR2H, 0x0080); /* Enable profile mode */
+ brg_ddswrite(bus_channel, DDS_ASF, 0x0fff); /* Set amplitude to maximum */
+ brg_ddswrite(bus_channel, DDS_CFR4H, 0x0105); /* Enable DAC calibration */
+ brg_ddswrite(bus_channel, DDS_FUD, 0);
t = clock_get_ms();
while(clock_get_ms() < t + 2);
- brg_ddswrite(DDS_CFR4H, 0x0005); /* Disable DAC calibration */
- brg_ddsfud();
+ brg_ddswrite(bus_channel, DDS_CFR4H, 0x0005); /* Disable DAC calibration */
+ brg_ddsfud(bus_channel);
}
#endif
@@ -265,34 +287,34 @@ static void do_ddstest_one(unsigned int i)
unsigned int f, g, j;
#ifdef CONFIG_DDS_ONEHOT_SEL
- brg_ddssel(1 << i);
+ brg_ddssel(bus_channel, 1 << i);
#else
- brg_ddssel(i);
+ brg_ddssel(bus_channel, i);
#endif
ddsinit();
for(j=0; j<12; j++) {
f = v[j];
#ifdef CONFIG_DDS_AD9858
- brg_ddswrite(DDS_FTW0, f & 0xff);
- brg_ddswrite(DDS_FTW1, (f >> 8) & 0xff);
- brg_ddswrite(DDS_FTW2, (f >> 16) & 0xff);
- brg_ddswrite(DDS_FTW3, (f >> 24) & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW0, f & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW1, (f >> 8) & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW2, (f >> 16) & 0xff);
+ brg_ddswrite(bus_channel, DDS_FTW3, (f >> 24) & 0xff);
#endif
#ifdef CONFIG_DDS_AD9914
- brg_ddswrite(DDS_FTWL, f & 0xffff);
- brg_ddswrite(DDS_FTWH, (f >> 16) & 0xffff);
+ brg_ddswrite(bus_channel, DDS_FTWL, f & 0xffff);
+ brg_ddswrite(bus_channel, DDS_FTWH, (f >> 16) & 0xffff);
#endif
- brg_ddsfud();
+ brg_ddsfud(bus_channel);
#ifdef CONFIG_DDS_AD9858
- g = brg_ddsread(DDS_FTW0);
- g |= brg_ddsread(DDS_FTW1) << 8;
- g |= brg_ddsread(DDS_FTW2) << 16;
- g |= brg_ddsread(DDS_FTW3) << 24;
+ g = brg_ddsread(bus_channel, DDS_FTW0);
+ g |= brg_ddsread(bus_channel, DDS_FTW1) << 8;
+ g |= brg_ddsread(bus_channel, DDS_FTW2) << 16;
+ g |= brg_ddsread(bus_channel, DDS_FTW3) << 24;
#endif
#ifdef CONFIG_DDS_AD9914
- g = brg_ddsread(DDS_FTWL);
- g |= brg_ddsread(DDS_FTWH) << 16;
+ g = brg_ddsread(bus_channel, DDS_FTWL);
+ g |= brg_ddsread(bus_channel, DDS_FTWH) << 16;
#endif
if(g != f)
printf("readback fail on DDS %d, 0x%08x != 0x%08x\n", i, g, f);
@@ -330,7 +352,7 @@ static void ddstest(char *n, char *channel)
do_ddstest_one(channel2);
} else {
for(i=0;i - select RTIO clock source");
puts("ttloe - set TTL output enable");
puts("ttlo - set TTL output value");
+ puts("ddsbus - select the DDS bus RTIO channel");
puts("ddssel - select a DDS");
puts("ddsinit - reset, config, FUD DDS");
puts("ddsreset - reset DDS");
@@ -624,6 +647,7 @@ static void do_command(char *c)
else if(strcmp(token, "ttloe") == 0) ttloe(get_token(&c), get_token(&c));
else if(strcmp(token, "ttlo") == 0) ttlo(get_token(&c), get_token(&c));
+ else if(strcmp(token, "ddsbus") == 0) ddsbus(get_token(&c));
else if(strcmp(token, "ddssel") == 0) ddssel(get_token(&c));
else if(strcmp(token, "ddsw") == 0) ddsw(get_token(&c), get_token(&c));
else if(strcmp(token, "ddsr") == 0) ddsr(get_token(&c));
diff --git a/doc/manual/core_device.rst b/doc/manual/core_device.rst
index 484f69358..9489277a7 100644
--- a/doc/manual/core_device.rst
+++ b/doc/manual/core_device.rst
@@ -89,6 +89,8 @@ The board has RTIO SPI buses mapped as follows:
| 25 | SPI2_CS_N | SPI2_MOSI | SPI2_MISO | SPI2_CLK |
+--------------+-------------+-------------+-----------+------------+
+The DDS bus is on channel 26.
+
NIST QC2
++++++++
diff --git a/examples/master/device_db.pyon b/examples/master/device_db.pyon
index f10b1e6b2..05f9bc7ca 100644
--- a/examples/master/device_db.pyon
+++ b/examples/master/device_db.pyon
@@ -14,6 +14,12 @@
"class": "Core",
"arguments": {"ref_period": 1e-9}
},
+ "core_dds": {
+ "type": "local",
+ "module": "artiq.coredevice.dds",
+ "class": "CoreDDS",
+ "arguments": {"sysclk": 3e9}
+ },
"i2c_switch": {
"type": "local",
@@ -121,30 +127,24 @@
"arguments": {"spi_device": "spi0", "ldac_device": "ttl0"}
},
- "dds_bus": {
- "type": "local",
- "module": "artiq.coredevice.dds",
- "class": "DDSBus",
- "arguments": {}
- },
"dds0": {
"type": "local",
"module": "artiq.coredevice.dds",
"class": "AD9914",
- "arguments": {"sysclk": 3e9, "channel": 0},
+ "arguments": {"bus_channel": 26, "channel": 0},
"comment": "Comments work in DDS panel as well"
},
"dds1": {
"type": "local",
"module": "artiq.coredevice.dds",
"class": "AD9914",
- "arguments": {"sysclk": 3e9, "channel": 1}
+ "arguments": {"bus_channel": 26, "channel": 1}
},
"dds2": {
"type": "local",
"module": "artiq.coredevice.dds",
"class": "AD9914",
- "arguments": {"sysclk": 3e9, "channel": 2}
+ "arguments": {"bus_channel": 26, "channel": 2}
},
"qc_q1_0": {
diff --git a/examples/master/repository/coredevice_examples/photon_histogram.py b/examples/master/repository/coredevice_examples/photon_histogram.py
index 307b3a52e..5a919aa4a 100644
--- a/examples/master/repository/coredevice_examples/photon_histogram.py
+++ b/examples/master/repository/coredevice_examples/photon_histogram.py
@@ -6,7 +6,7 @@ class PhotonHistogram(EnvExperiment):
def build(self):
self.setattr_device("core")
- self.setattr_device("dds_bus")
+ self.setattr_device("core_dds")
self.setattr_device("bd_dds")
self.setattr_device("bd_sw")
self.setattr_device("bdd_dds")
@@ -22,7 +22,7 @@ class PhotonHistogram(EnvExperiment):
@kernel
def program_cooling(self):
- with self.dds_bus.batch:
+ with self.core_dds.batch:
self.bd_dds.set(200*MHz)
self.bdd_dds.set(300*MHz)
diff --git a/examples/master/repository/coredevice_examples/simple/dds_test.py b/examples/master/repository/coredevice_examples/simple/dds_test.py
index a0b60bf73..5e262211a 100644
--- a/examples/master/repository/coredevice_examples/simple/dds_test.py
+++ b/examples/master/repository/coredevice_examples/simple/dds_test.py
@@ -6,7 +6,7 @@ class DDSTest(EnvExperiment):
def build(self):
self.setattr_device("core")
- self.setattr_device("dds_bus")
+ self.setattr_device("core_dds")
self.setattr_device("dds0")
self.setattr_device("dds1")
self.setattr_device("dds2")
@@ -17,7 +17,7 @@ class DDSTest(EnvExperiment):
@kernel
def run(self):
- with self.dds_bus.batch:
+ with self.core_dds.batch:
self.dds1.set(120*MHz)
self.dds2.set(200*MHz)
delay(1*us)