diff --git a/artiq/coredevice/dds.py b/artiq/coredevice/dds.py index fc9952980..9332ac34c 100644 --- a/artiq/coredevice/dds.py +++ b/artiq/coredevice/dds.py @@ -14,6 +14,11 @@ PHASE_MODE_TRACKING = 2 def dds_init(time_mu: TInt64, bus_channel: TInt32, channel: TInt32) -> TNone: raise NotImplementedError("syscall not simulated") +@syscall(flags={"nowrite"}) +def dds_init_sync(time_mu: TInt64, bus_channel: TInt32, + channel: TInt32, sync_delay: TInt32) -> TNone: + raise NotImplementedError("syscall not simulated") + @syscall(flags={"nowrite"}) def dds_set(time_mu: TInt64, bus_channel: TInt32, channel: TInt32, ftw: TInt32, pow: TInt32, phase_mode: TInt32, amplitude: TInt32) -> TNone: @@ -151,6 +156,24 @@ class _DDSGeneric: timing margin.""" dds_init(now_mu(), self.bus_channel, self.channel) + @kernel + def init_sync(self, sync_delay=0): + """Resets and initializes the DDS channel as well as configures + the AD9914 DDS for synchronisation. The synchronisation procedure + follows the steps outlined in the AN-1254 application note. + + This needs to be done for each DDS channel before it can be used, and + it is recommended to use the startup kernel for this. + + This function cannot be used in a batch; the correct way of + initializing multiple DDS channels is to call this function + sequentially with a delay between the calls. 10ms provides a good + timing margin. + + :param sync_delay: integer from 0 to 0x3f that sets value of + SYNC_OUT (bits 3-5) and SYNC_IN (bits 0-2) delay ADJ bits.""" + dds_init_sync(now_mu(), self.bus_channel, self.channel, sync_delay) + @kernel def set_phase_mode(self, phase_mode): """Sets the phase mode of the DDS channel. Supported phase modes are: diff --git a/artiq/runtime/dds.c b/artiq/runtime/dds.c index 44661658c..4f882aacb 100644 --- a/artiq/runtime/dds.c +++ b/artiq/runtime/dds.c @@ -22,6 +22,7 @@ #define DURATION_DAC_CAL (147000 << CONFIG_RTIO_FINE_TS_WIDTH) /* not counting final FUD */ #define DURATION_INIT (8*DURATION_WRITE + DURATION_DAC_CAL) +#define DURATION_INIT_SYNC (16*DURATION_WRITE + 2*DURATION_DAC_CAL) #define DURATION_PROGRAM (6*DURATION_WRITE) /* not counting FUD */ #else @@ -83,6 +84,41 @@ void dds_init(long long int timestamp, int bus_channel, int channel) #endif } +void dds_init_sync(long long int timestamp, int bus_channel, int channel, int sync_delay) +{ + long long int now; + + now = timestamp - DURATION_INIT_SYNC; + +#ifdef CONFIG_DDS_ONEHOT_SEL + channel = 1 << channel; +#endif + channel <<= 1; + DDS_WRITE(DDS_GPIO, channel); + +#ifdef CONFIG_DDS_AD9914 + DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ + DDS_WRITE(DDS_FUD, 0); + now += DURATION_DAC_CAL; + DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ + DDS_WRITE(DDS_FUD, 0); + DDS_WRITE(DDS_CFR2L, 0x8b00); /* Enable matched latency and sync_out*/ + DDS_WRITE(DDS_FUD, 0); + /* Set cal with sync and set sync_out and sync_in delay */ + DDS_WRITE(DDS_USR0, 0x0840 | (sync_delay & 0x3f)); + DDS_WRITE(DDS_FUD, 0); + DDS_WRITE(DDS_CFR4H, 0x0105); /* Enable DAC calibration */ + DDS_WRITE(DDS_FUD, 0); + now += DURATION_DAC_CAL; + DDS_WRITE(DDS_CFR4H, 0x0005); /* Disable DAC calibration */ + DDS_WRITE(DDS_FUD, 0); + DDS_WRITE(DDS_CFR1H, 0x0000); /* Enable cosine output */ + DDS_WRITE(DDS_CFR2H, 0x0080); /* Enable profile mode */ + DDS_WRITE(DDS_ASF, 0x0fff); /* Set amplitude to maximum */ + DDS_WRITE(DDS_FUD, 0); +#endif +} + /* Compensation to keep phase continuity when switching from absolute or tracking * to continuous phase mode. */ static unsigned int continuous_phase_comp[CONFIG_RTIO_DDS_COUNT][CONFIG_DDS_CHANNELS_PER_BUS]; diff --git a/artiq/runtime/dds.h b/artiq/runtime/dds.h index 189d9ada7..8cca5cb74 100644 --- a/artiq/runtime/dds.h +++ b/artiq/runtime/dds.h @@ -38,6 +38,7 @@ #define DDS_FTWH 0x2f #define DDS_POW 0x31 #define DDS_ASF 0x33 +#define DDS_USR0 0x6d #define DDS_FUD 0x80 #define DDS_GPIO 0x81 #endif @@ -57,6 +58,8 @@ enum { }; void dds_init(long long int timestamp, int bus_channel, int channel); +void dds_init_sync(long long int timestamp, int bus_channel, int channel, + int sync_delay); void dds_batch_enter(long long int timestamp); void dds_batch_exit(void); void dds_set(long long int timestamp, int bus_channel, int channel, diff --git a/artiq/runtime/ksupport.c b/artiq/runtime/ksupport.c index b881b4f04..d11511bfb 100644 --- a/artiq/runtime/ksupport.c +++ b/artiq/runtime/ksupport.c @@ -121,6 +121,7 @@ static const struct symbol runtime_exports[] = { #if ((defined CONFIG_RTIO_DDS_COUNT) && (CONFIG_RTIO_DDS_COUNT > 0)) {"dds_init", &dds_init}, + {"dds_init_sync", &dds_init_sync}, {"dds_batch_enter", &dds_batch_enter}, {"dds_batch_exit", &dds_batch_exit}, {"dds_set", &dds_set},