VPixx offers several standard cables designed in partnership with EEG and MEG manufacturers. We also make fully custom cables for our customers as needed.
For simple systems, a single custom cable is typically sufficient. For more complex layouts, particularly with multiple inputs and outputs, you may want to use a breakout box for added flexibility.
If you have any doubts about how to connect our equipment to your receiver, feel free to reach out to our staff scientists, who are happy to provide guidance. Please make sure to let us know the make and model of your receiver and your desired cable length, and include any documentation you might have related to the third-party hardware’s port and pin mappings.
Once you have connected the following:
It’s time to configure your DATAPixx3 for button activity forwarding.
To do this, you will first need to ensure your PC has a copy of our software tools installed. You will also need access to either Python or MATLAB scripting; we provide code examples for both options below.
Whichever software tool you prefer, make sure you install our API tools for that software before running the code. You can find more details about our MATLAB API installation here, and our Python API installation (including adding it to PsychyoPy) here.
Button activity forwarding uses a special schedule that pre-loads one or more digital waveforms onto the DATAPixx3’s onboard memory. Button activity triggers the playback of waveforms on the digital output, which is read by your receiver. This forwarding is near-instantaneous; you may however see a delay if your receiver has a particularly slow sampling rate.
Output waveforms are customizable. You can configure them to:
play on any digital output channel
play at different speeds/durations
play custom pulse sequences
trigger on a button press, release or both
The custom waveform’s address in DATAPixx3 memory determines what button/button activity triggers it. Once the forwarding configuration is saved on your DATAPixx3, it will persist until it is overwritten or the forwarding mode is disabled via a software command.
After writing your waveforms to the DOUT buffer, you need to define the DOUT playback schedule using ‘SetDoutSchedule.’
The maximum size of the waveform in memory defined in the schedule is the number of samples in the waveform + 1. The reason for this is that when the schedule starts, the number of samples actually “played” will be the number of samples specified in ‘SetDoutSchedule’ - 1.
Our first example shows the simplest case of button activity forwarding using the RESPONSEPixx /MRI 10-button unit.
Pressing any button triggers a 50 ms pulse on a unique digital output channel. The output channel value is the same as the input channel value, effectively making this a 1-1 mapping.
MATLAB Example
MATLAB
function enableDinDoutPassthrough()
%This function enables a 1-1 DIN to DOUT passthrough on the DATAPixx3
%We use the RESPONSEPixx MRI 10-button as an example.
%This script only needs to be run once; it will persist on the device until a
%disable command is passed.
% Open Datapixx, stop any schedules which might already be running, and clear any
%existing forwarding behaviour
Datapixx('Open');
Datapixx('StopAllSchedules');
Datapixx('DisableDoutButtonSchedules');
Datapixx('RegWrRd');
%Step 1 - Generate automated DOUT waveforms and load them into DATAPixx3
%memory. For reference, DIN bit assignment for RESPONSEPixx /MRI 10-button is:
%Red Left = 0
%Yellow Left = 1
%Green Left = 2
%Blue Left = 3
%White Left = 4
%Red Right = 5
%Yellow Right = 6
%Green Right = 7
%Blue Right = 8
%White Right = 9
%Pressing a button will trigger a 50 ms pulse on the corresponding DOUT channel.
%The playback speed is determined by samplesPerSecond and triggerLength.
%Adjust either to change trigger lengths. Note some receivers cannot detect very
%short pulses.
triggerLength = 50; %ms
samplesPerSecond = 1000; %s
waveformOnset = 0; %s
maxSamples = triggerLength+1; %maximum size of waveform in memory
doutBufferBaseAddr = 0; %Starting hardware address for button waveforms
doutButtonSchedulesMode = 1; %Waveforms start on a rising edge only, MRI units
%Define bits for each button (0-9)
bits = linspace(0,9,10);
%Simple loop to write waveforms into hardware.
%Buffer address for each DIN channel for a rising edge behaviour is baseAddress + 4069*DIN
for k = 1:numel(bits)
waveform = repmat(2^bits(k), 1, triggerLength);
bufferAddress = doutBufferBaseAddr + 4096*bits(k);
Datapixx('WriteDoutBuffer', waveform, bufferAddress);
end
%Step 2 - Pass playback settings to device and enable passthrough mode
Datapixx('SetDoutSchedule', waveformOnset, samplesPerSecond, maxSamples, doutBufferBaseAddr);
%Filter out button bounces (mostly a concern for electrical units, doesn't hurt)
Datapixx('EnableDinDebounce');
Datapixx('EnableDoutButtonSchedules', doutButtonSchedulesMode); %see DisableDoutButtonSchedules to turn off this mode
%Push commands to hardware and sever connection
Datapixx('RegWrRd');
Datapixx('Close');
fprintf('\n\nAutomatic buttons schedules running\n\n');
end
Python example
PY
import numpy as np
from pypixxlib import _libdpx as dp
def enable_din_dout_passthrough():
#This function enables a 1-1 DIN to DOUT passthrough on the DATAPixx3
#We use the RESPONSEPixx MRI 10-button as an example.
#This script only needs to be run once; it will persist on the device until a
#disable command is passed.
# Open Datapixx and clear any forwarding behaviours
dp.DPxOpen()
dp.DPxDisableDoutButtonSchedules()
dp.DPxUpdateRegCache()
# Step 1 - %Step 1 - Generate automated DOUT waveforms and load them into DATAPixx3
#memory. For reference, DIN bit assignment for RESPONSEPixx /MRI 10-button is:
#Red Left = 0
#Yellow Left = 1
#Green Left = 2
#Blue Left = 3
#White Left = 4
#Red Right = 5
#Yellow Right = 6
#Green Right = 7
#Blue Right = 8
#White Right = 9
#Pressing a button will trigger a 50 ms pulse on the corresponding DOUT channel.
#The playback speed is determined by samplesPerSecond and triggerLength.
#Adjust either to change trigger lengths. Note some receivers cannot detect very
#short pulses.
trigger_length = 50 # ms
samples_per_second = 1000 # Hz
dout_buffer_base_addr = 0 # Initial address for button waveforms
dout_button_schedules_mode = 1 # Triggers start on a rising edge; 1 for MRI
#Define bits for each button (0-9)
bits = np.arange(10)
#Simple loop to write waveforms into hardware.
#Buffer address for each DIN channel for a rising edge behaviour is baseAddress + 4069*DIN
for bit in bits:
waveform = list(np.full(trigger_length, 2 ** bit, dtype=np.uint32))
buffer_address = dout_buffer_base_addr + 4096 * bit
dp.DPxWriteRam(buffer_address, waveform)
# %Step 2 - Pass playback settings to device and enable passthrough mode
#configure buffer-- only need to configure the first one, rest will follow the same format
dp.DPxSetDoutBuff(dout_buffer_base_addr + 4096 * 0, trigger_length*2)
dp.DPxSetDoutSched(0, samples_per_second, 'hz', trigger_length+1)
#Filter out button bounces (mostly a concern for electrical units, doesn't hurt)
dp.DPxEnableDinDebounce()
dp.DPxEnableDoutButtonSchedules()
dp.DPxSetDoutButtonSchedulesMode(dout_button_schedules_mode)
%Push commands to hardware and sever connection
dp.DPxUpdateRegCache()
dp.DPxClose()
print('\n\nAutomatic button schedules running\n\n')
# Call the function
enable_din_dout_passthrough()
Our second example shows a more complex case of button forwarding, in which triggers/pulses encoding button events are sent on a single Digital Output channel. We differentiate between the different button presses by sending a pulse train, composed of 100ms-duration pulses, with the number of pulses corresponding to the button’s Digital Input channel value +1. Once again, we use the RESPONSEPixx /MRI 10-button unit.
MATLAB Example
MATLAB
function forwardButtonActivityAsPulseTrains()
%This function enables button press activity on DIN to send a corresponding pulse train on DOUT 0, on the DATAPixx3
%We use the RESPONSEPixx MRI 10-button as an example.
%This script only needs to be run once; it will persist on the device until a
%disable command is passed.
% Open Datapixx, stop any schedules which might already be running, and clear any
%existing forwarding behaviour
Datapixx('Open');
Datapixx('StopAllSchedules');
Datapixx('DisableDoutButtonSchedules');
Datapixx('RegWrRd');
%Step 1 - Generate automated DOUT waveforms and load them into DATAPixx3
%memory. For reference, DIN bit assignment for RESPONSEPixx /MRI 10-button is:
%Red Left = 0
%Yellow Left = 1
%Green Left = 2
%Blue Left = 3
%White Left = 4
%Red Right = 5
%Yellow Right = 6
%Green Right = 7
%Blue Right = 8
%White Right = 9
%Pressing a button will trigger a train of 100ms-duration pulses on a single DOUT channel (DOUT0), the number of pulses will correspond to the button's DIN channel + 1.
%The playback speed is determined by samplesPerSecond and triggerLength.
%Adjust either to change trigger lengths. Note some receivers cannot detect very
%short pulses.
triggerLength = 100; %ms
samplesPerSecond = 1000; %s
waveformOnset = 0; %s
maxSamples = (triggerLength*2*10); %maximum size of waveform in memory; should be less than 4096, which is the maximum size allowed for each button schedule
doutBufferBaseAddr = 0; %Starting hardware address for button waveforms
doutButtonSchedulesMode = 0; %Waveforms start on a rising edge only, MRI units
%Define bits for each button (0-9)
bits = linspace(0,9,10);
%Simple loop to write waveforms into hardware.
%Buffer address for each DIN channel for a rising edge behaviour is baseAddress + 4069*DIN
for k = 1:numel(bits)
waveform = [repmat(1, 1, triggerLength),repmat(0,1,triggerLength)];
full_waveform = repmat(waveform,1,k); % repeat the pulse a requisite number of times
full_waveform(end+1:end+(maxSamples - length(full_waveform))) = 0; %pad the rest of the values with zero
bufferAddress = doutBufferBaseAddr + 4096*bits(k);
Datapixx('WriteDoutBuffer', full_waveform, bufferAddress);
end
%Step 2 - Pass playback settings to device and enable passthrough mode
Datapixx('SetDoutSchedule', waveformOnset, samplesPerSecond, maxSamples+1, doutBufferBaseAddr);
%Filter out button bounces (mostly a concern for electrical units, doesn't hurt)
Datapixx('EnableDinDebounce');
Datapixx('EnableDoutButtonSchedules', doutButtonSchedulesMode); %see DisableDoutButtonSchedules to turn off this mode
%Push commands to hardware and sever connection
Datapixx('RegWrRd');
Datapixx('Close');
fprintf('\n\nAutomatic buttons schedules running\n\n');
end
Python example
PY
import numpy as np
from pypixxlib import _libdpx as dp
def forwardButtonActivityAsPulseTrains():
# This function enables button press activity on DIN to send a corresponding pulse train on DOUT 0, on the DATAPixx3
#The number of pulses will correspond to the DIN bit of the pressed button +1, e.g. A press on Red button/DIN 0 will result in 1 pulse on DOUT0
# We use the RESPONSEPixx MRI 10-button as an example.
# This script only needs to be run once; it will persist on the device until a
# disable command is passed.
# Open Datapixx and clear any forwarding behaviours
dp.DPxOpen()
dp.DPxDisableDoutButtonSchedules()
dp.DPxUpdateRegCache()
# Step 1 - %Step 1 - Generate automated DOUT waveforms and load them into DATAPixx3
# memory. For reference, DIN bit assignment for RESPONSEPixx /MRI 10-button is:
# Red Left = 0
# Yellow Left = 1
# Green Left = 2
# Blue Left = 3
# White Left = 4
# Red Right = 5
# Yellow Right = 6
# Green Right = 7
# Blue Right = 8
# White Right = 9
# Pressing a button will trigger a train of 100ms-duration pulses on a single DOUT channel (DOUT0), the number of pulses will correspond to the button's DIN channel + 1.
# The playback speed is determined by samplesPerSecond and triggerLength.
# Adjust either to change trigger lengths. Note some receivers cannot detect very
# short pulses.
trigger_length = 100 # ms
samples_per_second = 1000 # Hz
maxSamples = (trigger_length * 2 * 10); # maximum size of waveform in memory; should be less than 4096, which is the maximum size allowed for each button schedule
dout_buffer_base_addr = 0 # Initial address for button waveforms
dout_button_schedules_mode = 1 # Triggers start on a rising edge; 1 for MRI
# Define bits for each button (0-9)
bits = np.arange(10)
# Simple loop to write waveforms into hardware.
# Buffer address for each DIN channel for a rising edge behaviour is baseAddress + 4069*DIN
for bit in bits:
waveformHigh = list(np.full(trigger_length, 1, dtype=np.uint32)) #create high part of pulse
waveformLow = list(np.full(trigger_length, 0, dtype=np.uint32)) #create low part of pulse
waveform = (waveformHigh + waveformLow)*(bit+1) #repeat the pulse for the bit value corresponding to button +1
waveform_zeros = list(np.full(maxSamples-len(waveform), 0, dtype=np.uint32)) #pad the rest of samples with 0s
waveform = waveform + waveform_zeros #pad the rest of samples with 0s
buffer_address = dout_buffer_base_addr + 4096 * bit
dp.DPxWriteRam(buffer_address, waveform)
# %Step 2 - Pass playback settings to device and enable passthrough mode
# configure buffer-- only need to configure the first one, rest will follow the same format
dp.DPxSetDoutSchedule(0.0,samples_per_second,maxSamples+1,dout_buffer_base_addr)
# Filter out button bounces (mostly a concern for electrical units, doesn't hurt)
dp.DPxEnableDinDebounce()
dp.DPxEnableDoutButtonSchedules()
dp.DPxSetDoutButtonSchedulesMode(dout_button_schedules_mode) #Push commnds to hardware and sever connection
dp.DPxUpdateRegCache()
dp.DPxClose()
print('\n\nAutomatic button schedules running\n\n')
# Call the function
forwardButtonActivityAsPulseTrains()
Our final example shows how to combine automatic button forwarding with Pixel Mode triggers. As in the first example, we use the RESPONSEPixx /MRI 10-button unit; and pressing any button triggers a 50 ms pulse on a unique digital output channel. The output channel value is the same as the input channel value, effectively making this a 1-1 mapping. Simultaneously, we use Pixel Mode B to send automated triggers on the last 8 digital output channels (DOUT 16-23), based on the Blue channel value in the top-left pixel of the current video frame; we alternate between displaying full-white and full-black frames to set the last 8 digital output channels to all high and all low, respectively.
This demo requires Pixel Mode B, which is only available on the DATAPixx3 with firmware revision 27 or higher. To update your device firmware, see Performing Firmware Updates
MATLAB Example
MATLAB
function enableDinDoutPassthroughAndPixelModeB()
%This function enables a 1-1 DIN to DOUT passthrough on the DATAPixx3, as
%well as Pixel Mode B to send automated triggers on the last 8 DOUT channels, DOUT 16-23
%We use the RESPONSEPixx MRI 10-button as an example.
%This script only needs to be run once; it will persist on the device until a
%disable command is passed.
% Open Datapixx, stop any schedules which might already be running, and clear any
%existing forwarding behaviour
Datapixx('Open');
Datapixx('StopAllSchedules');
Datapixx('DisableDoutButtonSchedules');
Datapixx('RegWrRd');
%Step 1 - Generate automated DOUT waveforms and load them into DATAPixx3
%memory. For reference, DIN bit assignment for RESPONSEPixx /MRI 10-button is:
%Red Left = 0
%Yellow Left = 1
%Green Left = 2
%Blue Left = 3
%White Left = 4
%Red Right = 5
%Yellow Right = 6
%Green Right = 7
%Blue Right = 8
%White Right = 9
%Pressing a button will trigger a 50 ms pulse on the corresponding DOUT channel.
%The playback speed is determined by samplesPerSecond and triggerLength.
%Adjust either to change trigger lengths. Note some receivers cannot detect very
%short pulses.
triggerLength = 50; %ms
samplesPerSecond = 1000; %s
waveformOnset = 0; %s
maxSamples = triggerLength+1; %maximum size of waveform in memory
doutBufferBaseAddr = 0; %Starting hardware address for button waveforms
doutButtonSchedulesMode = 1; %Waveforms start on a rising edge only, MRI units
%Define bits for each button (0-9)
bits = linspace(0,9,10);
%Simple loop to write waveforms into hardware.
%Buffer address for each DIN channel for a rising edge behaviour is baseAddress + 4069*DIN
for k = 1:numel(bits)
waveform = repmat(2^bits(k), 1, triggerLength);
bufferAddress = doutBufferBaseAddr + 4096*bits(k);
Datapixx('WriteDoutBuffer', waveform, bufferAddress);
end
%Step 2 - Pass playback settings to device and enable passthrough mode
Datapixx('SetDoutSchedule', waveformOnset, samplesPerSecond, maxSamples, doutBufferBaseAddr);
%Filter out button bounces (mostly a concern for electrical units, doesn't hurt)
Datapixx('EnableDinDebounce');
Datapixx('EnableDoutButtonSchedules', doutButtonSchedulesMode); %see DisableDoutButtonSchedules to turn off this mode
%Push commands to hardware and sever connection
Datapixx('RegWrRd');
fprintf('\n\nAutomatic buttons schedules running\n\n');
%Step 3: Enable Pixel Mode B to send automated triggers on DOUT 16-23 by changing the blue channel value of top-left pixel; we will alternate between showing white and black frames, resulting in DOUT 16-23 channels to alternate between high and low.
%Enable Pixel Mode
Datapixx('EnablePixelMode', 2); %eEnable pixel mode B to automatically send triggers on DOUT 16-23 based on the Blue channel value in the top-left pixel
Datapixx('RegWr');
Screen('Preference', 'SkipSyncTests', 1);
% Open a fullscreen window
screenid = max(Screen('Screens'));
[window, windowRect]=PsychImaging('OpenWindow', screenid, 0);
% Wait for a spacebar press to exit
KbName('UnifyKeyNames');
exitKey = KbName('space');
while true
Screen('FillRect',window,[255 255 255]) %draw white frame; top-left pixel will be 255 on blue channel, corresponding to Pixel Mode B trigger: high on last 8 DOUT channels
Screen('Flip',window);
Screen('FillRect',window,[0 0 0]) %draw blackframe; top-left pixel will be 0 on blue channel, corresponding to Pixel Mode B trigger: low on last 8 DOUT channels
Screen('Flip',window);
[keyIsDown, ~, keyCode] = KbCheck;
if keyIsDown && keyCode(exitKey)
break;
end
end
% Close the Psychtoolbox window
sca;
%Shut down
Datapixx('DisablePixelMode');
Datapixx('RegWr');
Datapixx('Close');
end
Python example
PY
import keyboard
import numpy as np
from pypixxlib import _libdpx as dp
from psychopy import core, visual
def enable_din_dout_passthrough_pixel_mode():
# This function enables a 1-1 DIN to DOUT passthrough on the DATAPixx3, as well as Pixel Mode B to send automated triggers on the last 8 DOUT channels, DOUT 16-23
# We use the RESPONSEPixx MRI 10-button as an example.
# This script only needs to be run once; it will persist on the device until a
# disable command is passed.
# Open Datapixx and clear any forwarding behaviours
dp.DPxOpen()
dp.DPxDisableDoutButtonSchedules()
dp.DPxUpdateRegCache()
# Step 1 - %Step 1 - Generate automated DOUT waveforms and load them into DATAPixx3
# memory. For reference, DIN bit assignment for RESPONSEPixx /MRI 10-button is:
# Red Left = 0
# Yellow Left = 1
# Green Left = 2
# Blue Left = 3
# White Left = 4
# Red Right = 5
# Yellow Right = 6
# Green Right = 7
# Blue Right = 8
# White Right = 9
# Pressing a button will trigger a 50 ms pulse on the corresponding DOUT channel.
# The playback speed is determined by samplesPerSecond and triggerLength.
# Adjust either to change trigger lengths. Note some receivers cannot detect very
# short pulses.
trigger_length = 50 # ms
samples_per_second = 1000 # Hz
dout_buffer_base_addr = 0 # Initial address for button waveforms
dout_button_schedules_mode = 1 # Triggers start on a rising edge; 1 for MRI
# Define bits for each button (0-9)
bits = np.arange(10)
# Simple loop to write waveforms into hardware.
# Buffer address for each DIN channel for a rising edge behaviour is baseAddress + 4069*DIN
for bit in bits:
waveform = list(np.full(trigger_length, 2 ** bit, dtype=np.uint32))
buffer_address = dout_buffer_base_addr + 4096 * bit
dp.DPxWriteRam(buffer_address, waveform)
# %Step 2 - Pass playback settings to device and enable passthrough mode
# configure buffer-- only need to configure the first one, rest will follow the same format
dp.DPxSetDoutBuff(dout_buffer_base_addr + 4096 * 0, trigger_length * 2)
dp.DPxSetDoutSched(0, samples_per_second, 'hz', trigger_length + 1)
# Filter out button bounces (mostly a concern for electrical units, doesn't hurt)
dp.DPxEnableDinDebounce()
dp.DPxEnableDoutButtonSchedules()
dp.DPxSetDoutButtonSchedulesMode(dout_button_schedules_mode)
# Push command to hardware
dp.DPxUpdateRegCache()
print('\n\nAutomatic button schedules running\n\n')
#Step 3: Enable Pixel Mode B to send automated triggers on DOUT 16-23 by changing the blue channel value of top-left pixel; we will alternate between showing white and black frames, resulting in DOUT 16-23 channels to alternate between high and low.
dp.DPxEnableDoutPixelModeB() #enable Pixel Mode B
dp.DPxUpdateRegCache()
win = visual.Window(
screen=1,
monitor=None,
fullscr=True,
pos=[0, 0],
color='black',
units="pix"
)
# Get the actual size of the full-screen window
window_width, window_height = win.size
full_screen_white = visual.Rect(
win=win,
width=window_width,
height=window_height,
fillColor='white', # Example fill color
pos=(0, 0) # Center the rectangle
)
full_screen_black = visual.Rect(
win=win,
width=window_width,
height=window_height,
fillColor='black', # Example fill color
pos=(0, 0) # Center the rectangle
)
while True:
if keyboard.is_pressed('q'):
print(" 'q' pressed. Exiting loop.")
break
full_screen_white.draw() #draw white frame; top-left pixel will be 255 on blue channel, corresponding to Pixel Mode B trigger: high on last 8 DOUT channels
win.flip()
full_screen_black.draw() #draw black frame; top-left pixel will be 0 on blue channel, corresponding to Pixel Mode B trigger: low on last 8 DOUT channels
win.flip()
dp.DPxEnableDoutPixelModeB() #disable Pixel Mode B
dp.DPxUpdateRegCache()
win.close()
core.quit()
# Call the function
enable_din_dout_passthrough_pixel_mode()