complete support for TTL clock generator

This commit is contained in:
Sebastien Bourdeauducq 2015-07-04 18:36:01 +02:00
parent a615a3830a
commit 753d61b38f
10 changed files with 124 additions and 14 deletions

View File

@ -21,6 +21,7 @@ _syscalls = {
"ttl_set_oe": "Iib:n",
"ttl_set_sensitivity": "Iii:n",
"ttl_get": "iI:I",
"ttl_clock_set": "Iii:n",
"dds_init": "Ii:n",
"dds_batch_enter": "I:n",
"dds_batch_exit": "n:n",

View File

@ -26,7 +26,8 @@ class TTLOut(AutoDB):
@kernel
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:
pass
@ -37,12 +38,12 @@ class TTLOut(AutoDB):
@kernel
def off(self):
"""Sets the output to a logic low state."""
"""Set the output to a logic low state."""
self.set_o(False)
@kernel
def pulse_mu(self, duration):
"""Pulses the output high for the specified duration
"""Pulse the output high for the specified duration
(in machine units)."""
self.on()
delay_mu(duration)
@ -50,7 +51,7 @@ class TTLOut(AutoDB):
@kernel
def pulse(self, duration):
"""Pulses the output high for the specified duration
"""Pulse the output high for the specified duration
(in seconds)."""
self.on()
delay(duration)
@ -103,18 +104,19 @@ class TTLInOut(AutoDB):
@kernel
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:
pass
@kernel
def on(self):
"""Sets the output to a logic high state."""
"""Set the output to a logic high state."""
self.set_o(True)
@kernel
def off(self):
"""Sets the output to a logic low state."""
"""Set the output to a logic low state."""
self.set_o(False)
@kernel
@ -204,3 +206,69 @@ class TTLInOut(AutoDB):
If the gate is permanently closed, returns a negative value.
"""
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

View File

@ -78,7 +78,7 @@ class Inout(Module):
class ClockGen(Module):
def __init__(self, pad, ftw_width=16):
def __init__(self, pad, ftw_width=24):
self.rtlink = rtlink.Interface(
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_phy += [
acc.eq(acc + ftw),
# known phase on write: at rising edge
If(self.rtlink.o.stb, acc.eq(2**(ftw_width - 1))),
If(self.rtlink.o.stb,
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])
]

View File

@ -46,6 +46,26 @@ class Loopback(Experiment, AutoDB):
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 DBKeys:
core = Device()
@ -81,6 +101,10 @@ class CoredeviceTest(ExperimentCase):
self.assertGreater(rtt, 0*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):
rate = self.execute(PulseRate)["pulse_rate"]
print(rate)

View File

@ -21,6 +21,7 @@ services = [
("ttl_set_oe", "ttl_set_oe"),
("ttl_set_sensitivity", "ttl_set_sensitivity"),
("ttl_get", "ttl_get"),
("ttl_clock_set", "ttl_clock_set"),
("dds_init", "dds_init"),
("dds_batch_enter", "dds_batch_enter"),

View File

@ -51,7 +51,7 @@ static void moninj_monitor(const ip_addr_t *addr, u16_t port)
reply.ttl_levels = 0;
reply.ttl_oes = 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_probe_sel_write(0);
rtio_moninj_mon_value_update_write(1);

View File

@ -56,3 +56,11 @@ long long int ttl_get(int channel, long long int time_limit)
rtio_i_re_write(1);
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);
}

View File

@ -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_sensitivity(long long int timestamp, int channel, int sensitivity);
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 */

View File

@ -103,7 +103,7 @@ class NIST_QC1(_NIST_QCx):
phy = ttl_simple.Output(platform.request("user_led", 2))
self.submodules += 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))
self.submodules += phy
@ -142,7 +142,7 @@ class NIST_QC2(_NIST_QCx):
phy = ttl_simple.Output(platform.request("user_led", 2))
self.submodules += 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))
self.submodules += phy

View File

@ -113,7 +113,7 @@ trce -v 12 -fastpaths -tsi {build_name}.tsi -o {build_name}.twr {build_name}.ncd
self.submodules += phy
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))
self.submodules += phy