forked from M-Labs/artiq
more TTL channels and larger input FIFOs on Papilio Pro
This commit is contained in:
parent
e5286c57ab
commit
1f6441948d
|
@ -13,14 +13,30 @@ The low-cost Papilio Pro FPGA board can be used with some limitations.
|
||||||
|
|
||||||
When plugged to a QC-DAQ LVDS adapter, the AD9858 DDS hardware can be used in addition to a limited number of TTL channels. The TTL lines are mapped to RTIO channels as follows:
|
When plugged to a QC-DAQ LVDS adapter, the AD9858 DDS hardware can be used in addition to a limited number of TTL channels. The TTL lines are mapped to RTIO channels as follows:
|
||||||
|
|
||||||
+--------------+----------+----------------+
|
+--------------+----------+-----------------+
|
||||||
| RTIO channel | TTL line | Capability |
|
| RTIO channel | TTL line | Capability |
|
||||||
+==============+==========+================+
|
+==============+==========+=================+
|
||||||
| 0 | PMT0 | Output + input |
|
| 0 | PMT0 | Input only |
|
||||||
+--------------+----------+----------------+
|
+--------------+----------+-----------------+
|
||||||
| 1 | TTL0 | Output only |
|
| 1 | PMT1 | Input only |
|
||||||
+--------------+----------+----------------+
|
+--------------+----------+-----------------+
|
||||||
| 2 | TTL1 | Output only |
|
| 2 | TTL0 | Output only |
|
||||||
+--------------+----------+----------------+
|
+--------------+----------+-----------------+
|
||||||
| 3 | TTL2 | Output only |
|
| 3 | TTL1 | Output only |
|
||||||
+--------------+----------+----------------+
|
+--------------+----------+-----------------+
|
||||||
|
| 4 | TTL2 | Output only |
|
||||||
|
+--------------+----------+-----------------+
|
||||||
|
| 5 | TTL3 | Output only |
|
||||||
|
+--------------+----------+-----------------+
|
||||||
|
| 6 | TTL4 | Output only |
|
||||||
|
+--------------+----------+-----------------+
|
||||||
|
| 7 | TTL5 | Output only |
|
||||||
|
+--------------+----------+-----------------+
|
||||||
|
| 8 | TTL6 | Output only |
|
||||||
|
+--------------+----------+-----------------+
|
||||||
|
| 9 | TTL7 | Output only |
|
||||||
|
+--------------+----------+-----------------+
|
||||||
|
| 10 | FUD | DDS driver only |
|
||||||
|
+--------------+----------+-----------------+
|
||||||
|
|
||||||
|
The input only limitation on channels 0 and 1 comes from the QC-DAQ adapter. When the adapter is not used (and physically unplugged from the Papilio Pro board), the corresponding pins on the Papilio Pro can be used as outputs. Do not configure these channels as outputs when the adapter is plugged, as this would cause electrical contention.
|
||||||
|
|
|
@ -96,11 +96,11 @@ Create a new file ``rtio.py`` containing the following: ::
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
with comm_serial.Comm() as comm:
|
with comm_serial.Comm() as comm:
|
||||||
core_driver = core.Core(comm)
|
core_driver = core.Core(comm)
|
||||||
out_driver = rtio.RTIOOut(core=core_driver, channel=1)
|
out_driver = rtio.RTIOOut(core=core_driver, channel=2)
|
||||||
exp = Tutorial(core=core_driver, o=out_driver)
|
exp = Tutorial(core=core_driver, o=out_driver)
|
||||||
exp.run()
|
exp.run()
|
||||||
|
|
||||||
Connect an oscilloscope or logic analyzer to the RTIO channel 1 (pin C11 on the Papilio Pro) and run ``python3 rtio.py``. Notice that the generated signal's period is precisely 4 microseconds, and that it has a duty cycle of precisely 50%. This is not what you would expect if the delay and the pulse were implemented with CPU-controlled GPIO: overhead from the loop management, function calls, etc. would increase the signal's period, and asymmetry in the overhead would cause duty cycle distortion.
|
Connect an oscilloscope or logic analyzer to the RTIO channel 2 (pin C11 on the Papilio Pro, TTL0) and run ``python3 rtio.py``. Notice that the generated signal's period is precisely 4 microseconds, and that it has a duty cycle of precisely 50%. This is not what you would expect if the delay and the pulse were implemented with CPU-controlled GPIO: overhead from the loop management, function calls, etc. would increase the signal's period, and asymmetry in the overhead would cause duty cycle distortion.
|
||||||
|
|
||||||
Instead, inside the core device, output timing is generated by the gateware and the CPU only programs switching commands with certain timestamps that the CPU computes. This guarantees precise timing as long as the CPU can keep generating timestamps that are increasing fast enough. In case it fails to do that (and attempts to program an event with a timestamp in the past), the :class:`artiq.coredevice.runtime_exceptions.RTIOUnderflow` exception is raised. The kernel causing it may catch it (using a regular ``try... except...`` construct), or it will be propagated to the host.
|
Instead, inside the core device, output timing is generated by the gateware and the CPU only programs switching commands with certain timestamps that the CPU computes. This guarantees precise timing as long as the CPU can keep generating timestamps that are increasing fast enough. In case it fails to do that (and attempts to program an event with a timestamp in the past), the :class:`artiq.coredevice.runtime_exceptions.RTIOUnderflow` exception is raised. The kernel causing it may catch it (using a regular ``try... except...`` construct), or it will be propagated to the host.
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ Try the following code and observe the generated pulses on a 2-channel oscillosc
|
||||||
self.o2.pulse(4*us)
|
self.o2.pulse(4*us)
|
||||||
delay(4*us)
|
delay(4*us)
|
||||||
|
|
||||||
If you assign ``o2`` to the RTIO channel 2, the signal will be generated on the pin C10 of the Papilio Pro.
|
If you assign ``o2`` to the RTIO channel 3, the signal will be generated on the pin C10 (TTL1) of the Papilio Pro.
|
||||||
|
|
||||||
Within a parallel block, some statements can be made sequential again using a ``with sequential`` construct. Observe the pulses generated by this code: ::
|
Within a parallel block, some statements can be made sequential again using a ``with sequential`` construct. Observe the pulses generated by this code: ::
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,13 @@ def main():
|
||||||
exp = DDSTest(
|
exp = DDSTest(
|
||||||
core=coredev,
|
core=coredev,
|
||||||
a=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
a=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=0, rtio_switch=0),
|
reg_channel=0, rtio_switch=2),
|
||||||
b=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
b=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=1, rtio_switch=1),
|
reg_channel=1, rtio_switch=3),
|
||||||
c=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
c=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=2, rtio_switch=2),
|
reg_channel=2, rtio_switch=4),
|
||||||
d=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
d=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=3, rtio_switch=3),
|
reg_channel=3, rtio_switch=5),
|
||||||
led=gpio.GPIOOut(core=coredev, channel=0)
|
led=gpio.GPIOOut(core=coredev, channel=0)
|
||||||
)
|
)
|
||||||
exp.run()
|
exp.run()
|
||||||
|
|
|
@ -41,9 +41,9 @@ def main():
|
||||||
exp = PhotonHistogram(
|
exp = PhotonHistogram(
|
||||||
core=coredev,
|
core=coredev,
|
||||||
bd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
bd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=0, rtio_switch=1),
|
reg_channel=0, rtio_switch=2),
|
||||||
bdd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
bdd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=1, rtio_switch=2),
|
reg_channel=1, rtio_switch=3),
|
||||||
pmt=rtio.RTIOIn(core=coredev, channel=0),
|
pmt=rtio.RTIOIn(core=coredev, channel=0),
|
||||||
repeats=100,
|
repeats=100,
|
||||||
nbins=100
|
nbins=100
|
||||||
|
|
|
@ -30,5 +30,5 @@ if __name__ == "__main__":
|
||||||
with comm_serial.Comm() as comm:
|
with comm_serial.Comm() as comm:
|
||||||
coredev = core.Core(comm)
|
coredev = core.Core(comm)
|
||||||
exp = PulsePerformance(core=coredev,
|
exp = PulsePerformance(core=coredev,
|
||||||
o=rtio.RTIOOut(core=coredev, channel=1))
|
o=rtio.RTIOOut(core=coredev, channel=2))
|
||||||
exp.run()
|
exp.run()
|
||||||
|
|
|
@ -32,5 +32,5 @@ if __name__ == "__main__":
|
||||||
coredev = core.Core(comm)
|
coredev = core.Core(comm)
|
||||||
exp = RTIOSkew(core=coredev,
|
exp = RTIOSkew(core=coredev,
|
||||||
i=rtio.RTIOIn(core=coredev, channel=0),
|
i=rtio.RTIOIn(core=coredev, channel=0),
|
||||||
o=rtio.RTIOOut(core=coredev, channel=1))
|
o=rtio.RTIOOut(core=coredev, channel=2))
|
||||||
exp.run()
|
exp.run()
|
||||||
|
|
|
@ -120,16 +120,16 @@ if __name__ == "__main__":
|
||||||
exp = Transport(
|
exp = Transport(
|
||||||
core=coredev,
|
core=coredev,
|
||||||
bd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
bd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=0, rtio_switch=1),
|
reg_channel=0, rtio_switch=2),
|
||||||
bdd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
bdd=dds.DDS(core=coredev, dds_sysclk=1*GHz,
|
||||||
reg_channel=1, rtio_switch=2),
|
reg_channel=1, rtio_switch=3),
|
||||||
pmt=rtio.RTIOIn(core=coredev, channel=0),
|
pmt=rtio.RTIOIn(core=coredev, channel=0),
|
||||||
# a compound pdq device that wraps multiple usb devices (looked up
|
# a compound pdq device that wraps multiple usb devices (looked up
|
||||||
# by usb "serial number"/id) into one
|
# by usb "serial number"/id) into one
|
||||||
electrodes=pdq2.CompoundPDQ2(
|
electrodes=pdq2.CompoundPDQ2(
|
||||||
core=coredev,
|
core=coredev,
|
||||||
ids=["qc_q1_{}".format(i) for i in range(4)],
|
ids=["qc_q1_{}".format(i) for i in range(4)],
|
||||||
rtio_trigger=3, rtio_frame=(4, 5, 6)),
|
rtio_trigger=4, rtio_frame=(5, 6, 7)),
|
||||||
transport_data=data, # or: json.load
|
transport_data=data, # or: json.load
|
||||||
wait_at_stop=100*us,
|
wait_at_stop=100*us,
|
||||||
speed=1.5,
|
speed=1.5,
|
||||||
|
|
|
@ -78,7 +78,7 @@ int rtio_pileup_count(int channel)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define RTIO_FUD_CHANNEL 4
|
#define RTIO_FUD_CHANNEL 10
|
||||||
|
|
||||||
void rtio_fud_sync(void)
|
void rtio_fud_sync(void)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,12 +9,23 @@ from artiqlib import rtio, ad9858
|
||||||
|
|
||||||
_tester_io = [
|
_tester_io = [
|
||||||
("user_led", 1, Pins("B:7"), IOStandard("LVTTL")),
|
("user_led", 1, Pins("B:7"), IOStandard("LVTTL")),
|
||||||
("ttl", 0, Pins("C:13"), IOStandard("LVTTL")),
|
|
||||||
("ttl", 1, Pins("C:11"), IOStandard("LVTTL")),
|
("pmt", 0, Pins("C:13"), IOStandard("LVTTL")),
|
||||||
("ttl", 2, Pins("C:10"), IOStandard("LVTTL")),
|
("pmt", 1, Pins("C:14"), IOStandard("LVTTL")),
|
||||||
("ttl", 3, Pins("C:9"), IOStandard("LVTTL")),
|
|
||||||
("ttl", 4, Pins("C:8"), IOStandard("LVTTL")),
|
("ttl", 0, Pins("C:11"), IOStandard("LVTTL")),
|
||||||
("ttl_tx_en", 0, Pins("A:9"), IOStandard("LVTTL")),
|
("ttl", 1, Pins("C:10"), IOStandard("LVTTL")),
|
||||||
|
("ttl", 2, Pins("C:9"), IOStandard("LVTTL")),
|
||||||
|
("ttl", 3, Pins("C:8"), IOStandard("LVTTL")),
|
||||||
|
("ttl", 4, Pins("C:7"), IOStandard("LVTTL")),
|
||||||
|
("ttl", 5, Pins("C:6"), IOStandard("LVTTL")),
|
||||||
|
("ttl", 6, Pins("C:5"), IOStandard("LVTTL")),
|
||||||
|
("ttl", 7, Pins("C:4"), IOStandard("LVTTL")),
|
||||||
|
("ttl_l_tx_en", 0, Pins("A:9"), IOStandard("LVTTL")),
|
||||||
|
|
||||||
|
("ttl", 8, Pins("C:3"), IOStandard("LVTTL")),
|
||||||
|
("ttl_h_tx_en", 0, Pins("B:6"), IOStandard("LVTTL")),
|
||||||
|
|
||||||
("dds", 0,
|
("dds", 0,
|
||||||
Subsignal("a", Pins("A:5 B:10 A:6 B:9 A:7 B:8")),
|
Subsignal("a", Pins("A:5 B:10 A:6 B:9 A:7 B:8")),
|
||||||
Subsignal("d", Pins("A:12 B:3 A:13 B:2 A:14 B:1 A:15 B:0")),
|
Subsignal("d", Pins("A:12 B:3 A:13 B:2 A:14 B:1 A:15 B:0")),
|
||||||
|
@ -74,18 +85,24 @@ class ARTIQMiniSoC(BaseSoC):
|
||||||
platform.request("user_led", 0),
|
platform.request("user_led", 0),
|
||||||
platform.request("user_led", 1)))
|
platform.request("user_led", 1)))
|
||||||
|
|
||||||
self.comb += platform.request("ttl_tx_en").eq(1)
|
|
||||||
rtio_pads = [platform.request("ttl", i) for i in range(4)]
|
|
||||||
fud = Signal()
|
fud = Signal()
|
||||||
rtio_pads.append(fud)
|
self.comb += [
|
||||||
|
platform.request("ttl_l_tx_en").eq(1),
|
||||||
|
platform.request("ttl_h_tx_en").eq(1)
|
||||||
|
]
|
||||||
|
rtio_ins = [platform.request("pmt") for i in range(2)]
|
||||||
|
rtio_outs = [platform.request("ttl", i) for i in range(8)] + [fud]
|
||||||
|
|
||||||
self.submodules.rtiocrg = _RTIOMiniCRG(platform)
|
self.submodules.rtiocrg = _RTIOMiniCRG(platform)
|
||||||
self.submodules.rtiophy = rtio.phy.SimplePHY(
|
self.submodules.rtiophy = rtio.phy.SimplePHY(
|
||||||
rtio_pads,
|
rtio_ins + rtio_outs,
|
||||||
output_only_pads={rtio_pads[1], rtio_pads[2], rtio_pads[3], fud})
|
output_only_pads=set(rtio_outs))
|
||||||
self.submodules.rtio = rtio.RTIO(self.rtiophy, 125000000)
|
self.submodules.rtio = rtio.RTIO(self.rtiophy,
|
||||||
|
clk_freq=125000000,
|
||||||
|
ififo_depth=512)
|
||||||
|
|
||||||
if with_test_gen:
|
if with_test_gen:
|
||||||
self.submodules.test_gen = _TestGen(platform.request("ttl", 4))
|
self.submodules.test_gen = _TestGen(platform.request("ttl", 8))
|
||||||
|
|
||||||
dds_pads = platform.request("dds")
|
dds_pads = platform.request("dds")
|
||||||
self.submodules.dds = ad9858.AD9858(dds_pads)
|
self.submodules.dds = ad9858.AD9858(dds_pads)
|
||||||
|
|
|
@ -256,7 +256,7 @@ class RTIOCase(unittest.TestCase):
|
||||||
uut = _RTIOLoopback(
|
uut = _RTIOLoopback(
|
||||||
core=coredev,
|
core=coredev,
|
||||||
i=rtio.RTIOIn(core=coredev, channel=0),
|
i=rtio.RTIOIn(core=coredev, channel=0),
|
||||||
o=rtio.RTIOOut(core=coredev, channel=1),
|
o=rtio.RTIOOut(core=coredev, channel=2),
|
||||||
npulses=npulses
|
npulses=npulses
|
||||||
)
|
)
|
||||||
uut.run()
|
uut.run()
|
||||||
|
@ -267,7 +267,7 @@ class RTIOCase(unittest.TestCase):
|
||||||
coredev = core.Core(comm)
|
coredev = core.Core(comm)
|
||||||
uut = _RTIOUnderflow(
|
uut = _RTIOUnderflow(
|
||||||
core=coredev,
|
core=coredev,
|
||||||
o=rtio.RTIOOut(core=coredev, channel=1)
|
o=rtio.RTIOOut(core=coredev, channel=2)
|
||||||
)
|
)
|
||||||
with self.assertRaises(runtime_exceptions.RTIOUnderflow):
|
with self.assertRaises(runtime_exceptions.RTIOUnderflow):
|
||||||
uut.run()
|
uut.run()
|
||||||
|
@ -277,7 +277,7 @@ class RTIOCase(unittest.TestCase):
|
||||||
coredev = core.Core(comm)
|
coredev = core.Core(comm)
|
||||||
uut = _RTIOSequenceError(
|
uut = _RTIOSequenceError(
|
||||||
core=coredev,
|
core=coredev,
|
||||||
o=rtio.RTIOOut(core=coredev, channel=1)
|
o=rtio.RTIOOut(core=coredev, channel=2)
|
||||||
)
|
)
|
||||||
with self.assertRaises(runtime_exceptions.RTIOSequenceError):
|
with self.assertRaises(runtime_exceptions.RTIOSequenceError):
|
||||||
uut.run()
|
uut.run()
|
||||||
|
|
Loading…
Reference in New Issue