forked from M-Labs/artiq
dds: phase control (mostly untested)
This commit is contained in:
parent
e01050b19a
commit
1780759327
@ -3,6 +3,12 @@ from artiq.language.units import *
|
||||
from artiq.coredevice import rtio
|
||||
|
||||
|
||||
PHASE_MODE_DEFAULT = -1
|
||||
PHASE_MODE_CONTINUOUS = 0
|
||||
PHASE_MODE_ABSOLUTE = 1
|
||||
PHASE_MODE_TRACKING = 2
|
||||
|
||||
|
||||
class DDS(AutoContext):
|
||||
"""Core device Direct Digital Synthesis (DDS) driver.
|
||||
|
||||
@ -21,6 +27,7 @@ class DDS(AutoContext):
|
||||
|
||||
def build(self):
|
||||
self.previous_frequency = 0*MHz
|
||||
self.set_phase_mode(PHASE_MODE_CONTINUOUS)
|
||||
self.sw = rtio.RTIOOut(self, channel=self.rtio_switch)
|
||||
|
||||
@portable
|
||||
@ -40,33 +47,71 @@ class DDS(AutoContext):
|
||||
return ftw*self.dds_sysclk/2**32
|
||||
|
||||
@kernel
|
||||
def on(self, frequency):
|
||||
"""Sets the DDS channel to the specified frequency and turns it on.
|
||||
def set_phase_mode(self, phase_mode):
|
||||
"""Sets the phase mode of the DDS channel. Supported phase modes are:
|
||||
|
||||
If the DDS channel was already on, a real-time frequency update is
|
||||
performed.
|
||||
* ``PHASE_MODE_CONTINUOUS``: the phase accumulator is unchanged when
|
||||
switching frequencies. The DDS phase is the sum of the phase
|
||||
accumulator and the phase offset. The only discrete jumps in the
|
||||
DDS output phase come from changes to the phase offset.
|
||||
|
||||
* ``PHASE_MODE_ABSOLUTE``: the phase accumulator is reset when
|
||||
switching frequencies. Thus, the phase of the DDS at the time of
|
||||
the frequency change is equal to the phase offset.
|
||||
|
||||
* ``PHASE_MODE_TRACKING``: when switching frequencies, the phase
|
||||
accumulator is set to the value it would have if the DDS had been
|
||||
running at the specified frequency since the start of the
|
||||
experiment.
|
||||
|
||||
"""
|
||||
self.phase_mode = phase_mode
|
||||
syscall("dds_phase_clear_en", self.reg_channel,
|
||||
self.phase_mode != PHASE_MODE_CONTINUOUS)
|
||||
|
||||
@kernel
|
||||
def on(self, frequency, phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
|
||||
"""Sets the DDS channel to the specified frequency and turns it on.
|
||||
|
||||
If the DDS channel was already on, a real-time frequency and phase
|
||||
update is performed.
|
||||
|
||||
:param frequency: frequency to generate.
|
||||
:param phase_mode: if specified, overrides the default phase mode set
|
||||
by ``set_phase_mode`` for this call.
|
||||
:param phase_offset: adds an offset, in turns, to the phase.
|
||||
|
||||
"""
|
||||
if phase_mode != PHASE_MODE_DEFAULT:
|
||||
old_phase_mode = self.phase_mode
|
||||
self.set_phase_mode(phase_mode)
|
||||
|
||||
if self.previous_frequency != frequency:
|
||||
merge = self.sw.previous_timestamp == time_to_cycles(now())
|
||||
if not merge:
|
||||
self.sw.sync()
|
||||
if merge or bool(self.sw.previous_value):
|
||||
# Channel is already on.
|
||||
# Precise timing of frequency change is required.
|
||||
fud_time = time_to_cycles(now())
|
||||
# Channel is already on:
|
||||
# Precise timing of frequency change is required.
|
||||
# Channel is off:
|
||||
# Use soft timing on FUD to prevent conflicts when reprogramming
|
||||
# several channels that need to be turned on at the same time.
|
||||
rt_fud = merge or bool(self.sw.previous_value)
|
||||
ftw = self.frequency_to_ftw(frequency)
|
||||
if self.phase_mode != PHASE_MODE_CONTINUOUS:
|
||||
phase_per_microcycle = ftw*int64(
|
||||
self.dds_sysclk.amount*self.core.runtime_env.ref_period)
|
||||
else:
|
||||
# Channel is off.
|
||||
# Use soft timing on FUD to prevent conflicts when
|
||||
# reprogramming several channels that need to be turned on at
|
||||
# the same time.
|
||||
fud_time = -1
|
||||
syscall("dds_program", self.reg_channel,
|
||||
self.frequency_to_ftw(frequency),
|
||||
fud_time)
|
||||
phase_per_microcycle = int64(0)
|
||||
syscall("dds_program", time_to_cycles(now()), self.reg_channel,
|
||||
ftw, int(phase_offset*2**14),
|
||||
phase_per_microcycle,
|
||||
rt_fud, self.phase_mode == PHASE_MODE_TRACKING)
|
||||
self.previous_frequency = frequency
|
||||
self.sw.on()
|
||||
|
||||
if phase_mode != PHASE_MODE_DEFAULT:
|
||||
self.set_phase_mode(old_phase_mode)
|
||||
|
||||
@kernel
|
||||
def off(self):
|
||||
"""Turns the DDS channel off.
|
||||
@ -75,13 +120,16 @@ class DDS(AutoContext):
|
||||
self.sw.off()
|
||||
|
||||
@kernel
|
||||
def pulse(self, frequency, duration):
|
||||
def pulse(self, frequency, duration,
|
||||
phase_mode=PHASE_MODE_DEFAULT, phase_offset=0):
|
||||
"""Pulses the DDS channel for the specified duration at the specified
|
||||
frequency.
|
||||
|
||||
See ``on`` for a description of the parameters.
|
||||
|
||||
Equivalent to a ``on``, ``delay``, ``off`` sequence.
|
||||
|
||||
"""
|
||||
self.on(frequency)
|
||||
self.on(frequency, phase_mode, phase_offset)
|
||||
delay(duration)
|
||||
self.off()
|
||||
|
@ -19,17 +19,20 @@ _syscalls = {
|
||||
"rtio_sync": "i:n",
|
||||
"rtio_get": "i:I",
|
||||
"rtio_pileup_count": "i:i",
|
||||
"dds_program": "iiI:n",
|
||||
"dds_phase_clear_en": "ib:n",
|
||||
"dds_program": "IiiiIbb:n",
|
||||
}
|
||||
|
||||
_chr_to_type = {
|
||||
"n": lambda: lc.Type.void(),
|
||||
"b": lambda: lc.Type.int(1),
|
||||
"i": lambda: lc.Type.int(32),
|
||||
"I": lambda: lc.Type.int(64)
|
||||
}
|
||||
|
||||
_chr_to_value = {
|
||||
"n": lambda: base_types.VNone(),
|
||||
"b": lambda: base_types.VBool(),
|
||||
"i": lambda: base_types.VInt(),
|
||||
"I": lambda: base_types.VInt(64)
|
||||
}
|
||||
|
@ -9,6 +9,8 @@
|
||||
#define DDS_FTW1 0x0b
|
||||
#define DDS_FTW2 0x0c
|
||||
#define DDS_FTW3 0x0d
|
||||
#define DDS_POW0 0x0e
|
||||
#define DDS_POW1 0x0f
|
||||
#define DDS_GPIO 0x41
|
||||
|
||||
#define DDS_READ(addr) \
|
||||
@ -25,22 +27,55 @@ void dds_init(void)
|
||||
DDS_WRITE(DDS_GPIO, i);
|
||||
DDS_WRITE(DDS_GPIO, i | (1 << 7));
|
||||
DDS_WRITE(DDS_GPIO, i);
|
||||
DDS_WRITE(0x00, 0x78);
|
||||
DDS_WRITE(0x01, 0x00);
|
||||
DDS_WRITE(0x02, 0x00);
|
||||
DDS_WRITE(0x03, 0x00);
|
||||
rtio_fud(-1);
|
||||
rtio_fud_sync();
|
||||
dds_phase_clear_en(i, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void dds_program(int channel, int ftw, long long int fud_time)
|
||||
void dds_phase_clear_en(int channel, int phase_clear_en)
|
||||
{
|
||||
DDS_WRITE(0x00, 0x78);
|
||||
DDS_WRITE(0x01, 0x00);
|
||||
DDS_WRITE(0x02, phase_clear_en ? 0x40 : 0x00);
|
||||
DDS_WRITE(0x03, 0x00);
|
||||
}
|
||||
|
||||
/*
|
||||
* DDS phase modes:
|
||||
* - continuous: Set phase_per_microcycle=0 to disable POW alteration.
|
||||
* phase_tracking is ignored, set to 0.
|
||||
* Disable phase accumulator clearing prior to programming.
|
||||
* - absolute: Set phase_per_microcycle to its nominal value
|
||||
* and phase_tracking=0.
|
||||
* Enable phase accumulator clearing prior to programming.
|
||||
* - tracking: Set phase_per_microcycle to its nominal value
|
||||
* and phase_tracking=1.
|
||||
* Enable phase accumulator clearing prior to programming.
|
||||
*/
|
||||
void dds_program(long long int timestamp, int channel,
|
||||
int ftw, int pow, long long int phase_per_microcycle,
|
||||
int rt_fud, int phase_tracking)
|
||||
{
|
||||
long long int fud_time;
|
||||
long long int phase_time_offset;
|
||||
|
||||
rtio_fud_sync();
|
||||
DDS_WRITE(DDS_GPIO, channel);
|
||||
|
||||
DDS_WRITE(DDS_FTW0, ftw & 0xff);
|
||||
DDS_WRITE(DDS_FTW1, (ftw >> 8) & 0xff);
|
||||
DDS_WRITE(DDS_FTW2, (ftw >> 16) & 0xff);
|
||||
DDS_WRITE(DDS_FTW3, (ftw >> 24) & 0xff);
|
||||
|
||||
phase_time_offset = phase_tracking ? timestamp : 0;
|
||||
if(rt_fud)
|
||||
fud_time = timestamp;
|
||||
else {
|
||||
fud_time = rtio_get_counter() + 8000;
|
||||
phase_time_offset -= timestamp - fud_time;
|
||||
}
|
||||
pow += phase_time_offset*phase_per_microcycle;
|
||||
DDS_WRITE(DDS_POW0, pow & 0xff);
|
||||
DDS_WRITE(DDS_POW1, (pow >> 8) & 0x3f);
|
||||
|
||||
rtio_fud(fud_time);
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
#define __DDS_H
|
||||
|
||||
void dds_init(void);
|
||||
void dds_program(int channel, int ftw, long long int fud_time);
|
||||
void dds_phase_clear_en(int channel, int phase_clear_en);
|
||||
void dds_program(long long int timestamp, int channel,
|
||||
int ftw, int pow, long long int phase_per_microcycle,
|
||||
int rt_fud, int phase_tracking);
|
||||
|
||||
#endif /* __DDS_H */
|
||||
|
@ -110,7 +110,6 @@ int main(void)
|
||||
uart_init();
|
||||
|
||||
puts("ARTIQ runtime built "__DATE__" "__TIME__"\n");
|
||||
rtio_init();
|
||||
dds_init();
|
||||
blink_led();
|
||||
comm_serve(load_object, run_kernel);
|
||||
|
@ -10,6 +10,7 @@ void rtio_init(void)
|
||||
previous_fud_end_time = 0;
|
||||
rtio_reset_counter_write(1);
|
||||
rtio_reset_logic_write(1);
|
||||
rtio_reset_counter_write(0);
|
||||
rtio_reset_logic_write(0);
|
||||
}
|
||||
|
||||
@ -21,7 +22,6 @@ void rtio_oe(int channel, int oe)
|
||||
|
||||
void rtio_set(long long int timestamp, int channel, int value)
|
||||
{
|
||||
rtio_reset_counter_write(0);
|
||||
rtio_chan_sel_write(channel);
|
||||
rtio_o_timestamp_write(timestamp);
|
||||
rtio_o_value_write(value);
|
||||
@ -53,6 +53,12 @@ void rtio_sync(int channel)
|
||||
while(rtio_o_level_read() != 0);
|
||||
}
|
||||
|
||||
long long int rtio_get_counter(void)
|
||||
{
|
||||
rtio_counter_update_write(1);
|
||||
return rtio_counter_read();
|
||||
}
|
||||
|
||||
long long int rtio_get(int channel)
|
||||
{
|
||||
long long int r;
|
||||
@ -94,12 +100,7 @@ void rtio_fud(long long int fud_time)
|
||||
{
|
||||
long long int fud_end_time;
|
||||
|
||||
rtio_reset_counter_write(0);
|
||||
rtio_chan_sel_write(RTIO_FUD_CHANNEL);
|
||||
if(fud_time < 0) {
|
||||
rtio_counter_update_write(1);
|
||||
fud_time = rtio_counter_read() + 4000;
|
||||
}
|
||||
fud_end_time = fud_time + 3*8;
|
||||
if(fud_time < previous_fud_end_time)
|
||||
exception_raise(EID_RTIO_SEQUENCE_ERROR);
|
||||
|
@ -6,6 +6,7 @@ void rtio_oe(int channel, int oe);
|
||||
void rtio_set(long long int timestamp, int channel, int value);
|
||||
void rtio_replace(long long int timestamp, int channel, int value);
|
||||
void rtio_sync(int channel);
|
||||
long long int rtio_get_counter(void);
|
||||
long long int rtio_get(int channel);
|
||||
int rtio_pileup_count(int channel);
|
||||
|
||||
|
@ -17,6 +17,7 @@ static const struct symbol syscalls[] = {
|
||||
{"rtio_sync", rtio_sync},
|
||||
{"rtio_get", rtio_get},
|
||||
{"rtio_pileup_count", rtio_pileup_count},
|
||||
{"dds_phase_clear_en", dds_phase_clear_en},
|
||||
{"dds_program", dds_program},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user