From b3831d33874522d1882d6208c5fbfd3d5698fb71 Mon Sep 17 00:00:00 2001 From: Raghavendra Srinivas Date: Sat, 5 Sep 2015 13:14:01 -0600 Subject: [PATCH] dds: support amplitude tuning on AD9914 Closes #108 --- artiq/coredevice/dds.py | 25 ++++++++++++++++++++----- artiq/coredevice/runtime.py | 2 +- soc/runtime/dds.c | 23 ++++++++++++++++------- soc/runtime/dds.h | 2 +- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index e9e830331..4eb0872fc 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -89,6 +89,17 @@ class _DDSGeneric: word.""" return pow/2**self.pow_width + @portable + def amplitude_to_asf(self, amplitude): + """Returns amplitude scale factor corresponding to given amplitude.""" + return round(amplitude*0x0fff) + + @portable + def asf_to_amplitude(self, asf): + """Returns the amplitude corresponding to the given amplitude scale + factor.""" + return round(amplitude*0x0fff) + @kernel def init(self): """Resets and initializes the DDS channel. @@ -117,12 +128,14 @@ class _DDSGeneric: self.phase_mode = phase_mode @kernel - def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT): + def set_mu(self, frequency, phase=0, phase_mode=_PHASE_MODE_DEFAULT, + amplitude=0x0fff): """Sets the DDS channel to the specified frequency and phase. 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. + chip and can be retrieved via the ``pow_width`` attribute. The amplitude + width is 12. :param frequency: frequency to generate. :param phase: adds an offset, in turns, to the phase. @@ -132,13 +145,15 @@ class _DDSGeneric: if phase_mode == _PHASE_MODE_DEFAULT: phase_mode = self.phase_mode syscall("dds_set", now_mu(), self.channel, frequency, - phase, phase_mode) + phase, phase_mode, amplitude) @kernel - def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT): + def set(self, frequency, phase=0.0, phase_mode=_PHASE_MODE_DEFAULT, + amplitude=1.0): """Like ``set_mu``, but uses Hz and turns.""" self.set_mu(self.frequency_to_ftw(frequency), - self.turns_to_pow(phase), phase_mode) + self.turns_to_pow(phase), phase_mode, + self.amplitude_to_asf(amplitude)) class AD9858(_DDSGeneric): diff --git a/artiq/coredevice/runtime.py b/artiq/coredevice/runtime.py index ae818b1a6..5fcaf56d1 100644 --- a/artiq/coredevice/runtime.py +++ b/artiq/coredevice/runtime.py @@ -25,7 +25,7 @@ _syscalls = { "dds_init": "Ii:n", "dds_batch_enter": "I:n", "dds_batch_exit": "n:n", - "dds_set": "Iiiii:n", + "dds_set": "Iiiiii:n", } diff --git a/soc/runtime/dds.c b/soc/runtime/dds.c index ad62988d5..92d83915d 100644 --- a/soc/runtime/dds.c +++ b/soc/runtime/dds.c @@ -19,7 +19,7 @@ #define DURATION_DAC_CAL (147000 << RTIO_FINE_TS_WIDTH) /* not counting final FUD */ #define DURATION_INIT (10*DURATION_WRITE + DURATION_DAC_CAL) -#define DURATION_PROGRAM (5*DURATION_WRITE) /* not counting FUD */ +#define DURATION_PROGRAM (6*DURATION_WRITE) /* not counting FUD */ #else #error Unknown DDS configuration @@ -94,7 +94,7 @@ void dds_init(long long int timestamp, int channel) 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, - unsigned int ftw, unsigned int pow, int phase_mode) + unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude) { unsigned int channel_enc; @@ -130,7 +130,8 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int DDS_WRITE(DDS_CFR2, 0x00); #endif #ifdef DDS_AD9914 - DDS_WRITE(DDS_CFR1L, 0x0008); + /* Disable autoclear phase accumulator and enables OSK. */ + DDS_WRITE(DDS_CFR1L, 0x0108); #endif pow += continuous_phase_comp[channel]; } else { @@ -141,7 +142,8 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int DDS_WRITE(DDS_CFR2, 0x40); #endif #ifdef DDS_AD9914 - DDS_WRITE(DDS_CFR1L, 0x2008); + /* Enable autoclear phase accumulator and enables OSK. */ + DDS_WRITE(DDS_CFR1L, 0x2108); #endif fud_time = now + 2*DURATION_WRITE; pow -= (ref_time - fud_time)*DDS_RTIO_CLK_RATIO*ftw >> (32-DDS_POW_WIDTH); @@ -156,6 +158,9 @@ static void dds_set_one(long long int now, long long int ref_time, unsigned int #endif #ifdef DDS_AD9914 DDS_WRITE(DDS_POW, pow); +#endif +#ifdef DDS_AD9914 + DDS_WRITE(DDS_ASF, amplitude); #endif DDS_WRITE(DDS_FUD, 0); } @@ -165,6 +170,7 @@ struct dds_set_params { unsigned int ftw; unsigned int pow; int phase_mode; + unsigned int amplitude; }; static int batch_mode; @@ -193,14 +199,15 @@ void dds_batch_exit(void) now = batch_ref_time - batch_count*(DURATION_PROGRAM + DURATION_WRITE); for(i=0;i= DDS_MAX_BATCH) @@ -210,9 +217,11 @@ void dds_set(long long int timestamp, int channel, batch[batch_count].ftw = ftw; batch[batch_count].pow = pow; batch[batch_count].phase_mode = phase_mode; + batch[batch_count].amplitude = amplitude; batch_count++; } else { rtio_chan_sel_write(RTIO_DDS_CHANNEL); - dds_set_one(timestamp - DURATION_PROGRAM, timestamp, channel, ftw, pow, phase_mode); + dds_set_one(timestamp - DURATION_PROGRAM, timestamp, channel, ftw, pow, phase_mode, + amplitude); } } diff --git a/soc/runtime/dds.h b/soc/runtime/dds.h index 03c2bf095..2e3a4d07e 100644 --- a/soc/runtime/dds.h +++ b/soc/runtime/dds.h @@ -59,6 +59,6 @@ void dds_init(long long int timestamp, int channel); void dds_batch_enter(long long int timestamp); void dds_batch_exit(void); void dds_set(long long int timestamp, int channel, - unsigned int ftw, unsigned int pow, int phase_mode); + unsigned int ftw, unsigned int pow, int phase_mode, unsigned int amplitude); #endif /* __DDS_H */