From caab81974a33ca7758cab6e868a22e0be16a407b Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 17 Oct 2014 00:13:09 +0800 Subject: [PATCH] devices: add pdq2 (incomplete) --- artiq/devices/pdq2.py | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 artiq/devices/pdq2.py diff --git a/artiq/devices/pdq2.py b/artiq/devices/pdq2.py new file mode 100644 index 000000000..8daaf79ec --- /dev/null +++ b/artiq/devices/pdq2.py @@ -0,0 +1,131 @@ +from artiq.language.core import * +from artiq.language.units import * +from artiq.devices import rtio_core + + +# FIXME: check those numbers +frame_setup = 20*ns +trigger_duration = 100*ns +frame_wait = 100*ns +sample_period = 10*us + + +class SegmentSequenceError(Exception): + pass + + +class FrameActiveError(Exception): + pass + + +class FrameCloseError(Exception): + pass + + +class _Segment: + def __init__(self, frame, sn, duration, host_data): + self.core = frame.core + self.frame = frame + self.sn = sn + self.duration = duration + self.host_data = host_data + + @kernel + def advance(self): + if self.frame.pdq.current_frame != self.frame.fn: + raise FrameActiveError + if self.frame.pdq.next_sn != self.sn: + raise SegmentSequenceError + self.frame.pdq.next_sn += 1 + + t = time_to_cycles(now()) + self.frame.pdq.trigger.on(t) + self.frame.pdq.trigger.off(t + time_to_cycles(trigger_duration)) + delay(self.duration) + + +class _Frame: + def __init__(self, core): + self.core = core + self.segment_count = 0 + self.closed = False + + def append(self, name, t, u, trigger=False): + if self.closed: + raise FrameCloseError + sn = self.segment_count + duration = (t[-1] - t[0])*sample_period + segment = _Segment(self, sn, duration, (t, u, trigger)) + setattr(self, name, segment) + self.segment_count += 1 + + def close(self): + if self.closed: + raise FrameCloseError + self.closed = True + + @kernel + def begin(self): + if self.pdq.current_frame >= 0: + raise FrameActiveError + self.pdq.current_frame = self.fn + self.pdq.next_sn = 0 + + t = (time_to_cycles(now()) + - time_to_cycles(frame_setup + trigger_duration + frame_wait)) + self.pdq.frame0.set_value(t, self.fn & 1) + self.pdq.frame1.set_value(t, (self.fn & 2) >> 1) + self.pdq.frame2.set_value(t, (self.fn & 4) >> 2) + t += time_to_cycles(frame_setup) + self.pdq.trigger.on(t) + self.pdq.trigger.off(t + time_to_cycles(trigger_duration)) + + @kernel + def finish(self): + if self.pdq.current_frame != self.fn: + raise FrameActiveError + if self.pdq.next_sn != self.segment_count: + raise FrameActiveError + self.pdq.current_frame = -1 + self.pdq.next_sn = -1 + + def _prepare(self, pdq, fn): + if not self.closed: + raise FrameCloseError + self.pdq = pdq + self.fn = fn + + def _invalidate(self): + del self.pdq + del self.fn + + +class CompoundPDQ2(AutoContext): + parameters = "ids rtio_trigger rtio_frame" + + def build(self): + self.trigger = rtio_core.LLRTIOOut(self, channel=self.rtio_trigger) + self.frame0 = rtio_core.LLRTIOOut(self, channel=self.rtio_frame[0]) + self.frame1 = rtio_core.LLRTIOOut(self, channel=self.rtio_frame[1]) + self.frame2 = rtio_core.LLRTIOOut(self, channel=self.rtio_frame[2]) + + self.frames = [] + self.current_frame = -1 + self.next_sn = -1 + + kernel_attr = "current_frame next_sn" + + def create_frame(self): + return _Frame(self.core) + + def prepare(self, *frames): + # prevent previous frames and their segments from + # being (incorrectly) used again + for frame in self.frames: + frame._invalidate() + + self.frames = list(frames) + for fn, frame in enumerate(frames): + frame._prepare(self, fn) + + # TODO: upload to PDQ2 devices