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)