Skip to content

Commit 34aacd3

Browse files
committedJul 8, 2015
complete AD9914 support (no programmable modulus, untested)
1 parent 0109821 commit 34aacd3

File tree

10 files changed

+221
-52
lines changed

10 files changed

+221
-52
lines changed
 

Diff for: ‎artiq/coredevice/dds.py

+22-5
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,14 @@ def batch_exit(self):
4646
syscall("dds_batch_exit")
4747

4848

49-
class DDS(AutoDB):
49+
class _DDSGeneric(AutoDB):
5050
"""Core device Direct Digital Synthesis (DDS) driver.
5151
5252
Controls one DDS channel managed directly by the core device's runtime.
5353
54+
This class should not be used directly, instead, use the chip-specific
55+
drivers such as ``AD9858`` and ``AD9914``.
56+
5457
:param sysclk: DDS system frequency.
5558
:param channel: channel number of the DDS device to control.
5659
"""
@@ -80,13 +83,13 @@ def ftw_to_frequency(self, ftw):
8083
def turns_to_pow(self, turns):
8184
"""Returns the phase offset word corresponding to the given phase
8285
in turns."""
83-
return round(turns*2**14)
86+
return round(turns*2**self.pow_width)
8487

8588
@portable
8689
def pow_to_turns(self, pow):
8790
"""Returns the phase in turns corresponding to the given phase offset
8891
word."""
89-
return pow/2**14
92+
return pow/2**self.pow_width
9093

9194
@kernel
9295
def init(self):
@@ -119,7 +122,9 @@ def set_phase_mode(self, phase_mode):
119122
def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT):
120123
"""Sets the DDS channel to the specified frequency and phase.
121124
122-
This uses machine units (FTW and POW).
125+
This uses machine units (FTW and POW). The frequency tuning word width
126+
is 32, whereas the phase offset word width depends on the type of DDS
127+
chip and can be retrieved via the ``pow_width`` attribute.
123128
124129
:param frequency: frequency to generate.
125130
:param phase: adds an offset, in turns, to the phase.
@@ -129,10 +134,22 @@ def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT):
129134
if phase_mode == _PHASE_MODE_DEFAULT:
130135
phase_mode = self.phase_mode
131136
syscall("dds_set", now_mu(), self.channel,
132-
frequency, round(phase*2**14), phase_mode)
137+
frequency, round(phase*2**self.pow_width), phase_mode)
133138

134139
@kernel
135140
def set(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT):
136141
"""Like ``set_mu``, but uses Hz and turns."""
137142
self.set_mu(self.frequency_to_ftw(frequency),
138143
self.turns_to_pow(phase), phase_mode)
144+
145+
146+
class AD9858(_DDSGeneric):
147+
"""Driver for AD9858 DDS chips. See ``_DDSGeneric`` for a description
148+
of the functionality."""
149+
pow_width = 14
150+
151+
152+
class AD9914(_DDSGeneric):
153+
"""Driver for AD9914 DDS chips. See ``_DDSGeneric`` for a description
154+
of the functionality."""
155+
pow_width = 16

Diff for: ‎artiq/gateware/ad9xxx.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class AD9xxx(Module):
1313
1414
Write to address 2**flen(pads.a) to pulse the FUD signal.
1515
Address 2**flen(pads.a)+1 is a GPIO register that controls the
16-
sel and reset signals. sel is mapped to the lower bits, followed by reset.
16+
sel and reset signals. rst is mapped to bit 0, followed by sel.
1717
1818
Write timing:
1919
Address is set one cycle before assertion of we_n.
@@ -58,11 +58,11 @@ def __init__(self, pads,
5858
gpio = Signal(flen(pads.sel) + 1)
5959
gpio_load = Signal()
6060
self.sync += If(gpio_load, gpio.eq(bus.dat_w))
61-
self.comb += pads.sel.eq(gpio),
6261
if hasattr(pads, "rst"):
63-
self.comb += pads.rst.eq(gpio[-1])
62+
self.comb += pads.rst.eq(gpio[0])
6463
else:
65-
self.comb += pads.rst_n.eq(~gpio[-1])
64+
self.comb += pads.rst_n.eq(~gpio[0])
65+
self.comb += pads.sel.eq(gpio[1:])
6666

6767
bus_r_gpio = Signal()
6868
self.comb += If(bus_r_gpio,

Diff for: ‎doc/manual/core_drivers_reference.rst

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ These drivers are for peripherals closely integrated into the core device, which
1212
:mod:`artiq.coredevice.dds` module
1313
----------------------------------
1414

15+
.. autoclass:: artiq.coredevice.dds._DDSGeneric
16+
:members:
17+
1518
.. automodule:: artiq.coredevice.dds
1619
:members:
1720

Diff for: ‎examples/master/ddb.pyon

+3-3
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,19 @@
6565
"dds0": {
6666
"type": "local",
6767
"module": "artiq.coredevice.dds",
68-
"class": "DDS",
68+
"class": "AD9858",
6969
"arguments": {"sysclk": 1e9, "channel": 0}
7070
},
7171
"dds1": {
7272
"type": "local",
7373
"module": "artiq.coredevice.dds",
74-
"class": "DDS",
74+
"class": "AD9858",
7575
"arguments": {"sysclk": 1e9, "channel": 1}
7676
},
7777
"dds2": {
7878
"type": "local",
7979
"module": "artiq.coredevice.dds",
80-
"class": "DDS",
80+
"class": "AD9858",
8181
"arguments": {"sysclk": 1e9, "channel": 2}
8282
},
8383

Diff for: ‎soc/runtime/bridge.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,15 @@ void bridge_main(void)
6666
struct msg_brg_dds_sel *msg;
6767

6868
msg = (struct msg_brg_dds_sel *)umsg;
69-
dds_write(DDS_GPIO, msg->channel);
69+
dds_write(DDS_GPIO, msg->channel << 1);
7070
mailbox_acknowledge();
7171
break;
7272
}
7373
case MESSAGE_TYPE_BRG_DDS_RESET: {
7474
unsigned int g;
7575

7676
g = dds_read(DDS_GPIO);
77-
dds_write(DDS_GPIO, g | (1 << 7));
77+
dds_write(DDS_GPIO, g | 1);
7878
dds_write(DDS_GPIO, g);
7979

8080
mailbox_acknowledge();

Diff for: ‎soc/runtime/dds.c

+82-11
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,24 @@
77
#include "dds.h"
88

99
#define DURATION_WRITE (5 << RTIO_FINE_TS_WIDTH)
10+
11+
#if defined DDS_AD9858
12+
/* Assume 8-bit bus */
1013
#define DURATION_INIT (7*DURATION_WRITE) /* not counting FUD */
1114
#define DURATION_PROGRAM (8*DURATION_WRITE) /* not counting FUD */
1215

16+
#elif defined DDS_AD9914
17+
/* Assume 16-bit bus */
18+
/* DAC calibration takes max. 135us as per datasheet. Take a good margin. */
19+
#define DURATION_DAC_CAL (30000 << RTIO_FINE_TS_WIDTH)
20+
/* not counting final FUD */
21+
#define DURATION_INIT (8*DURATION_WRITE + DURATION_DAC_CAL)
22+
#define DURATION_PROGRAM (5*DURATION_WRITE) /* not counting FUD */
23+
24+
#else
25+
#error Unknown DDS configuration
26+
#endif
27+
1328
#define DDS_WRITE(addr, data) do { \
1429
rtio_o_address_write(addr); \
1530
rtio_o_data_write(data); \
@@ -39,16 +54,43 @@ void dds_init(long long int timestamp, int channel)
3954

4055
now = timestamp - DURATION_INIT;
4156

57+
#ifdef DDS_ONEHOT_SEL
58+
channel = 1 << channel;
59+
#endif
60+
channel <<= 1;
4261
DDS_WRITE(DDS_GPIO, channel);
43-
DDS_WRITE(DDS_GPIO, channel | (1 << 5));
62+
DDS_WRITE(DDS_GPIO, channel | 1); /* reset */
4463
DDS_WRITE(DDS_GPIO, channel);
4564

46-
DDS_WRITE(0x00, 0x78);
47-
DDS_WRITE(0x01, 0x00);
48-
DDS_WRITE(0x02, 0x00);
49-
DDS_WRITE(0x03, 0x00);
65+
#ifdef DDS_AD9858
66+
/*
67+
* 2GHz divider disable
68+
* SYNCLK disable
69+
* Mixer power-down
70+
* Phase detect power down
71+
*/
72+
DDS_WRITE(DDS_CFR0, 0x78);
73+
DDS_WRITE(DDS_CFR1, 0x00);
74+
DDS_WRITE(DDS_CFR2, 0x00);
75+
DDS_WRITE(DDS_CFR3, 0x00);
76+
DDS_WRITE(DDS_FUD, 0);
77+
#endif
5078

79+
#ifdef DDS_AD9914
80+
/*
81+
* Enable cosine output (to match AD9858 behavior)
82+
* Enable DAC calibration
83+
* Leave SYNCLK enabled and PLL/divider disabled
84+
*/
85+
DDS_WRITE(DDS_CFR1L, 0x0008);
86+
DDS_WRITE(DDS_CFR1H, 0x0000);
87+
DDS_WRITE(DDS_CFR4H, 0x0105);
5188
DDS_WRITE(DDS_FUD, 0);
89+
/* Disable DAC calibration */
90+
now += DURATION_DAC_CAL;
91+
DDS_WRITE(DDS_CFR4H, 0x0005);
92+
DDS_WRITE(DDS_FUD, 0);
93+
#endif
5294
}
5395

5496
/* Compensation to keep phase continuity when switching from absolute or tracking
@@ -58,38 +100,67 @@ static unsigned int continuous_phase_comp[DDS_CHANNEL_COUNT];
58100
static void dds_set_one(long long int now, long long int ref_time, unsigned int channel,
59101
unsigned int ftw, unsigned int pow, int phase_mode)
60102
{
103+
unsigned int channel_enc;
104+
61105
if(channel >= DDS_CHANNEL_COUNT) {
62106
log("Attempted to set invalid DDS channel");
63107
return;
64108
}
65-
DDS_WRITE(DDS_GPIO, channel);
66-
109+
#ifdef DDS_ONEHOT_SEL
110+
channel_enc = 1 << channel;
111+
#else
112+
channel_enc = channel;
113+
#endif
114+
DDS_WRITE(DDS_GPIO, channel_enc << 1);
115+
116+
#ifdef DDS_AD9858
67117
DDS_WRITE(DDS_FTW0, ftw & 0xff);
68118
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
69119
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
70120
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
121+
#endif
122+
123+
#ifdef DDS_AD9914
124+
DDS_WRITE(DDS_FTWL, ftw & 0xffff);
125+
DDS_WRITE(DDS_FTWH, (ftw >> 16) & 0xffff);
126+
#endif
71127

72128
/* We need the RTIO fine timestamp clock to be phase-locked
73129
* to DDS SYSCLK, and divided by an integer DDS_RTIO_CLK_RATIO.
74130
*/
75131
if(phase_mode == PHASE_MODE_CONTINUOUS) {
76132
/* Do not clear phase accumulator on FUD */
77-
DDS_WRITE(0x02, 0x00);
133+
#ifdef DDS_AD9858
134+
DDS_WRITE(DDS_CFR2, 0x00);
135+
#endif
136+
#ifdef DDS_AD9914
137+
DDS_WRITE(DDS_CFR1L, 0x0008);
138+
#endif
78139
pow += continuous_phase_comp[channel];
79140
} else {
80141
long long int fud_time;
81142

82143
/* Clear phase accumulator on FUD */
83-
DDS_WRITE(0x02, 0x40);
144+
#ifdef DDS_AD9858
145+
DDS_WRITE(DDS_CFR2, 0x40);
146+
#endif
147+
#ifdef DDS_AD9914
148+
DDS_WRITE(DDS_CFR1L, 0x2008);
149+
#endif
84150
fud_time = now + 2*DURATION_WRITE;
85-
pow -= (ref_time - fud_time)*DDS_RTIO_CLK_RATIO*ftw >> 18;
151+
pow -= (ref_time - fud_time)*DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH);
86152
if(phase_mode == PHASE_MODE_TRACKING)
87-
pow += ref_time*DDS_RTIO_CLK_RATIO*ftw >> 18;
153+
pow += ref_time*DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH);
88154
continuous_phase_comp[channel] = pow;
89155
}
90156

157+
#ifdef DDS_AD9858
91158
DDS_WRITE(DDS_POW0, pow & 0xff);
92159
DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f);
160+
#endif
161+
#ifdef DDS_AD9914
162+
DDS_WRITE(DDS_POW, pow);
163+
#endif
93164
DDS_WRITE(DDS_FUD, 0);
94165
}
95166

Diff for: ‎soc/runtime/dds.h

+31-1
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22
#define __DDS_H
33

44
#include <hw/common.h>
5+
#include <generated/csr.h>
56
#include <generated/mem.h>
67

78
/* Maximum number of commands in a batch */
89
#define DDS_MAX_BATCH 16
910

10-
/* DDS core registers */
11+
#ifdef DDS_AD9858
12+
#define DDS_CFR0 0x00
13+
#define DDS_CFR1 0x01
14+
#define DDS_CFR2 0x02
15+
#define DDS_CFR3 0x03
1116
#define DDS_FTW0 0x0a
1217
#define DDS_FTW1 0x0b
1318
#define DDS_FTW2 0x0c
@@ -16,6 +21,31 @@
1621
#define DDS_POW1 0x0f
1722
#define DDS_FUD 0x40
1823
#define DDS_GPIO 0x41
24+
#endif
25+
26+
#ifdef DDS_AD9914
27+
#define DDS_CFR1L 0x01
28+
#define DDS_CFR1H 0x03
29+
#define DDS_CFR2L 0x05
30+
#define DDS_CFR2H 0x07
31+
#define DDS_CFR3L 0x09
32+
#define DDS_CFR3H 0x0b
33+
#define DDS_CFR4L 0x0d
34+
#define DDS_CFR4H 0x0f
35+
#define DDS_FTWL 0x2d
36+
#define DDS_FTWH 0x2f
37+
#define DDS_POW 0x31
38+
#define DDS_FUD 0x80
39+
#define DDS_GPIO 0x81
40+
#endif
41+
42+
#ifdef DDS_AD9858
43+
#define DDS_POW_WIDTH 14
44+
#endif
45+
46+
#ifdef DDS_AD9914
47+
#define DDS_POW_WIDTH 16
48+
#endif
1949

2050
enum {
2151
PHASE_MODE_CONTINUOUS = 0,

Diff for: ‎soc/runtime/main.c

+10-14
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <uart.h>
55
#include <console.h>
66
#include <system.h>
7-
#include <time.h>
87
#include <generated/csr.h>
98
#include <hw/flags.h>
109

@@ -32,7 +31,6 @@
3231

3332
static void common_init(void)
3433
{
35-
clock_init();
3634
brg_start();
3735
brg_ddsinitall();
3836
kloader_stop();
@@ -211,34 +209,31 @@ static void regular_main(void)
211209

212210
static void blink_led(void)
213211
{
214-
int i, ev, p;
212+
int i;
213+
long long int t;
215214

216-
p = identifier_frequency_read()/10;
217-
time_init();
218215
for(i=0;i<3;i++) {
219216
leds_out_write(1);
220-
while(!elapsed(&ev, p));
217+
t = clock_get_ms();
218+
while(clock_get_ms() < t + 250);
221219
leds_out_write(0);
222-
while(!elapsed(&ev, p));
220+
t = clock_get_ms();
221+
while(clock_get_ms() < t + 250);
223222
}
224223
}
225224

226225
static int check_test_mode(void)
227226
{
228227
char c;
228+
long long int t;
229229

230-
timer0_en_write(0);
231-
timer0_reload_write(0);
232-
timer0_load_write(identifier_frequency_read() >> 2);
233-
timer0_en_write(1);
234-
timer0_update_value_write(1);
235-
while(timer0_value_read()) {
230+
t = clock_get_ms();
231+
while(clock_get_ms() < t + 1000) {
236232
if(readchar_nonblock()) {
237233
c = readchar();
238234
if((c == 't')||(c == 'T'))
239235
return 1;
240236
}
241-
timer0_update_value_write(1);
242237
}
243238
return 0;
244239
}
@@ -251,6 +246,7 @@ int main(void)
251246

252247
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
253248

249+
clock_init();
254250
puts("Press 't' to enter test mode...");
255251
blink_led();
256252

Diff for: ‎soc/runtime/test_mode.c

+63-12
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "dds.h"
1111
#include "flash_storage.h"
1212
#include "bridge_ctl.h"
13+
#include "clock.h"
1314
#include "test_mode.h"
1415

1516
static void leds(char *value)
@@ -114,6 +115,9 @@ static void ddssel(char *n)
114115
return;
115116
}
116117

118+
#ifdef DDS_ONEHOT_SEL
119+
n2 = 1 << n2;
120+
#endif
117121
brg_ddssel(n2);
118122
}
119123

@@ -157,7 +161,12 @@ static void ddsr(char *addr)
157161
return;
158162
}
159163

164+
#ifdef DDS_AD9858
160165
printf("0x%02x\n", brg_ddsread(addr2));
166+
#endif
167+
#ifdef DDS_AD9914
168+
printf("0x%04x\n", brg_ddsread(addr2));
169+
#endif
161170
}
162171

163172
static void ddsfud(void)
@@ -186,11 +195,22 @@ static void ddsftw(char *n, char *ftw)
186195
return;
187196
}
188197

198+
#ifdef DDS_ONEHOT_SEL
199+
n2 = 1 << n2;
200+
#endif
189201
brg_ddssel(n2);
202+
203+
#ifdef DDS_AD9858
190204
brg_ddswrite(DDS_FTW0, ftw2 & 0xff);
191205
brg_ddswrite(DDS_FTW1, (ftw2 >> 8) & 0xff);
192206
brg_ddswrite(DDS_FTW2, (ftw2 >> 16) & 0xff);
193207
brg_ddswrite(DDS_FTW3, (ftw2 >> 24) & 0xff);
208+
#endif
209+
#ifdef DDS_AD9914
210+
brg_ddswrite(DDS_FTWL, ftw2 & 0xffff);
211+
brg_ddswrite(DDS_FTWH, (ftw2 >> 16) & 0xffff);
212+
#endif
213+
194214
brg_ddsfud();
195215
}
196216

@@ -199,15 +219,34 @@ static void ddsreset(void)
199219
brg_ddsreset();
200220
}
201221

222+
#ifdef DDS_AD9858
202223
static void ddsinit(void)
203224
{
204225
brg_ddsreset();
205-
brg_ddswrite(0x00, 0x78);
206-
brg_ddswrite(0x01, 0x00);
207-
brg_ddswrite(0x02, 0x00);
208-
brg_ddswrite(0x03, 0x00);
226+
brg_ddswrite(DDS_CFR0, 0x78);
227+
brg_ddswrite(DDS_CFR1, 0x00);
228+
brg_ddswrite(DDS_CFR2, 0x00);
229+
brg_ddswrite(DDS_CFR3, 0x00);
209230
brg_ddsfud();
210231
}
232+
#endif
233+
234+
#ifdef DDS_AD9914
235+
static void ddsinit(void)
236+
{
237+
long long int t;
238+
239+
brg_ddsreset();
240+
brg_ddswrite(DDS_CFR1L, 0x0008);
241+
brg_ddswrite(DDS_CFR1H, 0x0000);
242+
brg_ddswrite(DDS_CFR4H, 0x0105);
243+
brg_ddswrite(DDS_FUD, 0);
244+
t = clock_get_ms();
245+
while(clock_get_ms() < t + 2);
246+
brg_ddswrite(DDS_CFR4H, 0x0005);
247+
brg_ddsfud();
248+
}
249+
#endif
211250

212251
static void ddstest_one(unsigned int i)
213252
{
@@ -223,15 +262,27 @@ static void ddstest_one(unsigned int i)
223262

224263
for(j=0; j<12; j++) {
225264
f = v[j];
226-
brg_ddswrite(0x0a, f & 0xff);
227-
brg_ddswrite(0x0b, (f >> 8) & 0xff);
228-
brg_ddswrite(0x0c, (f >> 16) & 0xff);
229-
brg_ddswrite(0x0d, (f >> 24) & 0xff);
265+
#ifdef DDS_AD9858
266+
brg_ddswrite(DDS_FTW0, f & 0xff);
267+
brg_ddswrite(DDS_FTW1, (f >> 8) & 0xff);
268+
brg_ddswrite(DDS_FTW2, (f >> 16) & 0xff);
269+
brg_ddswrite(DDS_FTW3, (f >> 24) & 0xff);
270+
#endif
271+
#ifdef DDS_AD9914
272+
brg_ddswrite(DDS_FTWL, f & 0xffff);
273+
brg_ddswrite(DDS_FTWH, (f >> 16) & 0xffff);
274+
#endif
230275
brg_ddsfud();
231-
g = brg_ddsread(0x0a);
232-
g |= brg_ddsread(0x0b) << 8;
233-
g |= brg_ddsread(0x0c) << 16;
234-
g |= brg_ddsread(0x0d) << 24;
276+
#ifdef DDS_AD9858
277+
g = brg_ddsread(DDS_FTW0);
278+
g |= brg_ddsread(DDS_FTW1) << 8;
279+
g |= brg_ddsread(DDS_FTW2) << 16;
280+
g |= brg_ddsread(DDS_FTW3) << 24;
281+
#endif
282+
#ifdef DDS_AD9914
283+
g = brg_ddsread(DDS_FTWL);
284+
g |= brg_ddsread(DDS_FTWH) << 16;
285+
#endif
235286
if(g != f)
236287
printf("readback fail on DDS %d, 0x%08x != 0x%08x\n", i, g, f);
237288
}

Diff for: ‎soc/targets/artiq_pipistrello.py

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def __init__(self, platform, cpu_type="or1k", **kwargs):
119119

120120
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
121121
self.add_constant("DDS_CHANNEL_COUNT", 8)
122+
self.add_constant("DDS_AD9858")
122123
phy = dds.AD9858(platform.request("dds"), 8)
123124
self.submodules += phy
124125
rtio_channels.append(rtio.Channel.from_phy(phy,

0 commit comments

Comments
 (0)
Please sign in to comment.