forked from M-Labs/artiq
complete support for TTL clock generator
This commit is contained in:
parent
a615a3830a
commit
753d61b38f
|
@ -21,6 +21,7 @@ _syscalls = {
|
||||||
"ttl_set_oe": "Iib:n",
|
"ttl_set_oe": "Iib:n",
|
||||||
"ttl_set_sensitivity": "Iii:n",
|
"ttl_set_sensitivity": "Iii:n",
|
||||||
"ttl_get": "iI:I",
|
"ttl_get": "iI:I",
|
||||||
|
"ttl_clock_set": "Iii:n",
|
||||||
"dds_init": "Ii:n",
|
"dds_init": "Ii:n",
|
||||||
"dds_batch_enter": "I:n",
|
"dds_batch_enter": "I:n",
|
||||||
"dds_batch_exit": "n:n",
|
"dds_batch_exit": "n:n",
|
||||||
|
|
|
@ -26,7 +26,8 @@ class TTLOut(AutoDB):
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def sync(self):
|
def sync(self):
|
||||||
"""Busy-waits until all programmed level switches have been effected."""
|
"""Busy-wait until all programmed level switches have been
|
||||||
|
effected."""
|
||||||
while syscall("rtio_get_counter") < self.o_previous_timestamp:
|
while syscall("rtio_get_counter") < self.o_previous_timestamp:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -37,12 +38,12 @@ class TTLOut(AutoDB):
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def off(self):
|
def off(self):
|
||||||
"""Sets the output to a logic low state."""
|
"""Set the output to a logic low state."""
|
||||||
self.set_o(False)
|
self.set_o(False)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse_mu(self, duration):
|
def pulse_mu(self, duration):
|
||||||
"""Pulses the output high for the specified duration
|
"""Pulse the output high for the specified duration
|
||||||
(in machine units)."""
|
(in machine units)."""
|
||||||
self.on()
|
self.on()
|
||||||
delay_mu(duration)
|
delay_mu(duration)
|
||||||
|
@ -50,7 +51,7 @@ class TTLOut(AutoDB):
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def pulse(self, duration):
|
def pulse(self, duration):
|
||||||
"""Pulses the output high for the specified duration
|
"""Pulse the output high for the specified duration
|
||||||
(in seconds)."""
|
(in seconds)."""
|
||||||
self.on()
|
self.on()
|
||||||
delay(duration)
|
delay(duration)
|
||||||
|
@ -103,18 +104,19 @@ class TTLInOut(AutoDB):
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def sync(self):
|
def sync(self):
|
||||||
"""Busy-waits until all programmed level switches have been effected."""
|
"""Busy-wait until all programmed level switches have been
|
||||||
|
effected."""
|
||||||
while syscall("rtio_get_counter") < self.o_previous_timestamp:
|
while syscall("rtio_get_counter") < self.o_previous_timestamp:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def on(self):
|
def on(self):
|
||||||
"""Sets the output to a logic high state."""
|
"""Set the output to a logic high state."""
|
||||||
self.set_o(True)
|
self.set_o(True)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
def off(self):
|
def off(self):
|
||||||
"""Sets the output to a logic low state."""
|
"""Set the output to a logic low state."""
|
||||||
self.set_o(False)
|
self.set_o(False)
|
||||||
|
|
||||||
@kernel
|
@kernel
|
||||||
|
@ -204,3 +206,69 @@ class TTLInOut(AutoDB):
|
||||||
If the gate is permanently closed, returns a negative value.
|
If the gate is permanently closed, returns a negative value.
|
||||||
"""
|
"""
|
||||||
return syscall("ttl_get", self.channel, self.i_previous_timestamp)
|
return syscall("ttl_get", self.channel, self.i_previous_timestamp)
|
||||||
|
|
||||||
|
|
||||||
|
class TTLClockGen(AutoDB):
|
||||||
|
"""RTIO TTL clock generator driver.
|
||||||
|
|
||||||
|
This should be used with TTL channels that have a clock generator
|
||||||
|
built into the gateware (not compatible with regular TTL channels).
|
||||||
|
|
||||||
|
:param core: core device
|
||||||
|
:param channel: channel number
|
||||||
|
"""
|
||||||
|
class DBKeys:
|
||||||
|
core = Device()
|
||||||
|
channel = Argument()
|
||||||
|
|
||||||
|
def build(self):
|
||||||
|
# in RTIO cycles
|
||||||
|
self.previous_timestamp = int64(0)
|
||||||
|
|
||||||
|
@portable
|
||||||
|
def frequency_to_ftw(self, frequency):
|
||||||
|
"""Returns the frequency tuning word corresponding to the given
|
||||||
|
frequency.
|
||||||
|
"""
|
||||||
|
return round(2**24*frequency*self.core.ref_period)
|
||||||
|
|
||||||
|
@portable
|
||||||
|
def ftw_to_frequency(self, ftw):
|
||||||
|
"""Returns the frequency corresponding to the given frequency tuning
|
||||||
|
word.
|
||||||
|
"""
|
||||||
|
return ftw/self.core.ref_period/2**24
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set_mu(self, frequency):
|
||||||
|
"""Set the frequency of the clock, in machine units.
|
||||||
|
|
||||||
|
This also sets the phase, as the time of the first generated rising
|
||||||
|
edge corresponds to the time of the call.
|
||||||
|
|
||||||
|
The clock generator contains a 24-bit phase accumulator operating on
|
||||||
|
the RTIO clock. At each RTIO clock tick, the frequency tuning word is
|
||||||
|
added to the phase accumulator. The most significant bit of the phase
|
||||||
|
accumulator is connected to the TTL line. Setting the frequency tuning
|
||||||
|
word has the additional effect of setting the phase accumulator to
|
||||||
|
0x800000.
|
||||||
|
"""
|
||||||
|
syscall("ttl_clock_set", now_mu(), self.channel, frequency)
|
||||||
|
self.previous_timestamp = now_mu()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def set(self, frequency):
|
||||||
|
"""Like ``set_mu``, but using Hz."""
|
||||||
|
self.set_mu(self.frequency_to_ftw(frequency))
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def stop(self):
|
||||||
|
"""Stop the toggling of the clock and set the output level to 0."""
|
||||||
|
self.set_mu(0)
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def sync(self):
|
||||||
|
"""Busy-wait until all programmed frequency switches and stops have
|
||||||
|
been effected."""
|
||||||
|
while syscall("rtio_get_counter") < self.o_previous_timestamp:
|
||||||
|
pass
|
||||||
|
|
|
@ -78,7 +78,7 @@ class Inout(Module):
|
||||||
|
|
||||||
|
|
||||||
class ClockGen(Module):
|
class ClockGen(Module):
|
||||||
def __init__(self, pad, ftw_width=16):
|
def __init__(self, pad, ftw_width=24):
|
||||||
self.rtlink = rtlink.Interface(
|
self.rtlink = rtlink.Interface(
|
||||||
rtlink.OInterface(ftw_width, suppress_nop=False))
|
rtlink.OInterface(ftw_width, suppress_nop=False))
|
||||||
|
|
||||||
|
@ -89,7 +89,14 @@ class ClockGen(Module):
|
||||||
self.sync.rio += If(self.rtlink.o.stb, ftw.eq(self.rtlink.o.data))
|
self.sync.rio += If(self.rtlink.o.stb, ftw.eq(self.rtlink.o.data))
|
||||||
self.sync.rio_phy += [
|
self.sync.rio_phy += [
|
||||||
acc.eq(acc + ftw),
|
acc.eq(acc + ftw),
|
||||||
# known phase on write: at rising edge
|
If(self.rtlink.o.stb,
|
||||||
If(self.rtlink.o.stb, acc.eq(2**(ftw_width - 1))),
|
If(self.rtlink.o.data != 0,
|
||||||
|
# known phase on frequency write: at rising edge
|
||||||
|
acc.eq(2**(ftw_width - 1))
|
||||||
|
).Else(
|
||||||
|
# set output to 0 on stop
|
||||||
|
acc.eq(0)
|
||||||
|
)
|
||||||
|
),
|
||||||
pad.eq(acc[-1])
|
pad.eq(acc[-1])
|
||||||
]
|
]
|
||||||
|
|
|
@ -46,6 +46,26 @@ class Loopback(Experiment, AutoDB):
|
||||||
self.rtt = mu_to_seconds(self.loop_in.timestamp() - t0)
|
self.rtt = mu_to_seconds(self.loop_in.timestamp() - t0)
|
||||||
|
|
||||||
|
|
||||||
|
class ClockGeneratorLoopback(Experiment, AutoDB):
|
||||||
|
class DBKeys:
|
||||||
|
core = Device()
|
||||||
|
loop_clock_in = Device()
|
||||||
|
loop_clock_out = Device()
|
||||||
|
count = Result()
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def run(self):
|
||||||
|
self.loop_clock_in.input()
|
||||||
|
self.loop_clock_out.stop()
|
||||||
|
delay(1*us)
|
||||||
|
with parallel:
|
||||||
|
self.loop_clock_in.gate_rising(10*us)
|
||||||
|
with sequential:
|
||||||
|
delay(200*ns)
|
||||||
|
self.loop_clock_out.set(1*MHz)
|
||||||
|
self.count = self.loop_clock_in.count()
|
||||||
|
|
||||||
|
|
||||||
class PulseRate(Experiment, AutoDB):
|
class PulseRate(Experiment, AutoDB):
|
||||||
class DBKeys:
|
class DBKeys:
|
||||||
core = Device()
|
core = Device()
|
||||||
|
@ -81,6 +101,10 @@ class CoredeviceTest(ExperimentCase):
|
||||||
self.assertGreater(rtt, 0*ns)
|
self.assertGreater(rtt, 0*ns)
|
||||||
self.assertLess(rtt, 50*ns)
|
self.assertLess(rtt, 50*ns)
|
||||||
|
|
||||||
|
def test_clock_generator_loopback(self):
|
||||||
|
count = self.execute(ClockGeneratorLoopback)["count"]
|
||||||
|
self.assertEqual(count, 10)
|
||||||
|
|
||||||
def test_pulse_rate(self):
|
def test_pulse_rate(self):
|
||||||
rate = self.execute(PulseRate)["pulse_rate"]
|
rate = self.execute(PulseRate)["pulse_rate"]
|
||||||
print(rate)
|
print(rate)
|
||||||
|
|
|
@ -21,6 +21,7 @@ services = [
|
||||||
("ttl_set_oe", "ttl_set_oe"),
|
("ttl_set_oe", "ttl_set_oe"),
|
||||||
("ttl_set_sensitivity", "ttl_set_sensitivity"),
|
("ttl_set_sensitivity", "ttl_set_sensitivity"),
|
||||||
("ttl_get", "ttl_get"),
|
("ttl_get", "ttl_get"),
|
||||||
|
("ttl_clock_set", "ttl_clock_set"),
|
||||||
|
|
||||||
("dds_init", "dds_init"),
|
("dds_init", "dds_init"),
|
||||||
("dds_batch_enter", "dds_batch_enter"),
|
("dds_batch_enter", "dds_batch_enter"),
|
||||||
|
|
|
@ -51,7 +51,7 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
|
||||||
reply.ttl_levels = 0;
|
reply.ttl_levels = 0;
|
||||||
reply.ttl_oes = 0;
|
reply.ttl_oes = 0;
|
||||||
reply.ttl_overrides = 0;
|
reply.ttl_overrides = 0;
|
||||||
for(i=0;i<RTIO_TTL_COUNT;i++) {
|
for(i=0;i<RTIO_REGULAR_TTL_COUNT;i++) {
|
||||||
rtio_moninj_mon_chan_sel_write(i);
|
rtio_moninj_mon_chan_sel_write(i);
|
||||||
rtio_moninj_mon_probe_sel_write(0);
|
rtio_moninj_mon_probe_sel_write(0);
|
||||||
rtio_moninj_mon_value_update_write(1);
|
rtio_moninj_mon_value_update_write(1);
|
||||||
|
|
|
@ -56,3 +56,11 @@ long long int ttl_get(int channel, long long int time_limit)
|
||||||
rtio_i_re_write(1);
|
rtio_i_re_write(1);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ttl_clock_set(long long int timestamp, int channel, int ftw)
|
||||||
|
{
|
||||||
|
rtio_chan_sel_write(channel);
|
||||||
|
rtio_o_timestamp_write(timestamp);
|
||||||
|
rtio_o_data_write(ftw);
|
||||||
|
rtio_write_and_process_status(timestamp, channel);
|
||||||
|
}
|
||||||
|
|
|
@ -5,5 +5,6 @@ void ttl_set_o(long long int timestamp, int channel, int value);
|
||||||
void ttl_set_oe(long long int timestamp, int channel, int oe);
|
void ttl_set_oe(long long int timestamp, int channel, int oe);
|
||||||
void ttl_set_sensitivity(long long int timestamp, int channel, int sensitivity);
|
void ttl_set_sensitivity(long long int timestamp, int channel, int sensitivity);
|
||||||
long long int ttl_get(int channel, long long int time_limit);
|
long long int ttl_get(int channel, long long int time_limit);
|
||||||
|
void ttl_clock_set(long long int timestamp, int channel, int ftw);
|
||||||
|
|
||||||
#endif /* __TTL_H */
|
#endif /* __TTL_H */
|
||||||
|
|
|
@ -103,7 +103,7 @@ class NIST_QC1(_NIST_QCx):
|
||||||
phy = ttl_simple.Output(platform.request("user_led", 2))
|
phy = ttl_simple.Output(platform.request("user_led", 2))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
self.add_constant("RTIO_REGULAR_TTL_COUNT", len(rtio_channels))
|
||||||
|
|
||||||
phy = ttl_simple.ClockGen(platform.request("ttl", 15))
|
phy = ttl_simple.ClockGen(platform.request("ttl", 15))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
|
@ -142,7 +142,7 @@ class NIST_QC2(_NIST_QCx):
|
||||||
phy = ttl_simple.Output(platform.request("user_led", 2))
|
phy = ttl_simple.Output(platform.request("user_led", 2))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy))
|
rtio_channels.append(rtio.Channel.from_phy(phy))
|
||||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
self.add_constant("RTIO_REGULAR_TTL_COUNT", len(rtio_channels))
|
||||||
|
|
||||||
phy = ttl_simple.ClockGen(platform.request("ttl", 14))
|
phy = ttl_simple.ClockGen(platform.request("ttl", 14))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
|
|
|
@ -113,7 +113,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4))
|
rtio_channels.append(rtio.Channel.from_phy(phy, ofifo_depth=4))
|
||||||
|
|
||||||
self.add_constant("RTIO_TTL_COUNT", len(rtio_channels))
|
self.add_constant("RTIO_REGULAR_TTL_COUNT", len(rtio_channels))
|
||||||
|
|
||||||
phy = ttl_simple.ClockGen(platform.request("ttl", 15))
|
phy = ttl_simple.ClockGen(platform.request("ttl", 15))
|
||||||
self.submodules += phy
|
self.submodules += phy
|
||||||
|
|
Loading…
Reference in New Issue