more TTL channels and larger input FIFOs on Papilio Pro

This commit is contained in:
Sebastien Bourdeauducq 2014-11-30 15:50:57 +08:00
parent e5286c57ab
commit 1f6441948d
10 changed files with 75 additions and 42 deletions

View File

@ -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:
+--------------+----------+----------------+
| RTIO channel | TTL line | Capability |
+==============+==========+================+
| 0 | PMT0 | Output + input |
+--------------+----------+----------------+
| 1 | TTL0 | Output only |
+--------------+----------+----------------+
| 2 | TTL1 | Output only |
+--------------+----------+----------------+
| 3 | TTL2 | Output only |
+--------------+----------+----------------+
+--------------+----------+-----------------+
| RTIO channel | TTL line | Capability |
+==============+==========+=================+
| 0 | PMT0 | Input only |
+--------------+----------+-----------------+
| 1 | PMT1 | Input only |
+--------------+----------+-----------------+
| 2 | TTL0 | 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.

View File

@ -96,11 +96,11 @@ Create a new file ``rtio.py`` containing the following: ::
if __name__ == "__main__":
with comm_serial.Comm() as 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.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.
@ -138,7 +138,7 @@ Try the following code and observe the generated pulses on a 2-channel oscillosc
self.o2.pulse(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: ::

View File

@ -28,13 +28,13 @@ def main():
exp = DDSTest(
core=coredev,
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,
reg_channel=1, rtio_switch=1),
reg_channel=1, rtio_switch=3),
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,
reg_channel=3, rtio_switch=3),
reg_channel=3, rtio_switch=5),
led=gpio.GPIOOut(core=coredev, channel=0)
)
exp.run()

View File

@ -41,9 +41,9 @@ def main():
exp = PhotonHistogram(
core=coredev,
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,
reg_channel=1, rtio_switch=2),
reg_channel=1, rtio_switch=3),
pmt=rtio.RTIOIn(core=coredev, channel=0),
repeats=100,
nbins=100

View File

@ -30,5 +30,5 @@ if __name__ == "__main__":
with comm_serial.Comm() as comm:
coredev = core.Core(comm)
exp = PulsePerformance(core=coredev,
o=rtio.RTIOOut(core=coredev, channel=1))
o=rtio.RTIOOut(core=coredev, channel=2))
exp.run()

View File

@ -32,5 +32,5 @@ if __name__ == "__main__":
coredev = core.Core(comm)
exp = RTIOSkew(core=coredev,
i=rtio.RTIOIn(core=coredev, channel=0),
o=rtio.RTIOOut(core=coredev, channel=1))
o=rtio.RTIOOut(core=coredev, channel=2))
exp.run()

View File

@ -120,16 +120,16 @@ if __name__ == "__main__":
exp = Transport(
core=coredev,
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,
reg_channel=1, rtio_switch=2),
reg_channel=1, rtio_switch=3),
pmt=rtio.RTIOIn(core=coredev, channel=0),
# a compound pdq device that wraps multiple usb devices (looked up
# by usb "serial number"/id) into one
electrodes=pdq2.CompoundPDQ2(
core=coredev,
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
wait_at_stop=100*us,
speed=1.5,

View File

@ -78,7 +78,7 @@ int rtio_pileup_count(int channel)
return r;
}
#define RTIO_FUD_CHANNEL 4
#define RTIO_FUD_CHANNEL 10
void rtio_fud_sync(void)
{

View File

@ -9,12 +9,23 @@ from artiqlib import rtio, ad9858
_tester_io = [
("user_led", 1, Pins("B:7"), IOStandard("LVTTL")),
("ttl", 0, Pins("C:13"), IOStandard("LVTTL")),
("ttl", 1, Pins("C:11"), IOStandard("LVTTL")),
("ttl", 2, Pins("C:10"), IOStandard("LVTTL")),
("ttl", 3, Pins("C:9"), IOStandard("LVTTL")),
("ttl", 4, Pins("C:8"), IOStandard("LVTTL")),
("ttl_tx_en", 0, Pins("A:9"), IOStandard("LVTTL")),
("pmt", 0, Pins("C:13"), IOStandard("LVTTL")),
("pmt", 1, Pins("C:14"), IOStandard("LVTTL")),
("ttl", 0, Pins("C:11"), 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,
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")),
@ -74,18 +85,24 @@ class ARTIQMiniSoC(BaseSoC):
platform.request("user_led", 0),
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()
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.rtiophy = rtio.phy.SimplePHY(
rtio_pads,
output_only_pads={rtio_pads[1], rtio_pads[2], rtio_pads[3], fud})
self.submodules.rtio = rtio.RTIO(self.rtiophy, 125000000)
rtio_ins + rtio_outs,
output_only_pads=set(rtio_outs))
self.submodules.rtio = rtio.RTIO(self.rtiophy,
clk_freq=125000000,
ififo_depth=512)
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")
self.submodules.dds = ad9858.AD9858(dds_pads)

View File

@ -256,7 +256,7 @@ class RTIOCase(unittest.TestCase):
uut = _RTIOLoopback(
core=coredev,
i=rtio.RTIOIn(core=coredev, channel=0),
o=rtio.RTIOOut(core=coredev, channel=1),
o=rtio.RTIOOut(core=coredev, channel=2),
npulses=npulses
)
uut.run()
@ -267,7 +267,7 @@ class RTIOCase(unittest.TestCase):
coredev = core.Core(comm)
uut = _RTIOUnderflow(
core=coredev,
o=rtio.RTIOOut(core=coredev, channel=1)
o=rtio.RTIOOut(core=coredev, channel=2)
)
with self.assertRaises(runtime_exceptions.RTIOUnderflow):
uut.run()
@ -277,7 +277,7 @@ class RTIOCase(unittest.TestCase):
coredev = core.Core(comm)
uut = _RTIOSequenceError(
core=coredev,
o=rtio.RTIOOut(core=coredev, channel=1)
o=rtio.RTIOOut(core=coredev, channel=2)
)
with self.assertRaises(runtime_exceptions.RTIOSequenceError):
uut.run()