mirror of https://github.com/m-labs/artiq.git
complete AD9914 support (no programmable modulus, untested)
This commit is contained in:
parent
0109821078
commit
34aacd3c5f
|
@ -46,11 +46,14 @@ class DDSBus(AutoDB):
|
||||||
syscall("dds_batch_exit")
|
syscall("dds_batch_exit")
|
||||||
|
|
||||||
|
|
||||||
class DDS(AutoDB):
|
class _DDSGeneric(AutoDB):
|
||||||
"""Core device Direct Digital Synthesis (DDS) driver.
|
"""Core device Direct Digital Synthesis (DDS) driver.
|
||||||
|
|
||||||
Controls one DDS channel managed directly by the core device's runtime.
|
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 sysclk: DDS system frequency.
|
||||||
:param channel: channel number of the DDS device to control.
|
:param channel: channel number of the DDS device to control.
|
||||||
"""
|
"""
|
||||||
|
@ -80,13 +83,13 @@ class DDS(AutoDB):
|
||||||
def turns_to_pow(self, turns):
|
def turns_to_pow(self, turns):
|
||||||
"""Returns the phase offset word corresponding to the given phase
|
"""Returns the phase offset word corresponding to the given phase
|
||||||
in turns."""
|
in turns."""
|
||||||
return round(turns*2**14)
|
return round(turns*2**self.pow_width)
|
||||||
|
|
||||||
@portable
|
@portable
|
||||||
def pow_to_turns(self, pow):
|
def pow_to_turns(self, pow):
|
||||||
"""Returns the phase in turns corresponding to the given phase offset
|
"""Returns the phase in turns corresponding to the given phase offset
|
||||||
word."""
|
word."""
|
||||||
return pow/2**14
|
return pow/2**self.pow_width
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def init(self):
|
def init(self):
|
||||||
|
@ -119,7 +122,9 @@ class DDS(AutoDB):
|
||||||
def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT):
|
def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT):
|
||||||
"""Sets the DDS channel to the specified frequency and phase.
|
"""Sets the DDS channel to the specified frequency and phase.
|
||||||
|
|
||||||
This uses machine units (FTW and POW).
|
This uses machine units (FTW and POW). The frequency tuning word width
|
||||||
|
is 32, whereas the phase offset word width depends on the type of DDS
|
||||||
|
chip and can be retrieved via the ``pow_width`` attribute.
|
||||||
|
|
||||||
:param frequency: frequency to generate.
|
:param frequency: frequency to generate.
|
||||||
:param phase: adds an offset, in turns, to the phase.
|
:param phase: adds an offset, in turns, to the phase.
|
||||||
|
@ -129,10 +134,22 @@ class DDS(AutoDB):
|
||||||
if phase_mode == _PHASE_MODE_DEFAULT:
|
if phase_mode == _PHASE_MODE_DEFAULT:
|
||||||
phase_mode = self.phase_mode
|
phase_mode = self.phase_mode
|
||||||
syscall("dds_set", now_mu(), self.channel,
|
syscall("dds_set", now_mu(), self.channel,
|
||||||
frequency, round(phase*2**14), phase_mode)
|
frequency, round(phase*2**self.pow_width), phase_mode)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def set(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT):
|
def set(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT):
|
||||||
"""Like ``set_mu``, but uses Hz and turns."""
|
"""Like ``set_mu``, but uses Hz and turns."""
|
||||||
self.set_mu(self.frequency_to_ftw(frequency),
|
self.set_mu(self.frequency_to_ftw(frequency),
|
||||||
self.turns_to_pow(phase), phase_mode)
|
self.turns_to_pow(phase), phase_mode)
|
||||||
|
|
||||||
|
|
||||||
|
class AD9858(_DDSGeneric):
|
||||||
|
"""Driver for AD9858 DDS chips. See ``_DDSGeneric`` for a description
|
||||||
|
of the functionality."""
|
||||||
|
pow_width = 14
|
||||||
|
|
||||||
|
|
||||||
|
class AD9914(_DDSGeneric):
|
||||||
|
"""Driver for AD9914 DDS chips. See ``_DDSGeneric`` for a description
|
||||||
|
of the functionality."""
|
||||||
|
pow_width = 16
|
||||||
|
|
|
@ -13,7 +13,7 @@ class AD9xxx(Module):
|
||||||
|
|
||||||
Write to address 2**flen(pads.a) to pulse the FUD signal.
|
Write to address 2**flen(pads.a) to pulse the FUD signal.
|
||||||
Address 2**flen(pads.a)+1 is a GPIO register that controls the
|
Address 2**flen(pads.a)+1 is a GPIO register that controls the
|
||||||
sel and reset signals. sel is mapped to the lower bits, followed by reset.
|
sel and reset signals. rst is mapped to bit 0, followed by sel.
|
||||||
|
|
||||||
Write timing:
|
Write timing:
|
||||||
Address is set one cycle before assertion of we_n.
|
Address is set one cycle before assertion of we_n.
|
||||||
|
@ -58,11 +58,11 @@ class AD9xxx(Module):
|
||||||
gpio = Signal(flen(pads.sel) + 1)
|
gpio = Signal(flen(pads.sel) + 1)
|
||||||
gpio_load = Signal()
|
gpio_load = Signal()
|
||||||
self.sync += If(gpio_load, gpio.eq(bus.dat_w))
|
self.sync += If(gpio_load, gpio.eq(bus.dat_w))
|
||||||
self.comb += pads.sel.eq(gpio),
|
|
||||||
if hasattr(pads, "rst"):
|
if hasattr(pads, "rst"):
|
||||||
self.comb += pads.rst.eq(gpio[-1])
|
self.comb += pads.rst.eq(gpio[0])
|
||||||
else:
|
else:
|
||||||
self.comb += pads.rst_n.eq(~gpio[-1])
|
self.comb += pads.rst_n.eq(~gpio[0])
|
||||||
|
self.comb += pads.sel.eq(gpio[1:])
|
||||||
|
|
||||||
bus_r_gpio = Signal()
|
bus_r_gpio = Signal()
|
||||||
self.comb += If(bus_r_gpio,
|
self.comb += If(bus_r_gpio,
|
||||||
|
|
|
@ -12,6 +12,9 @@ These drivers are for peripherals closely integrated into the core device, which
|
||||||
:mod:`artiq.coredevice.dds` module
|
:mod:`artiq.coredevice.dds` module
|
||||||
----------------------------------
|
----------------------------------
|
||||||
|
|
||||||
|
.. autoclass:: artiq.coredevice.dds._DDSGeneric
|
||||||
|
:members:
|
||||||
|
|
||||||
.. automodule:: artiq.coredevice.dds
|
.. automodule:: artiq.coredevice.dds
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
|
@ -65,19 +65,19 @@
|
||||||
"dds0": {
|
"dds0": {
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "AD9858",
|
||||||
"arguments": {"sysclk": 1e9, "channel": 0}
|
"arguments": {"sysclk": 1e9, "channel": 0}
|
||||||
},
|
},
|
||||||
"dds1": {
|
"dds1": {
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "AD9858",
|
||||||
"arguments": {"sysclk": 1e9, "channel": 1}
|
"arguments": {"sysclk": 1e9, "channel": 1}
|
||||||
},
|
},
|
||||||
"dds2": {
|
"dds2": {
|
||||||
"type": "local",
|
"type": "local",
|
||||||
"module": "artiq.coredevice.dds",
|
"module": "artiq.coredevice.dds",
|
||||||
"class": "DDS",
|
"class": "AD9858",
|
||||||
"arguments": {"sysclk": 1e9, "channel": 2}
|
"arguments": {"sysclk": 1e9, "channel": 2}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ void bridge_main(void)
|
||||||
struct msg_brg_dds_sel *msg;
|
struct msg_brg_dds_sel *msg;
|
||||||
|
|
||||||
msg = (struct msg_brg_dds_sel *)umsg;
|
msg = (struct msg_brg_dds_sel *)umsg;
|
||||||
dds_write(DDS_GPIO, msg->channel);
|
dds_write(DDS_GPIO, msg->channel << 1);
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ void bridge_main(void)
|
||||||
unsigned int g;
|
unsigned int g;
|
||||||
|
|
||||||
g = dds_read(DDS_GPIO);
|
g = dds_read(DDS_GPIO);
|
||||||
dds_write(DDS_GPIO, g | (1 << 7));
|
dds_write(DDS_GPIO, g | 1);
|
||||||
dds_write(DDS_GPIO, g);
|
dds_write(DDS_GPIO, g);
|
||||||
|
|
||||||
mailbox_acknowledge();
|
mailbox_acknowledge();
|
||||||
|
|
|
@ -7,9 +7,24 @@
|
||||||
#include "dds.h"
|
#include "dds.h"
|
||||||
|
|
||||||
#define DURATION_WRITE (5 << RTIO_FINE_TS_WIDTH)
|
#define DURATION_WRITE (5 << RTIO_FINE_TS_WIDTH)
|
||||||
|
|
||||||
|
#if defined DDS_AD9858
|
||||||
|
/* Assume 8-bit bus */
|
||||||
#define DURATION_INIT (7*DURATION_WRITE) /* not counting FUD */
|
#define DURATION_INIT (7*DURATION_WRITE) /* not counting FUD */
|
||||||
#define DURATION_PROGRAM (8*DURATION_WRITE) /* not counting FUD */
|
#define DURATION_PROGRAM (8*DURATION_WRITE) /* not counting FUD */
|
||||||
|
|
||||||
|
#elif defined DDS_AD9914
|
||||||
|
/* Assume 16-bit bus */
|
||||||
|
/* DAC calibration takes max. 135us as per datasheet. Take a good margin. */
|
||||||
|
#define DURATION_DAC_CAL (30000 << RTIO_FINE_TS_WIDTH)
|
||||||
|
/* not counting final FUD */
|
||||||
|
#define DURATION_INIT (8*DURATION_WRITE + DURATION_DAC_CAL)
|
||||||
|
#define DURATION_PROGRAM (5*DURATION_WRITE) /* not counting FUD */
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error Unknown DDS configuration
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DDS_WRITE(addr, data) do { \
|
#define DDS_WRITE(addr, data) do { \
|
||||||
rtio_o_address_write(addr); \
|
rtio_o_address_write(addr); \
|
||||||
rtio_o_data_write(data); \
|
rtio_o_data_write(data); \
|
||||||
|
@ -39,16 +54,43 @@ void dds_init(long long int timestamp, int channel)
|
||||||
|
|
||||||
now = timestamp - DURATION_INIT;
|
now = timestamp - DURATION_INIT;
|
||||||
|
|
||||||
|
#ifdef DDS_ONEHOT_SEL
|
||||||
|
channel = 1 << channel;
|
||||||
|
#endif
|
||||||
|
channel <<= 1;
|
||||||
DDS_WRITE(DDS_GPIO, channel);
|
DDS_WRITE(DDS_GPIO, channel);
|
||||||
DDS_WRITE(DDS_GPIO, channel | (1 << 5));
|
DDS_WRITE(DDS_GPIO, channel | 1); /* reset */
|
||||||
DDS_WRITE(DDS_GPIO, channel);
|
DDS_WRITE(DDS_GPIO, channel);
|
||||||
|
|
||||||
DDS_WRITE(0x00, 0x78);
|
#ifdef DDS_AD9858
|
||||||
DDS_WRITE(0x01, 0x00);
|
/*
|
||||||
DDS_WRITE(0x02, 0x00);
|
* 2GHz divider disable
|
||||||
DDS_WRITE(0x03, 0x00);
|
* SYNCLK disable
|
||||||
|
* Mixer power-down
|
||||||
|
* Phase detect power down
|
||||||
|
*/
|
||||||
|
DDS_WRITE(DDS_CFR0, 0x78);
|
||||||
|
DDS_WRITE(DDS_CFR1, 0x00);
|
||||||
|
DDS_WRITE(DDS_CFR2, 0x00);
|
||||||
|
DDS_WRITE(DDS_CFR3, 0x00);
|
||||||
DDS_WRITE(DDS_FUD, 0);
|
DDS_WRITE(DDS_FUD, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
/*
|
||||||
|
* Enable cosine output (to match AD9858 behavior)
|
||||||
|
* Enable DAC calibration
|
||||||
|
* Leave SYNCLK enabled and PLL/divider disabled
|
||||||
|
*/
|
||||||
|
DDS_WRITE(DDS_CFR1L, 0x0008);
|
||||||
|
DDS_WRITE(DDS_CFR1H, 0x0000);
|
||||||
|
DDS_WRITE(DDS_CFR4H, 0x0105);
|
||||||
|
DDS_WRITE(DDS_FUD, 0);
|
||||||
|
/* Disable DAC calibration */
|
||||||
|
now += DURATION_DAC_CAL;
|
||||||
|
DDS_WRITE(DDS_CFR4H, 0x0005);
|
||||||
|
DDS_WRITE(DDS_FUD, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compensation to keep phase continuity when switching from absolute or tracking
|
/* Compensation to keep phase continuity when switching from absolute or tracking
|
||||||
|
@ -58,38 +100,67 @@ static unsigned int continuous_phase_comp[DDS_CHANNEL_COUNT];
|
||||||
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, unsigned int channel,
|
||||||
unsigned int ftw, unsigned int pow, int phase_mode)
|
unsigned int ftw, unsigned int pow, int phase_mode)
|
||||||
{
|
{
|
||||||
|
unsigned int channel_enc;
|
||||||
|
|
||||||
if(channel >= DDS_CHANNEL_COUNT) {
|
if(channel >= DDS_CHANNEL_COUNT) {
|
||||||
log("Attempted to set invalid DDS channel");
|
log("Attempted to set invalid DDS channel");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DDS_WRITE(DDS_GPIO, channel);
|
#ifdef DDS_ONEHOT_SEL
|
||||||
|
channel_enc = 1 << channel;
|
||||||
|
#else
|
||||||
|
channel_enc = channel;
|
||||||
|
#endif
|
||||||
|
DDS_WRITE(DDS_GPIO, channel_enc << 1);
|
||||||
|
|
||||||
|
#ifdef DDS_AD9858
|
||||||
DDS_WRITE(DDS_FTW0, ftw & 0xff);
|
DDS_WRITE(DDS_FTW0, ftw & 0xff);
|
||||||
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
|
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
|
||||||
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
|
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
|
||||||
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
|
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
DDS_WRITE(DDS_FTWL, ftw & 0xffff);
|
||||||
|
DDS_WRITE(DDS_FTWH, (ftw >> 16) & 0xffff);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We need the RTIO fine timestamp clock to be phase-locked
|
/* We need the RTIO fine timestamp clock to be phase-locked
|
||||||
* to DDS SYSCLK, 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) {
|
if(phase_mode == PHASE_MODE_CONTINUOUS) {
|
||||||
/* Do not clear phase accumulator on FUD */
|
/* Do not clear phase accumulator on FUD */
|
||||||
DDS_WRITE(0x02, 0x00);
|
#ifdef DDS_AD9858
|
||||||
|
DDS_WRITE(DDS_CFR2, 0x00);
|
||||||
|
#endif
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
DDS_WRITE(DDS_CFR1L, 0x0008);
|
||||||
|
#endif
|
||||||
pow += continuous_phase_comp[channel];
|
pow += continuous_phase_comp[channel];
|
||||||
} else {
|
} else {
|
||||||
long long int fud_time;
|
long long int fud_time;
|
||||||
|
|
||||||
/* Clear phase accumulator on FUD */
|
/* Clear phase accumulator on FUD */
|
||||||
DDS_WRITE(0x02, 0x40);
|
#ifdef DDS_AD9858
|
||||||
|
DDS_WRITE(DDS_CFR2, 0x40);
|
||||||
|
#endif
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
DDS_WRITE(DDS_CFR1L, 0x2008);
|
||||||
|
#endif
|
||||||
fud_time = now + 2*DURATION_WRITE;
|
fud_time = now + 2*DURATION_WRITE;
|
||||||
pow -= (ref_time - fud_time)*DDS_RTIO_CLK_RATIO*ftw >> 18;
|
pow -= (ref_time - fud_time)*DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH);
|
||||||
if(phase_mode == PHASE_MODE_TRACKING)
|
if(phase_mode == PHASE_MODE_TRACKING)
|
||||||
pow += ref_time*DDS_RTIO_CLK_RATIO*ftw >> 18;
|
pow += ref_time*DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH);
|
||||||
continuous_phase_comp[channel] = pow;
|
continuous_phase_comp[channel] = pow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DDS_AD9858
|
||||||
DDS_WRITE(DDS_POW0, pow & 0xff);
|
DDS_WRITE(DDS_POW0, pow & 0xff);
|
||||||
DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f);
|
DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f);
|
||||||
|
#endif
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
DDS_WRITE(DDS_POW, pow);
|
||||||
|
#endif
|
||||||
DDS_WRITE(DDS_FUD, 0);
|
DDS_WRITE(DDS_FUD, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,17 @@
|
||||||
#define __DDS_H
|
#define __DDS_H
|
||||||
|
|
||||||
#include <hw/common.h>
|
#include <hw/common.h>
|
||||||
|
#include <generated/csr.h>
|
||||||
#include <generated/mem.h>
|
#include <generated/mem.h>
|
||||||
|
|
||||||
/* Maximum number of commands in a batch */
|
/* Maximum number of commands in a batch */
|
||||||
#define DDS_MAX_BATCH 16
|
#define DDS_MAX_BATCH 16
|
||||||
|
|
||||||
/* DDS core registers */
|
#ifdef DDS_AD9858
|
||||||
|
#define DDS_CFR0 0x00
|
||||||
|
#define DDS_CFR1 0x01
|
||||||
|
#define DDS_CFR2 0x02
|
||||||
|
#define DDS_CFR3 0x03
|
||||||
#define DDS_FTW0 0x0a
|
#define DDS_FTW0 0x0a
|
||||||
#define DDS_FTW1 0x0b
|
#define DDS_FTW1 0x0b
|
||||||
#define DDS_FTW2 0x0c
|
#define DDS_FTW2 0x0c
|
||||||
|
@ -16,6 +21,31 @@
|
||||||
#define DDS_POW1 0x0f
|
#define DDS_POW1 0x0f
|
||||||
#define DDS_FUD 0x40
|
#define DDS_FUD 0x40
|
||||||
#define DDS_GPIO 0x41
|
#define DDS_GPIO 0x41
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
#define DDS_CFR1L 0x01
|
||||||
|
#define DDS_CFR1H 0x03
|
||||||
|
#define DDS_CFR2L 0x05
|
||||||
|
#define DDS_CFR2H 0x07
|
||||||
|
#define DDS_CFR3L 0x09
|
||||||
|
#define DDS_CFR3H 0x0b
|
||||||
|
#define DDS_CFR4L 0x0d
|
||||||
|
#define DDS_CFR4H 0x0f
|
||||||
|
#define DDS_FTWL 0x2d
|
||||||
|
#define DDS_FTWH 0x2f
|
||||||
|
#define DDS_POW 0x31
|
||||||
|
#define DDS_FUD 0x80
|
||||||
|
#define DDS_GPIO 0x81
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DDS_AD9858
|
||||||
|
#define DDS_POW_WIDTH 14
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
#define DDS_POW_WIDTH 16
|
||||||
|
#endif
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
PHASE_MODE_CONTINUOUS = 0,
|
PHASE_MODE_CONTINUOUS = 0,
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <uart.h>
|
#include <uart.h>
|
||||||
#include <console.h>
|
#include <console.h>
|
||||||
#include <system.h>
|
#include <system.h>
|
||||||
#include <time.h>
|
|
||||||
#include <generated/csr.h>
|
#include <generated/csr.h>
|
||||||
#include <hw/flags.h>
|
#include <hw/flags.h>
|
||||||
|
|
||||||
|
@ -32,7 +31,6 @@
|
||||||
|
|
||||||
static void common_init(void)
|
static void common_init(void)
|
||||||
{
|
{
|
||||||
clock_init();
|
|
||||||
brg_start();
|
brg_start();
|
||||||
brg_ddsinitall();
|
brg_ddsinitall();
|
||||||
kloader_stop();
|
kloader_stop();
|
||||||
|
@ -211,34 +209,31 @@ static void regular_main(void)
|
||||||
|
|
||||||
static void blink_led(void)
|
static void blink_led(void)
|
||||||
{
|
{
|
||||||
int i, ev, p;
|
int i;
|
||||||
|
long long int t;
|
||||||
|
|
||||||
p = identifier_frequency_read()/10;
|
|
||||||
time_init();
|
|
||||||
for(i=0;i<3;i++) {
|
for(i=0;i<3;i++) {
|
||||||
leds_out_write(1);
|
leds_out_write(1);
|
||||||
while(!elapsed(&ev, p));
|
t = clock_get_ms();
|
||||||
|
while(clock_get_ms() < t + 250);
|
||||||
leds_out_write(0);
|
leds_out_write(0);
|
||||||
while(!elapsed(&ev, p));
|
t = clock_get_ms();
|
||||||
|
while(clock_get_ms() < t + 250);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_test_mode(void)
|
static int check_test_mode(void)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
long long int t;
|
||||||
|
|
||||||
timer0_en_write(0);
|
t = clock_get_ms();
|
||||||
timer0_reload_write(0);
|
while(clock_get_ms() < t + 1000) {
|
||||||
timer0_load_write(identifier_frequency_read() >> 2);
|
|
||||||
timer0_en_write(1);
|
|
||||||
timer0_update_value_write(1);
|
|
||||||
while(timer0_value_read()) {
|
|
||||||
if(readchar_nonblock()) {
|
if(readchar_nonblock()) {
|
||||||
c = readchar();
|
c = readchar();
|
||||||
if((c == 't')||(c == 'T'))
|
if((c == 't')||(c == 'T'))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
timer0_update_value_write(1);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -251,6 +246,7 @@ int main(void)
|
||||||
|
|
||||||
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
|
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
|
||||||
|
|
||||||
|
clock_init();
|
||||||
puts("Press 't' to enter test mode...");
|
puts("Press 't' to enter test mode...");
|
||||||
blink_led();
|
blink_led();
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "dds.h"
|
#include "dds.h"
|
||||||
#include "flash_storage.h"
|
#include "flash_storage.h"
|
||||||
#include "bridge_ctl.h"
|
#include "bridge_ctl.h"
|
||||||
|
#include "clock.h"
|
||||||
#include "test_mode.h"
|
#include "test_mode.h"
|
||||||
|
|
||||||
static void leds(char *value)
|
static void leds(char *value)
|
||||||
|
@ -114,6 +115,9 @@ static void ddssel(char *n)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DDS_ONEHOT_SEL
|
||||||
|
n2 = 1 << n2;
|
||||||
|
#endif
|
||||||
brg_ddssel(n2);
|
brg_ddssel(n2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +161,12 @@ static void ddsr(char *addr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DDS_AD9858
|
||||||
printf("0x%02x\n", brg_ddsread(addr2));
|
printf("0x%02x\n", brg_ddsread(addr2));
|
||||||
|
#endif
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
printf("0x%04x\n", brg_ddsread(addr2));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ddsfud(void)
|
static void ddsfud(void)
|
||||||
|
@ -186,11 +195,22 @@ static void ddsftw(char *n, char *ftw)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DDS_ONEHOT_SEL
|
||||||
|
n2 = 1 << n2;
|
||||||
|
#endif
|
||||||
brg_ddssel(n2);
|
brg_ddssel(n2);
|
||||||
|
|
||||||
|
#ifdef DDS_AD9858
|
||||||
brg_ddswrite(DDS_FTW0, ftw2 & 0xff);
|
brg_ddswrite(DDS_FTW0, ftw2 & 0xff);
|
||||||
brg_ddswrite(DDS_FTW1, (ftw2 >> 8) & 0xff);
|
brg_ddswrite(DDS_FTW1, (ftw2 >> 8) & 0xff);
|
||||||
brg_ddswrite(DDS_FTW2, (ftw2 >> 16) & 0xff);
|
brg_ddswrite(DDS_FTW2, (ftw2 >> 16) & 0xff);
|
||||||
brg_ddswrite(DDS_FTW3, (ftw2 >> 24) & 0xff);
|
brg_ddswrite(DDS_FTW3, (ftw2 >> 24) & 0xff);
|
||||||
|
#endif
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
brg_ddswrite(DDS_FTWL, ftw2 & 0xffff);
|
||||||
|
brg_ddswrite(DDS_FTWH, (ftw2 >> 16) & 0xffff);
|
||||||
|
#endif
|
||||||
|
|
||||||
brg_ddsfud();
|
brg_ddsfud();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,15 +219,34 @@ static void ddsreset(void)
|
||||||
brg_ddsreset();
|
brg_ddsreset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DDS_AD9858
|
||||||
static void ddsinit(void)
|
static void ddsinit(void)
|
||||||
{
|
{
|
||||||
brg_ddsreset();
|
brg_ddsreset();
|
||||||
brg_ddswrite(0x00, 0x78);
|
brg_ddswrite(DDS_CFR0, 0x78);
|
||||||
brg_ddswrite(0x01, 0x00);
|
brg_ddswrite(DDS_CFR1, 0x00);
|
||||||
brg_ddswrite(0x02, 0x00);
|
brg_ddswrite(DDS_CFR2, 0x00);
|
||||||
brg_ddswrite(0x03, 0x00);
|
brg_ddswrite(DDS_CFR3, 0x00);
|
||||||
brg_ddsfud();
|
brg_ddsfud();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
static void ddsinit(void)
|
||||||
|
{
|
||||||
|
long long int t;
|
||||||
|
|
||||||
|
brg_ddsreset();
|
||||||
|
brg_ddswrite(DDS_CFR1L, 0x0008);
|
||||||
|
brg_ddswrite(DDS_CFR1H, 0x0000);
|
||||||
|
brg_ddswrite(DDS_CFR4H, 0x0105);
|
||||||
|
brg_ddswrite(DDS_FUD, 0);
|
||||||
|
t = clock_get_ms();
|
||||||
|
while(clock_get_ms() < t + 2);
|
||||||
|
brg_ddswrite(DDS_CFR4H, 0x0005);
|
||||||
|
brg_ddsfud();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void ddstest_one(unsigned int i)
|
static void ddstest_one(unsigned int i)
|
||||||
{
|
{
|
||||||
|
@ -223,15 +262,27 @@ static void ddstest_one(unsigned int i)
|
||||||
|
|
||||||
for(j=0; j<12; j++) {
|
for(j=0; j<12; j++) {
|
||||||
f = v[j];
|
f = v[j];
|
||||||
brg_ddswrite(0x0a, f & 0xff);
|
#ifdef DDS_AD9858
|
||||||
brg_ddswrite(0x0b, (f >> 8) & 0xff);
|
brg_ddswrite(DDS_FTW0, f & 0xff);
|
||||||
brg_ddswrite(0x0c, (f >> 16) & 0xff);
|
brg_ddswrite(DDS_FTW1, (f >> 8) & 0xff);
|
||||||
brg_ddswrite(0x0d, (f >> 24) & 0xff);
|
brg_ddswrite(DDS_FTW2, (f >> 16) & 0xff);
|
||||||
|
brg_ddswrite(DDS_FTW3, (f >> 24) & 0xff);
|
||||||
|
#endif
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
brg_ddswrite(DDS_FTWL, f & 0xffff);
|
||||||
|
brg_ddswrite(DDS_FTWH, (f >> 16) & 0xffff);
|
||||||
|
#endif
|
||||||
brg_ddsfud();
|
brg_ddsfud();
|
||||||
g = brg_ddsread(0x0a);
|
#ifdef DDS_AD9858
|
||||||
g |= brg_ddsread(0x0b) << 8;
|
g = brg_ddsread(DDS_FTW0);
|
||||||
g |= brg_ddsread(0x0c) << 16;
|
g |= brg_ddsread(DDS_FTW1) << 8;
|
||||||
g |= brg_ddsread(0x0d) << 24;
|
g |= brg_ddsread(DDS_FTW2) << 16;
|
||||||
|
g |= brg_ddsread(DDS_FTW3) << 24;
|
||||||
|
#endif
|
||||||
|
#ifdef DDS_AD9914
|
||||||
|
g = brg_ddsread(DDS_FTWL);
|
||||||
|
g |= brg_ddsread(DDS_FTWH) << 16;
|
||||||
|
#endif
|
||||||
if(g != f)
|
if(g != f)
|
||||||
printf("readback fail on DDS %d, 0x%08x != 0x%08x\n", i, g, f);
|
printf("readback fail on DDS %d, 0x%08x != 0x%08x\n", i, g, f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||||
|
|
||||||
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
self.add_constant("RTIO_DDS_CHANNEL", len(rtio_channels))
|
||||||
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
self.add_constant("DDS_CHANNEL_COUNT", 8)
|
||||||
|
self.add_constant("DDS_AD9858")
|
||||||
phy = dds.AD9858(platform.request("dds"), 8)
|
phy = dds.AD9858(platform.request("dds"), 8)
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy,
|
rtio_channels.append(rtio.Channel.from_phy(phy,
|
||||||
|
|
Loading…
Reference in New Issue