Skip to content

Commit a36c51e

Browse files
committedMay 8, 2015
DDS over RTIO (batch mode not supported yet)
1 parent a91bb48 commit a36c51e

File tree

17 files changed

+200
-270
lines changed

17 files changed

+200
-270
lines changed
 

Diff for: ‎artiq/coredevice/dds.py

+18-77
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from artiq.language.core import *
22
from artiq.language.db import *
33
from artiq.language.units import *
4-
from artiq.coredevice import ttl
54

65

76
PHASE_MODE_DEFAULT = -1
7+
# keep in sync with dds.h
88
PHASE_MODE_CONTINUOUS = 0
99
PHASE_MODE_ABSOLUTE = 1
1010
PHASE_MODE_TRACKING = 2
@@ -13,45 +13,39 @@
1313
class DDS(AutoDB):
1414
"""Core device Direct Digital Synthesis (DDS) driver.
1515
16-
Controls DDS devices managed directly by the core device's runtime. It also
17-
uses a RTIO TTL channel (through :class:`artiq.coredevice.ttl.TTLOut`) to
18-
control a RF switch that gates the output of the DDS device.
16+
Controls DDS devices managed directly by the core device's runtime.
1917
2018
:param dds_sysclk: DDS system frequency, used for computing the frequency
2119
tuning words.
22-
:param reg_channel: channel number of the DDS device to control.
23-
:param rtio_switch: RTIO channel number of the RF switch associated with
24-
the DDS device.
25-
20+
:param channel: channel number of the DDS device to control.
2621
"""
2722
class DBKeys:
2823
core = Device()
29-
dds_sysclk = Parameter(1*GHz)
30-
reg_channel = Argument()
31-
rtio_switch = Argument()
24+
dds_sysclk = Argument(1*GHz)
25+
channel = Argument()
3226

3327
def build(self):
34-
self.previous_on = False
35-
self.previous_frequency = 0*MHz
36-
self.set_phase_mode(PHASE_MODE_CONTINUOUS)
37-
self.sw = ttl.TTLOut(core=self.core, channel=self.rtio_switch)
28+
self.phase_mode = PHASE_MODE_CONTINUOUS
3829

3930
@portable
4031
def frequency_to_ftw(self, frequency):
4132
"""Returns the frequency tuning word corresponding to the given
4233
frequency.
43-
4434
"""
4535
return round(2**32*frequency/self.dds_sysclk)
4636

4737
@portable
4838
def ftw_to_frequency(self, ftw):
4939
"""Returns the frequency corresponding to the given frequency tuning
5040
word.
51-
5241
"""
5342
return ftw*self.dds_sysclk/2**32
5443

44+
@kernel
45+
def init(self):
46+
"""Resets and initializes the DDS."""
47+
syscall("dds_init", time_to_cycles(now()), self.channel)
48+
5549
@kernel
5650
def set_phase_mode(self, phase_mode):
5751
"""Sets the phase mode of the DDS channel. Supported phase modes are:
@@ -69,74 +63,21 @@ def set_phase_mode(self, phase_mode):
6963
accumulator is set to the value it would have if the DDS had been
7064
running at the specified frequency since the start of the
7165
experiment.
72-
7366
"""
7467
self.phase_mode = phase_mode
75-
syscall("dds_phase_clear_en", self.reg_channel,
76-
self.phase_mode != PHASE_MODE_CONTINUOUS)
7768

7869
@kernel
79-
def on(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
80-
"""Sets the DDS channel to the specified frequency and turns it on.
81-
82-
If the DDS channel was already on, a real-time frequency and phase
83-
update is performed.
70+
def set(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
71+
"""Sets the DDS channel to the specified frequency and phase.
8472
8573
:param frequency: frequency to generate.
8674
:param phase_mode: if specified, overrides the default phase mode set
8775
by ``set_phase_mode`` for this call.
8876
:param phase_offset: adds an offset, in turns, to the phase.
89-
90-
"""
91-
if phase_mode != PHASE_MODE_DEFAULT:
92-
old_phase_mode = self.phase_mode
93-
self.set_phase_mode(phase_mode)
94-
95-
if self.previous_frequency != frequency:
96-
merge = self.sw.o_previous_timestamp == time_to_cycles(now())
97-
if not merge:
98-
self.sw.sync()
99-
# Channel is already on:
100-
# Precise timing of frequency change is required.
101-
# Channel is off:
102-
# Use soft timing on FUD to prevent conflicts when reprogramming
103-
# several channels that need to be turned on at the same time.
104-
rt_fud = merge or self.previous_on
105-
if self.phase_mode != PHASE_MODE_CONTINUOUS:
106-
sysclk_per_microcycle = int(self.dds_sysclk*
107-
self.core.ref_period)
108-
else:
109-
sysclk_per_microcycle = 0
110-
syscall("dds_program", time_to_cycles(now()), self.reg_channel,
111-
self.frequency_to_ftw(frequency), int(phase_offset*2**14),
112-
sysclk_per_microcycle,
113-
rt_fud, self.phase_mode == PHASE_MODE_TRACKING)
114-
self.previous_frequency = frequency
115-
self.sw.on()
116-
self.previous_on = True
117-
118-
if phase_mode != PHASE_MODE_DEFAULT:
119-
self.set_phase_mode(old_phase_mode)
120-
121-
@kernel
122-
def off(self):
123-
"""Turns the DDS channel off.
124-
12577
"""
126-
self.sw.off()
127-
self.previous_on = False
78+
if phase_mode == PHASE_MODE_DEFAULT:
79+
phase_mode = self.phase_mode
12880

129-
@kernel
130-
def pulse(self, frequency, duration,
131-
phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
132-
"""Pulses the DDS channel for the specified duration at the specified
133-
frequency.
134-
135-
See ``on`` for a description of the parameters.
136-
137-
Equivalent to a ``on``, ``delay``, ``off`` sequence.
138-
139-
"""
140-
self.on(frequency, phase_mode, phase_offset)
141-
delay(duration)
142-
self.off()
81+
syscall("dds_set", time_to_cycles(now()), self.channel,
82+
self.frequency_to_ftw(frequency), round(phase_offset*2**14),
83+
self.phase_mode)

Diff for: ‎artiq/coredevice/runtime.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
"rtio_set_sensitivity": "Iii:n",
2222
"rtio_get_counter": "n:I",
2323
"rtio_get": "iI:I",
24-
"dds_phase_clear_en": "ib:n",
25-
"dds_program": "Iiiiibb:n",
24+
"dds_init": "Ii:n",
25+
"dds_set": "Iiiii:n",
2626
}
2727

2828

Diff for: ‎artiq/gateware/ad9858.py

+14-16
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class AD9858(Module):
3636
3737
Read timing:
3838
Address is set one cycle before assertion of rd_n.
39-
rd_n is asserted for 3 cycles.
40-
Data is sampled 2 cycles into the assertion of rd_n.
39+
rd_n is asserted for read_wait_cycles, data is sampled at the end.
40+
rd_n is deasserted and data bus is not driven again before hiz_wait_cycles.
4141
4242
Design:
4343
All IO pads are registered.
@@ -48,7 +48,7 @@ class AD9858(Module):
4848
Round-trip addr A setup (> RX, RD, D to Z), RD prop, D valid (< D
4949
valid), D prop is ~15 + 10 + 20 + 10 = 55ns
5050
"""
51-
def __init__(self, pads, drive_fud=False,
51+
def __init__(self, pads,
5252
read_wait_cycles=10, hiz_wait_cycles=3,
5353
bus=None):
5454
if bus is None:
@@ -84,9 +84,8 @@ def __init__(self, pads, drive_fud=False,
8484
bus.dat_r.eq(dr)
8585
)
8686

87-
if drive_fud:
88-
fud = Signal()
89-
self.sync += pads.fud_n.eq(~fud)
87+
fud = Signal()
88+
self.sync += pads.fud_n.eq(~fud)
9089

9190
pads.wr_n.reset = 1
9291
pads.rd_n.reset = 1
@@ -106,7 +105,7 @@ def __init__(self, pads, drive_fud=False,
106105
If(bus.adr[0],
107106
NextState("GPIO")
108107
).Else(
109-
NextState("FUD") if drive_fud else None
108+
NextState("FUD")
110109
)
111110
).Else(
112111
If(bus.we,
@@ -141,19 +140,18 @@ def __init__(self, pads, drive_fud=False,
141140
)
142141
fsm.act("WAIT_HIZ",
143142
rx.eq(1),
144-
# For some reason, AD9858 has a address hold time to RD inactive.
143+
# For some reason, AD9858 has an address hold time to RD inactive.
145144
hold_address.eq(1),
146145
self.hiz_timer.wait.eq(1),
147146
If(self.hiz_timer.done, NextState("IDLE"))
148147
)
149-
if drive_fud:
150-
fsm.act("FUD",
151-
# 4ns FUD setup to SYNCLK
152-
# 0ns FUD hold to SYNCLK
153-
fud.eq(1),
154-
bus.ack.eq(1),
155-
NextState("IDLE")
156-
)
148+
fsm.act("FUD",
149+
# 4ns FUD setup to SYNCLK
150+
# 0ns FUD hold to SYNCLK
151+
fud.eq(1),
152+
bus.ack.eq(1),
153+
NextState("IDLE")
154+
)
157155
fsm.act("GPIO",
158156
bus.ack.eq(1),
159157
bus_r_gpio.eq(1),

Diff for: ‎artiq/gateware/rtio/core.py

+4
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,10 @@ def __init__(self, channels, clk_freq, full_ts_width=63,
291291
fine_ts_width = max(rtlink.get_fine_ts_width(c.interface)
292292
for c in channels)
293293

294+
self.data_width = data_width
295+
self.address_width = address_width
296+
self.fine_ts_width = fine_ts_width
297+
294298
# CSRs
295299
self.kcsrs = _KernelCSRs(bits_for(len(channels)-1),
296300
data_width, address_width,

Diff for: ‎artiq/gateware/rtio/phy/wishbone.py

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from migen.fhdl.std import *
2+
from migen.bus import wishbone
23

34
from artiq.gateware.rtio import rtlink
45

56

67
class RT2WB(Module):
7-
def __init__(self, wb, address_width):
8+
def __init__(self, address_width, wb=None):
9+
if wb is None:
10+
wb = wishbone.Interface()
11+
self.wb = wb
812
self.rtlink = rtlink.Interface(
913
rtlink.OInterface(
1014
flen(wb.dat_w),
@@ -18,7 +22,7 @@ def __init__(self, wb, address_width):
1822
# # #
1923

2024
active = Signal()
21-
self.sync.rio_phy += [
25+
self.sync.rio += [
2226
If(self.rtlink.o.stb,
2327
active.eq(1),
2428
wb.adr.eq(self.rtlink.o.address[:address_width]),
@@ -35,6 +39,6 @@ def __init__(self, wb, address_width):
3539
wb.cyc.eq(active),
3640
wb.stb.eq(active),
3741

38-
self.i.stb.eq(wb.ack & ~wb.we),
39-
self.i.data.eq(wb.dat_r)
42+
self.rtlink.i.stb.eq(wb.ack & ~wb.we),
43+
self.rtlink.i.data.eq(wb.dat_r)
4044
]

Diff for: ‎examples/master/ddb.pyon

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,19 +54,19 @@
5454
"type": "local",
5555
"module": "artiq.coredevice.dds",
5656
"class": "DDS",
57-
"arguments": {"reg_channel": 0, "rtio_switch": 5}
57+
"arguments": {"channel": 0}
5858
},
5959
"dds1": {
6060
"type": "local",
6161
"module": "artiq.coredevice.dds",
6262
"class": "DDS",
63-
"arguments": {"reg_channel": 1, "rtio_switch": 6}
63+
"arguments": {"channel": 1}
6464
},
6565
"dds2": {
6666
"type": "local",
6767
"module": "artiq.coredevice.dds",
6868
"class": "DDS",
69-
"arguments": {"reg_channel": 2, "rtio_switch": 7}
69+
"arguments": {"channel": 2}
7070
},
7171

7272
"qc_q1_0": {

Diff for: ‎examples/master/repository/dds_test.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,26 @@ class DBKeys:
99
dds0 = Device()
1010
dds1 = Device()
1111
dds2 = Device()
12+
ttl0 = Device()
13+
ttl1 = Device()
14+
ttl2 = Device()
1215
led = Device()
1316

1417
@kernel
1518
def run(self):
19+
# with dds_batch:
20+
# self.dds1.set(120*MHz)
21+
# self.dds2.set(200*MHz)
22+
1623
for i in range(10000):
1724
if i & 0x200:
1825
self.led.on()
1926
else:
2027
self.led.off()
2128
with parallel:
2229
with sequential:
23-
self.dds0.pulse(100*MHz + 4*i*kHz, 500*us)
24-
self.dds1.pulse(120*MHz, 500*us)
25-
self.dds2.pulse(200*MHz, 100*us)
30+
self.dds0.set(100*MHz + 4*i*kHz)
31+
self.ttl0.pulse(500*us)
32+
self.ttl1.pulse(500*us)
33+
self.ttl2.pulse(100*us)
2634
self.led.off()

Diff for: ‎soc/runtime/Makefile

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ ksupport.elf: $(OBJECTS_KSUPPORT)
3434
-T ksupport.ld \
3535
-N -o $@ \
3636
$(MSCDIR)/software/libbase/crt0-$(CPU).o \
37-
$^
37+
$^ \
38+
-L$(MSCDIR)/software/libcompiler-rt \
39+
-lcompiler-rt
3840
@chmod -x $@
3941

4042
ksupport_data.o: ksupport.bin

0 commit comments

Comments
 (0)
Please sign in to comment.