forked from M-Labs/artiq
DDS monitoring
This commit is contained in:
parent
03fe71228b
commit
5a9bdb2e33
@ -51,13 +51,12 @@ class DDS(AutoDB):
|
||||
|
||||
Controls one DDS channel managed directly by the core device's runtime.
|
||||
|
||||
:param dds_sysclk: DDS system frequency, used for computing the frequency
|
||||
tuning words.
|
||||
:param sysclk: DDS system frequency.
|
||||
:param channel: channel number of the DDS device to control.
|
||||
"""
|
||||
class DBKeys:
|
||||
core = Device()
|
||||
dds_sysclk = Argument(1*GHz)
|
||||
sysclk = Argument()
|
||||
channel = Argument()
|
||||
|
||||
def build(self):
|
||||
@ -68,14 +67,14 @@ class DDS(AutoDB):
|
||||
"""Returns the frequency tuning word corresponding to the given
|
||||
frequency.
|
||||
"""
|
||||
return round(2**32*frequency/self.dds_sysclk)
|
||||
return round(2**32*frequency/self.sysclk)
|
||||
|
||||
@portable
|
||||
def ftw_to_frequency(self, ftw):
|
||||
"""Returns the frequency corresponding to the given frequency tuning
|
||||
word.
|
||||
"""
|
||||
return ftw*self.dds_sysclk/2**32
|
||||
return ftw*self.sysclk/2**32
|
||||
|
||||
@kernel
|
||||
def init(self):
|
||||
|
@ -11,6 +11,7 @@ class Monitor(Module, AutoCSR):
|
||||
max_probe_len = max(flen(p) for cp in chan_probes for p in cp)
|
||||
self.chan_sel = CSRStorage(bits_for(len(chan_probes)-1))
|
||||
self.probe_sel = CSRStorage(bits_for(max_chan_probes-1))
|
||||
self.value_update = CSR()
|
||||
self.value = CSRStatus(max_probe_len)
|
||||
|
||||
# # #
|
||||
@ -25,8 +26,9 @@ class Monitor(Module, AutoCSR):
|
||||
cp_sys.append(vs.o)
|
||||
cp_sys += [0]*(max_chan_probes-len(cp))
|
||||
chan_probes_sys.append(Array(cp_sys)[self.probe_sel.storage])
|
||||
self.comb += self.value.status.eq(
|
||||
Array(chan_probes_sys)[self.chan_sel.storage])
|
||||
self.sync += If(self.value_update.re,
|
||||
self.value.status.eq(
|
||||
Array(chan_probes_sys)[self.chan_sel.storage]))
|
||||
|
||||
|
||||
class Injector(Module, AutoCSR):
|
||||
|
36
artiq/gateware/rtio/phy/dds.py
Normal file
36
artiq/gateware/rtio/phy/dds.py
Normal file
@ -0,0 +1,36 @@
|
||||
from migen.fhdl.std import *
|
||||
|
||||
from artiq.gateware import ad9858 as ad9858_ll
|
||||
from artiq.gateware.rtio.phy.wishbone import RT2WB
|
||||
|
||||
|
||||
class AD9858(Module):
|
||||
def __init__(self, pads, nchannels=8, **kwargs):
|
||||
self.submodules._ll = RenameClockDomains(
|
||||
ad9858_ll.AD9858(pads, **kwargs), "rio")
|
||||
self.submodules._rt2wb = RT2WB(7, self._ll.bus)
|
||||
self.rtlink = self._rt2wb.rtlink
|
||||
self.probes = [Signal(32) for i in range(nchannels)]
|
||||
|
||||
# # #
|
||||
|
||||
# keep track of the currently selected channel
|
||||
current_channel = Signal(max=nchannels)
|
||||
self.sync.rio += If(self.rtlink.o.stb & (self.rtlink.o.address == 65),
|
||||
current_channel.eq(self.rtlink.o.data))
|
||||
|
||||
# keep track of frequency tuning words, before they are FUDed
|
||||
ftws = [Signal(32) for i in range(nchannels)]
|
||||
for i in range(4):
|
||||
for c, ftw in enumerate(ftws):
|
||||
self.sync.rio += \
|
||||
If(self.rtlink.o.stb & \
|
||||
(self.rtlink.o.address == 0x0a+i) & \
|
||||
(current_channel == c),
|
||||
ftw[i*8:(i+1)*8].eq(self.rtlink.o.data)
|
||||
)
|
||||
|
||||
# FTW to probe on FUD
|
||||
for c, (probe, ftw) in enumerate(zip(self.probes, ftw)):
|
||||
fud = self.rtlink.o.stb & (self.rtlink.o.address == 64)
|
||||
self.sync.rio += If(fud & (current_channel == c), probe.eq(ftw))
|
@ -9,6 +9,7 @@ from pyqtgraph import dockarea
|
||||
|
||||
from artiq.tools import TaskObject
|
||||
from artiq.protocols.sync_struct import Subscriber
|
||||
from artiq.language.units import strip_unit
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -112,9 +113,10 @@ class _TTLWidget(QtGui.QFrame):
|
||||
|
||||
|
||||
class _DDSWidget(QtGui.QFrame):
|
||||
def __init__(self, send_to_device, channel, name):
|
||||
def __init__(self, send_to_device, channel, sysclk, name):
|
||||
self.send_to_device = send_to_device
|
||||
self.channel = channel
|
||||
self.sysclk = sysclk
|
||||
self.name = name
|
||||
|
||||
QtGui.QFrame.__init__(self)
|
||||
@ -128,48 +130,16 @@ class _DDSWidget(QtGui.QFrame):
|
||||
label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
grid.addWidget(label, 1, 1)
|
||||
|
||||
self._override = QtGui.QLabel()
|
||||
self._override.setAlignment(QtCore.Qt.AlignCenter)
|
||||
grid.addWidget(self._override, 2, 1)
|
||||
|
||||
self._value = QtGui.QLabel()
|
||||
self._value.setAlignment(QtCore.Qt.AlignCenter)
|
||||
grid.addWidget(self._value, 3, 1, 6, 1)
|
||||
grid.addWidget(self._value, 2, 1, 6, 1)
|
||||
|
||||
self._value.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
||||
self._override_action = QtGui.QAction("Override", self._value)
|
||||
self._override_action.setCheckable(True)
|
||||
self._value.addAction(self._override_action)
|
||||
self._override_action.triggered.connect(self._override_clicked)
|
||||
self.set_value(0)
|
||||
|
||||
self.set_value(0.0, False)
|
||||
|
||||
def _override_clicked(self):
|
||||
override_en = self._override_action.isChecked()
|
||||
if override_en:
|
||||
frequency, ok = QtGui.QInputDialog.getDouble(
|
||||
None, "DDS override",
|
||||
"Frequency in MHz for {}:".format(self.name),
|
||||
value=self._frequency, min=0, decimals=3)
|
||||
self._override_action.setChecked(ok)
|
||||
if ok:
|
||||
print("override set to", frequency)
|
||||
else:
|
||||
print("override disabled")
|
||||
|
||||
def set_value(self, frequency, override):
|
||||
self._frequency = frequency
|
||||
self._override_action.setChecked(override)
|
||||
value_s = "{:.3f} MHz".format(frequency)
|
||||
if override:
|
||||
value_s = "<b>" + value_s + "</b>"
|
||||
color = " color=\"red\""
|
||||
self._override.setText("<font size=\"1\" color=\"red\">OVERRIDE</font>")
|
||||
else:
|
||||
color = ""
|
||||
self._override.setText("")
|
||||
self._value.setText("<font size=\"9\"{}>{}</font>"
|
||||
.format(color, value_s))
|
||||
def set_value(self, ftw):
|
||||
frequency = ftw*self.sysclk/2**32
|
||||
self._value.setText("<font size=\"9\">{:.3f} MHz</font>"
|
||||
.format(float(frequency)))
|
||||
|
||||
|
||||
class _DeviceManager:
|
||||
@ -200,8 +170,9 @@ class _DeviceManager:
|
||||
if (v["module"] == "artiq.coredevice.dds"
|
||||
and v["class"] == "DDS"):
|
||||
channel = v["arguments"]["channel"]
|
||||
sysclk = strip_unit(v["arguments"]["sysclk"], "Hz")
|
||||
self.dds_widgets[channel] = _DDSWidget(
|
||||
self.send_to_device, channel, k)
|
||||
self.send_to_device, channel, sysclk, k)
|
||||
self.dds_cb()
|
||||
except KeyError:
|
||||
pass
|
||||
@ -277,11 +248,25 @@ class MonInj(TaskObject):
|
||||
self.transport = transport
|
||||
|
||||
def datagram_received(self, data, addr):
|
||||
ttl_levels, ttl_oes, ttl_overrides = struct.unpack(">QQQ", data)
|
||||
for channel, w in self.dm.ttl_widgets.items():
|
||||
w.set_value(ttl_levels & (1 << channel),
|
||||
ttl_oes & (1 << channel),
|
||||
ttl_overrides & (1 << channel))
|
||||
try:
|
||||
ttl_levels, ttl_oes, ttl_overrides = \
|
||||
struct.unpack(">QQQ", data[:8*3])
|
||||
for channel, w in self.dm.ttl_widgets.items():
|
||||
w.set_value(ttl_levels & (1 << channel),
|
||||
ttl_oes & (1 << channel),
|
||||
ttl_overrides & (1 << channel))
|
||||
dds_data = data[8*3:]
|
||||
ndds = len(dds_data)//4
|
||||
ftws = struct.unpack(">" + "I"*ndds, dds_data)
|
||||
for channel, w in self.dm.dds_widgets.items():
|
||||
try:
|
||||
ftw = ftws[channel]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
w.set_value(ftw)
|
||||
except:
|
||||
logger.warning("failed to process datagram", exc_info=True)
|
||||
|
||||
def error_received(self, exc):
|
||||
logger.warning("datagram endpoint error")
|
||||
|
@ -60,19 +60,22 @@
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.dds",
|
||||
"class": "DDS",
|
||||
"arguments": {"channel": 0}
|
||||
"arguments": {"sysclk": Quantity(Fraction(1000000000, 1), "Hz"),
|
||||
"channel": 0}
|
||||
},
|
||||
"dds1": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.dds",
|
||||
"class": "DDS",
|
||||
"arguments": {"channel": 1}
|
||||
"arguments": {"sysclk": Quantity(Fraction(1000000000, 1), "Hz"),
|
||||
"channel": 1}
|
||||
},
|
||||
"dds2": {
|
||||
"type": "local",
|
||||
"module": "artiq.coredevice.dds",
|
||||
"class": "DDS",
|
||||
"arguments": {"channel": 2}
|
||||
"arguments": {"sysclk": Quantity(Fraction(1000000000, 1), "Hz"),
|
||||
"channel": 2}
|
||||
},
|
||||
|
||||
"qc_q1_0": {
|
||||
|
@ -61,7 +61,7 @@ static void dds_set_one(long long int now, long long int ref_time, int channel,
|
||||
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
|
||||
|
||||
/* We need the RTIO fine timestamp clock to be phase-locked
|
||||
* to DDS SYNCLK, and divided by an integer DDS_RTIO_CLK_RATIO.
|
||||
* to DDS SYSCLK, and divided by an integer DDS_RTIO_CLK_RATIO.
|
||||
*/
|
||||
if(phase_mode == PHASE_MODE_CONTINUOUS) {
|
||||
/* Do not clear phase accumulator on FUD */
|
||||
|
@ -4,9 +4,6 @@
|
||||
#include <hw/common.h>
|
||||
#include <generated/mem.h>
|
||||
|
||||
/* Number of DDS channels to initialize */
|
||||
#define DDS_CHANNEL_COUNT 8
|
||||
|
||||
/* Maximum number of commands in a batch */
|
||||
#define DDS_MAX_BATCH 16
|
||||
|
||||
|
@ -39,6 +39,7 @@ struct monitor_reply {
|
||||
long long int ttl_levels;
|
||||
long long int ttl_oes;
|
||||
long long int ttl_overrides;
|
||||
unsigned int dds_ftws[DDS_CHANNEL_COUNT];
|
||||
};
|
||||
|
||||
static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
||||
@ -53,9 +54,11 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
||||
for(i=0;i<RTIO_TTL_COUNT;i++) {
|
||||
rtio_moninj_mon_chan_sel_write(i);
|
||||
rtio_moninj_mon_probe_sel_write(0);
|
||||
rtio_moninj_mon_value_update_write(1);
|
||||
if(rtio_moninj_mon_value_read())
|
||||
reply.ttl_levels |= 1LL << i;
|
||||
rtio_moninj_mon_probe_sel_write(1);
|
||||
rtio_moninj_mon_value_update_write(1);
|
||||
if(rtio_moninj_mon_value_read())
|
||||
reply.ttl_oes |= 1LL << i;
|
||||
rtio_moninj_inj_chan_sel_write(i);
|
||||
@ -64,6 +67,13 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
||||
reply.ttl_overrides |= 1LL << i;
|
||||
}
|
||||
|
||||
rtio_moninj_mon_chan_sel_write(RTIO_DDS_CHANNEL);
|
||||
for(i=0;i<DDS_CHANNEL_COUNT;i++) {
|
||||
rtio_moninj_mon_probe_sel_write(i);
|
||||
rtio_moninj_mon_value_update_write(1);
|
||||
reply.dds_ftws[i] = rtio_moninj_mon_value_read();
|
||||
}
|
||||
|
||||
reply_p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct monitor_reply), PBUF_RAM);
|
||||
if(!reply_p) {
|
||||
log("Failed to allocate pbuf for monitor reply");
|
||||
|
@ -10,9 +10,8 @@ from misoclib.mem.sdram.core.minicon import MiniconSettings
|
||||
from targets.kc705 import MiniSoC
|
||||
|
||||
from artiq.gateware.soc import AMPSoC
|
||||
from artiq.gateware import rtio, ad9858, nist_qc1
|
||||
from artiq.gateware.rtio.phy import ttl_simple
|
||||
from artiq.gateware.rtio.phy.wishbone import RT2WB
|
||||
from artiq.gateware import rtio, nist_qc1
|
||||
from artiq.gateware.rtio.phy import ttl_simple, dds
|
||||
|
||||
|
||||
class _RTIOCRG(Module, AutoCSR):
|
||||
@ -81,10 +80,8 @@ class NIST_QC1(MiniSoC, AMPSoC):
|
||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
||||
|
||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||
self.submodules.dds = RenameClockDomains(
|
||||
ad9858.AD9858(platform.request("dds")),
|
||||
"rio")
|
||||
phy = RT2WB(7, self.dds.bus)
|
||||
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
||||
phy = dds.AD9858(platform.request("dds"))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||
|
||||
|
@ -8,9 +8,8 @@ from misoclib.mem.sdram.core.minicon import MiniconSettings
|
||||
from targets.pipistrello import BaseSoC
|
||||
|
||||
from artiq.gateware.soc import AMPSoC
|
||||
from artiq.gateware import rtio, ad9858, nist_qc1
|
||||
from artiq.gateware.rtio.phy import ttl_simple
|
||||
from artiq.gateware.rtio.phy.wishbone import RT2WB
|
||||
from artiq.gateware import rtio, nist_qc1
|
||||
from artiq.gateware.rtio.phy import ttl_simple, dds
|
||||
|
||||
|
||||
class _RTIOCRG(Module, AutoCSR):
|
||||
@ -116,10 +115,8 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
||||
|
||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||
self.submodules.dds = RenameClockDomains(
|
||||
ad9858.AD9858(platform.request("dds")),
|
||||
"rio")
|
||||
phy = RT2WB(7, self.dds.bus)
|
||||
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
||||
phy = dds.AD9858(platform.request("dds"))
|
||||
self.submodules += phy
|
||||
rtio_channels.append(rtio.Channel.from_phy(phy, ififo_depth=4))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user