TDTZBUS User Guide
Use TDTZBUS to trigger and manage zBUS device racks from MATLAB or Python.
Requirements
-
TDT Drivers
-
TDT ActiveX package
-
Python only:
pywin32
About TDTZBUS
TDTZBUS is a wrapper for the zBUSx ActiveX control that installs with the TDT ActiveX package. It provides access to the zBUS (connect, fire the zBusTrigA and zBusTrigB triggers, flush and reset racks, look up device addresses and microcode versions) and is generally easier to use than calling the zBUSx object directly.
The main convenience is the triggers: the wrapper takes the trigger type by name rather than as a magic number, and supplies the minimum delay for you.
TDTZBUS installs with the ActiveX controls into:
C:\TDT\ActiveX\ActXExamples\Matlab
C:\TDT\ActiveX\ActXExamples\py
or you can download it in the ActiveX Controls example zip.
TDTZBUS Functionality
Note
See zBUS Device in the ActiveX User Reference for the complete zBUSx programming guide.
Creating a TDTZBUS object
zBUS = TDTZBUS();
% or over USB 3.0
zBUS = TDTZBUS('INTERFACE', 'USB3');
from TDTZBUS import TDTZBUS
zb = TDTZBUS()
# or over USB 3.0
zb = TDTZBUS(interface='USB3')
zBUS = actxserver('ZBUS.x');
if zBUS.ConnectZBUS('GB') == 0
error('Unable to connect')
end
Triggers
zBusTrigA and zBusTrigB trigger several processors simultaneously, either in one rack or across every rack.
Confirming a trigger fired
From microcode v57 onward these calls return 0 even when the trigger fired
correctly, so the wrapper does not report the return value. To confirm a
trigger, link the zTrig output to a digital output on the device, or to a
parameter tag you can read back.
To generate a single sample pulse, put an EdgeDetect after the zTrig
component in your circuit.
zBUS.trigA; % pulse trigger A on every rack
zBUS.trigA(1); % pulse trigger A on rack 1 only
zBUS.trigA(1, 'HIGH'); % hold rack 1 high
zBUS.trigA(1, 'LOW'); % and back low
zBUS.trigB(0, 'PULSE', 10); % trigger B, every rack, 10 ms delay
zb.trigA() # pulse trigger A on every rack
zb.trigA(1) # pulse trigger A on rack 1 only
zb.trigA(1, 'HIGH') # hold rack 1 high
zb.trigA(1, 'LOW') # and back low
zb.trigB(0, 'PULSE', 10) # trigger B, every rack, 10 ms delay
% 0 = pulse, 1 = high, 2 = low
zBUS.zBusTrigA(0, 0, 2);
zBUS.zBusTrigA(1, 0, 2);
zBUS.zBusTrigA(1, 1, 2);
zBUS.zBusTrigA(1, 2, 2);
zBUS.zBusTrigB(0, 0, 10);
Flushing and Resetting a Rack
flush clears the I/O lines to remove bad data from the buffers. reset
resets the rack's logical connection to the computer, clearing data lines and
restoring device connections. Both default to rack 1.
zBUS.flush(1);
zBUS.reset(1);
zb.flush(1)
zb.reset(1)
zBUS.FlushIO(1);
zBUS.HardwareReset(1); % returns 0 on success
Device Address and Version
Both take a device name and an optional device number (default 1). The wrapper maps the name to the numeric device ID the control expects.
addr returns 0 if there is no such device. Otherwise even numbers are
position 1 of a rack and odd numbers position 2: 2 = rack 1 position 1,
3 = rack 1 position 2, 4 = rack 2 position 1.
version returns 0 if there is no such device, otherwise the microcode
version.
address = zBUS.addr('PA5'); % address of PA5 #1
version = zBUS.version('RZ6', 2); % microcode version of RZ6 #2
if zBUS.version('RP2') < 50
disp('Update your microcode to run with this ActiveX')
end
address = zb.addr('PA5') # address of PA5 #1
version = zb.version('RZ6', 2) # microcode version of RZ6 #2
if zb.version('RP2') < 50:
print('Update your microcode to run with this ActiveX')
% the raw control takes numeric device IDs
address = zBUS.GetDeviceAddr(33, 1); % 33 = PA5
version = zBUS.GetDeviceVersion(54, 2); % 54 = RZ6
if zBUS.GetDeviceVersion(35, 1) < 50 % 35 = RP2
disp('Update your microcode to run with this ActiveX')
end
Recognised device names, and the IDs they map to:
Synchronising Rack Clocks
sync minimises drift between racks. The first rack listed is the master and
the rest take their clock from it. A raw bitmask is also accepted.
Warning
This only works with the UB1/UZ4 USB 1.1 interfaces and always returns 0 on any other interface type. Connect the Sync lines with short BNC cables and T-connectors to minimise noise.
zBUS.sync([1 3]); % rack 1 is master, rack 3 follows
zBUS.sync(5); % the same thing as a bitmask
zb.sync([1, 3]) # rack 1 is master, rack 3 follows
zb.sync(5) # the same thing as a bitmask
zBUS.zBusSync(5); % bitmask only
Checking for Errors
Returns the last error string, or an empty string if there was none. Note that an unsuccessful return is not always a zBUS error: asking for a device that does not exist legitimately returns 0.
if zBUS.version('PA5') == 0
disp(zBUS.error);
end
if zb.version('PA5') == 0:
print(zb.error())
Examples Using TDTZBUS
You can find examples installed with ActiveX in:
C:\TDT\ActiveX\ActXExamples\Matlab
C:\TDT\ActiveX\ActXExamples\py
or you can download them in the ActiveX Controls example zip.
Report what is on the bus, then toggle trigger A:
import time
from TDTZBUS import TDTZBUS
zb = TDTZBUS()
for device in ('RZ2', 'RZ5', 'RZ6', 'RP2', 'RX6', 'RX8'):
version = zb.version(device)
if version:
print('{0} #1 at address {1}, microcode v{2}'.format(
device, zb.addr(device), version))
for _ in range(5):
zb.trigA(0, 'HIGH')
time.sleep(2)
zb.trigA(0, 'LOW')
time.sleep(2)
zBUS = TDTZBUS();
devices = {'RZ2', 'RZ5', 'RZ6', 'RP2', 'RX6', 'RX8'};
for i = 1:numel(devices)
version = zBUS.version(devices{i});
if version > 0
fprintf('%s #1 at address %d, microcode v%d\n', ...
devices{i}, zBUS.addr(devices{i}), version);
end
end
for i = 1:5
zBUS.trigA(0, 'HIGH');
pause(2);
zBUS.trigA(0, 'LOW');
pause(2);
end