In Threshold Discriminator with Event Counter Lab (Lab 3), you created an FPGA design that includes an Oscilloscope block (plus your threshold comparator, event counter, and so on). In this Lab 5, we will remotely acquire the oscilloscope’s data buffers from the DT1260 and plot the captured waveforms in real time using PyQtGraph in Python.
Lab Overview
-
Setup the DT1260 with the firmware from Lab 3 (or similar) that exposes an Oscilloscope component.
-
Install Python and the required libraries:
scisdk
(SciSDK for DT1260 communication)pyqtgraph
(for interactive plotting)PyQt5
(orPySide2
) for the Qt framework (depending on your environment)
-
Run the Python script (we’ll call it
lab5_acquire_plot.py
), which:- Connects to the DT1260.
- Configures the Oscilloscope parameters (trigger mode, decimation, etc.).
- Allocates a buffer to receive waveform data.
- Periodically reads data from the board and updates a PyQtGraph plot in real time.
Key Points
- Memory Map JSON: Ensure you have the correct
RegisterFile.json
(or similarly named) that matches your current firmware build. - Trigger Settings: Adjust them as needed for your specific signal (e.g.,
trigger_mode = "self"
,trigger_level = 30000
, etc.). - Sampling: If your signal is very fast, you might see fewer points in the buffer. Adjust
decimator
if you want a lower effective sampling rate (longer capture).
Python Script: lab5_acquire_plot.py
Below is an example script using PyQtGraph to continuously update a waveform plot. This code is partially inspired by the sample in the problem statement, but adapted for PyQtGraph instead of Matplotlib.
"""
lab5_acquire_plot.py
Acquires waveforms from the DT1260 Oscilloscope using SciSDK and displays them
in real time using PyQtGraph.
"""
import sys
import time
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore, QtWidgets
# SciSDK import
from scisdk.scisdk import SciSDK
from scisdk.scisdk_defines import *
def main():
# 1. Create the SciSDK instance
sdk = SciSDK()
# 2. Add the DT1260 device
# - Adjust "usb:10500" to your actual board's serial number
# - Make sure "./RegisterFile.json" is the correct JSON for your build
res = sdk.AddNewDevice("usb:10500", "dt1260", "./RegisterFile.json", "board0")
if res != 0:
print("Error adding device:", sdk.s_error(res))
sys.exit(1)
# 3. Configure Oscilloscope parameters
# - The paths "board0:/MMCComponents/Oscilloscope_0.<parameter>" must match your design
sdk.SetParameterString("board0:/MMCComponents/Oscilloscope_0.data_processing", "decode")
sdk.SetParameterInteger("board0:/MMCComponents/Oscilloscope_0.trigger_level", 2300)
sdk.SetParameterString("board0:/MMCComponents/Oscilloscope_0.trigger_mode", "self")
sdk.SetParameterInteger("board0:/MMCComponents/Oscilloscope_0.trigger_channel", 0)
sdk.SetParameterInteger("board0:/MMCComponents/Oscilloscope_0.pretrigger", 150)
decimator = 1
sdk.SetParameterInteger("board0:/MMCComponents/Oscilloscope_0.decimator", decimator)
sdk.SetParameterString("board0:/MMCComponents/Oscilloscope_0.acq_mode", "blocking")
sdk.SetParameterInteger("board0:/MMCComponents/Oscilloscope_0.timeout", 3000)
# 4. Allocate buffer for the Oscilloscope
res, buf = sdk.AllocateBuffer("board0:/MMCComponents/Oscilloscope_0")
if res != 0:
print("Error allocating buffer:", sdk.s_error(res))
sys.exit(1)
# 5. Setup PyQtGraph window
app = QtWidgets.QApplication([])
win = pg.GraphicsLayoutWidget(show=True, title="DT1260 Oscilloscope Demo")
win.resize(800, 500)
p = win.addPlot(title="Analog Channel 0")
curve = p.plot(pen='y') # yellow curve
# 6. Create an update function to fetch + plot data
def update():
# Read data from oscilloscope
r, data_buf = sdk.ReadData("board0:/MMCComponents/Oscilloscope_0", buf)
if r == 0:
# Convert data to x/y arrays
x = []
y = []
for i in range(data_buf.info.samples_analog):
x.append(i * decimator)
y.append(data_buf.analog[i])
# Update the plot
curve.setData(x, y)
else:
print("Error reading data:", sdk.s_error(r))
# 7. Use a QTimer to periodically update the plot
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(100) # update every 100 ms
# 8. Start the Qt event loop
app.exec_()
# 9. Cleanup
sdk.DetachDevice("board0")
if __name__ == "__main__":
main()
Code Highlights
-
AddNewDevice
- Connects to the DT1260 over USB with a given serial number.
- Loads the register definitions from
RegisterFile.json
.
-
Oscilloscope Configuration
- We set
trigger_mode="self"
to continuously capture waveforms without waiting on an external trigger. trigger_level=2300
sets the level at which the scope triggers itself.pretrigger=150
means we capture some samples before the trigger point.decimator=1
keeps the full sampling rate. Increase it if you want fewer samples over a longer time window.
- We set
-
AllocateBuffer
- Creates a SciSDK buffer to hold the captured analog samples.
data_buf.info.samples_analog
indicates how many samples are returned.
-
update()
- Reads data from the board using
sdk.ReadData(...)
. - Fills arrays
x
andy
to be plotted in the PyQtGraph window. - Calls
curve.setData(x, y)
to refresh the plot.
- Reads data from the board using
-
Qt Timer
- A
QTimer
callsupdate()
every 100 ms. - This creates a near real-time graph of the acquired waveforms.
- A
Instructions
-
Install Requirements
pip install pyqtgraph PyQt5 scisdk
Note: Depending on your environment, you may need
PySide2
instead ofPyQt5
. -
Compile & Program your Lab 3 firmware onto the DT1260.
-
Copy the matching
RegisterFile.json
(or similarly named file) into the same folder aslab5_acquire_plot.py
.
Important: If you recompile the firmware, the register addresses (and the generated JSON) might change. Always use the latest JSON file that corresponds to the bitstream you programmed on your board.
-
Edit the
"usb:10500"
string to match your board’s serial number. -
Run:
python lab5_acquire_plot.py
-
Observe the PyQtGraph window. A yellow trace should update in real time, showing the captured waveforms.
- Trigger the oscilloscope on channel 1
Change the trigger source to channel 1 and set the trigger level to 2200. You can do this by changing to analog the trigger_mode
sdk.SetParameterString("board0:/MMCComponents/Oscilloscope_0.trigger_mode", "analog")
You will see the signal triggered in the oscilloscope window.