Reading parallel port pin (for acquiring response from response pad) for MEG experiment

Hi Experts!

I am trying to read the response pressed on a response pad through parallel port, but its not working. I don’t get any error message. I am very new to both parallel ports as well as programming. I am able to send the triggers successfully though.

The code I used to read the pins:


port = parallel.ParallelPort(0x4FF8)
port.setData(0) # set all pins low

for i in range(0,trials):
    win.flip()
    print("TRIAL NUMBER IS ", i)
    if port.readPin(16) ==0:
        print('16 is low')
    if port.readPin(16) == 1:
        print('16 is high')
    if port.readPin(15) ==0:
        print('15 is low')
    if port.readPin(15) == 1:
        print('15 is high')
    ...
    if port.readPin(1) == 1:
        print('1 is high')
    if port.readPin(1) == 0:
        print('1 is low')
    core.wait(2)

Output:

TRIAL NUMBER IS 0
Pin 16 cannot be read (by PParallelInpOut32.readPin())
Pin 16 cannot be read (by PParallelInpOut32.readPin())
15 is high
Pin 14 cannot be read (by PParallelInpOut32.readPin())
Pin 14 cannot be read (by PParallelInpOut32.readPin())
13 is high
12 is high
11 is low
10 is high
9 is low
7 is low
8 is low
6 is low
5 is low
4 is low
3 is low
2 is low
Pin 1 cannot be read (by PParallelInpOut32.readPin())
Pin 1 cannot be read (by PParallelInpOut32.readPin())

The output I get is irrespective of whether I press any key or not. I don’t understand why some pins cannot be read, and also why some pins are high though I kept them low.

Not sure how to fix this. Any suggestions are appreciated. Thanks in advance

My problem could be similar to yours @jtseng @ulrikeh

Hi There,

What type of response pad/box are you using? Asking because, if the response box has inbuilt support it might be that there is an easier way to communicate with it through PsychoPy.

Becca

1 Like

Hi,
yes, Becca is absolutely right - would be nice to know what kind of pad this is!

Adding to that: most devices on the parallel port use the data pins (2-9), the other pins often serve other functions (see Parallel port - Wikipedia ), so it is completely fine that some of them have other values or that you cannot access them.

Still your pins 2-9 seem not to respond to the button presses. Maybe this is indeed related to the problem I once experienced: Reading from parallel port - #2 by ulrikeh
There I used the pyserial parallel module instead of the psychopy module because I could then set the port to “reading mode”. Have you tried the code of that thread?

1 Like

Agreed with everyone here so far: can you look at your response pad documentation and find how responses map onto parallel port output? Typically, only pins 2-9 are read because those are the data bits - that’s why the psychopy.parallel documentation talks about those pins specifically.

Also, @ulrikeh - you can actually still use the parallel package to flip the bit in the control register that dictates whether it’s reading or sending! See my write-up here. If your data register (aka the typical address you’d use to read the data bits of the parallel port) is at 0x4FF8, then you can check the control register like so:

ctrl_port = parallel.ParallelPort(0x3048+2)
if ctrl_port.readPin(7) is 0:
        ctrl_port.setPin(7,1)
3 Likes

@Becca @ulrikeh @jtseng Thank you all for responding. And sorry for the delay, I am working on multiple things and it has been difficult to focus on one problem at a time.

We are using the response pad that came with Elekta Neuromag TRIUX. Its a bilateral finger response pad.

@jtseng I tried the way you suggested. I end up with the same output. Not able to get any input from the response pad.

@ulrikeh while importing parallel I am getting an error:
OSError: [WinError 193] %1 is not a valid Win32 application. Is it because import parallel is available only for 32 bit? My windows, python, psychopy are all 64bit. Sorry if my understanding is wrong, when I searched, PsychoPy is releasing only 64 bit versions. Is there a solution to this?

The CPU I am using did not have a parallel port, I got a PCIe parallel port card. Can this be a problem?

Hi @nithin, here are a few sporadic thoughts on further troubleshooting:

  1. Just to confirm, are you absolutely sure that you have the correct parallel port address for the button box? If your stimulus computer has NeurObs Presentation software, I could use Presentation to confirm that it was the right parallel port address because it didn’t need any of this additional configuration that PsychoPy ended up requiring to register button box responses.
  2. You can reach out to the Elekta manufacturer and ask for specifications on the bilateral response pad. They should be able to tell you the exact mapping of button responses onto parallel port pinout. That way, you don’t have to guess at which pins will hold the responses you’re looking for.
  3. You probably already got this covered, but in the snippet of code I pasted, you changed the parallel port address to your own right? Realizing that I used our address (3048) instead of yours (4FF8).
  4. Instead of exhaustively checking each pin, you can instead print the output of port.readData(). This should have a different value if a button is pressed.
  5. Hardware sanity checks: have you tried swapping the DB25 cable or swapping which parallel port you’re using for sending vs receiving triggers?
  6. Did you already put the inpout32.dll driver into the experiment folder? You may have read about this from other forum posts. https://www.highrez.co.uk/downloads/inpout32/

I’ll let you know if I can think of anything else. Good luck!

1 Like

Hi @jtseng, thank you for taking time to help me out.
1. I have confirmed my parallel port address through device manager as well as the parallel port tester. And I am able to send triggers through the same. And unfortunately we don’t have Presentation software.
2. I should definitely do this. However, on the trigger box input 14 and 15 lights up when the response is pressed on the response pad. Not quite sure if that means anything. I tried by connecting the BNC cables to 14 and 15 inputs from the output trigger box. That didn’t work though.
3. Yes, I changed it :slight_smile:
4. Thanks for that, using this now.
5. DB25 cable I tried. Have not tried with a different parallel port though. I will do this.
6. Yes

On the parallel port tester, this is how it looks

Just spitballing ideas here: within the same session, are you using the same parallel port address to send triggers and receive button box inputs? Or are you using one parallel port for sending, and another parallel port for receiving?

Is the read/send bit of the control register high or low? i.e., what’s the output of:

ctrl_port = parallel.ParallelPort(0x4FF8+2)
ctrl_port.readPin(7)

I think it would also be helpful for your readers if you do a comprehensive explanation of the setup including each component and its I/O path (e.g., response pad, trigger box that routes the signal, I/O into the machine). It’s also a good practice for you to thoroughly understand where everything’s coming from.

Hi @jtseng
Yes, I am using the same parallel port for sending triggers and receiving inputs. I will brief this as you mentioned. I am starting to think that there is a problem in interfacing. The parallel port of the PsychoPy system is connected ONLY to the stimulus output interface box (in the image, box in the right) of the trigger interface unit (please see image below) through a DB25 male to DB25 female cable.

On the trigger interface unit, 14 and 15 light up (in the image, box in the left) when we press the right and left response pads. There is no BNC cable attached to 14 and 15 of the input triggers from the response pads. I think there is something wrong in the way its interfaced. STIM 2 software uses StimTracker (Cedrus) to send the triggers. However, STIM 2 is not getting any input from the response pads either (Only the MEG acquisition system gets it). Do you think I should connect the 25 pin parallel port to the DB37 port (left box in the image)?

The read/send bit of the control register is low, i.e., 0

ctrl_port.setPin(7,1) # sets it high, i.e., 1

I am wondering, if it is always the pin 7 though.

Thank you!

Nithin

A few thoughts:

Yes, I am using the same parallel port for sending triggers and receiving inputs.

In our experiments and as suggested by other stim software (e.g., NeurObs Presentation), it’s cleanest to use a different parallel port for input (i.e., reading the button box) and another port for output (e.g., sending triggers to the MEG ACQ). Part of this is because bidirectional parallel ports can sometimes be wonky depending on if you have the right kind of hardware/drivers to support it. Furthermore, bit 5 of the control register specifically controls whether the parallel port is reading or writing. In fact, you can see in the parallel port instantiation here that the bit is flipped to OUTPUT mode. So, if you’re not flipping it back and forth, you will only be able to read or write. Maybe I should make a pull request to remove this as a default…

There is no BNC cable attached to 14 and 15 of the input triggers from the response pads.

If there’s no connection between the BNC cables that seem to hold the signal and the interface that sends it to PsychoPy, then it makes sense that PsychoPy wouldn’t receive the signal either!

I think there is something wrong in the way its interfaced.

Your reply was a great exercise for you to begin understanding your configuration, but I encourage you to draw a diagram and label with INPUT/OUTPUT to nail down exactly what’s going on. I’m sure that’ll be useful for future users of the system as well. Also, do you have documentation from the manufacturer on how to use these interface units? That might also help.

I am wondering, if it is always the pin 7 though.

image

Pin 7 on the control register would correspond to bit 5, which is the PS/2 data direction control. (Recall that pins 2-9 map onto data bits 0-7.) Some supplemental reading:

  • Page 4 of this PDF about the Control Register bit 5 (PS/2 Data direction)
  • Lines 52-57 of the PParallelInpOut class source code, where this bit is flipped when instantiating a parallel port
  • This website’s thorough write-up on parallel ports. Look for discussion on “control bit 5”.

Edit: Fixed links to correct _inpout.py git page.

Hi @jtseng
Thank you for explaining this to me. I understood that it is best to use different parallel ports for inputs and outputs. So, I am introducing a new component we have, a Cedrus StimTracker (StimTracker 1G Support). From the MEG manufacturers (MEGIN/Elekta) I got to know that if we attach a BNC to RJ45 cable (from 14 and 15 of the input triggers from the response pads to the RJ45 port on the StimTracker) we can get the inputs to the StimTracker. From the StimTracker website I got to know that these inputs are available as outputs on the two DB25 ports of the StimTracker (Interfacing With StimTracker’s TTL Input Connector). However, it would require a signal adapter board which we already have, and these inputs will be available on pin 10 of the DB25 port on the signal adapter board (StimTracker Interface to PC Parallel Port).

Initially we used this StimTracker only for sending the stimulus presentation triggers for the STIM2 system through USB. And for PsychoPy I was using parallel port.

Please let me know if you have any comments. I will post whatever I get once this procedure is done.

Thanks!
Nithin

Sounds like you’ll be expecting the signal to come into your stimulus computer via parallel port output of your signal adapter board @ pin 10. After instantiating your parallel port, you should use the port.readPin(10) functionality to read pin 10. It’ll return 1 if high, 0 if low. I’d also make sure that the parallel port is set to input functionality. In other words, once your setup is connected, assuming your parallel port address is 0x4FF8:

from psychopy import parallel

# instantiate ports
port = parallel.ParallelPort(0x4FF8)
ctrl_port = parallel.ParallelPort(0x4FF8+2)

# check if direction bit is set to 0 in the control register, if so flip it
if ctrl_port.readPin(7) == 0: 
   ctrl_port.setPin(7, 1)

# check whether a button has been pressed
pressed = False
while not pressed:
   response = port.readPin(10) # returns 1 if pressed, 0 if not
   if response:
      print("Hooray! Button response registered.")
      pressed = True

So here is the solution if anyone come across this situation. Thanks to everyone who helped out! Especially @jtseng !

I installed two PCIe parallel port cards, one for sending and one for receiving TTL pulses.

For sending trigger to the trigger box, I connected the parallel port of the PsychoPy PC (port address:0x4FF8) directly to the trigger box. I used this method to send the trigger.

For receiving the response outputs from the response pads, I connected the BNC outputs of the trigger box to a Cedrus StimTracker using a dual BNC to RJ45 cable (custom made according to pinout configuration of the Extra port on the StimTracker). I connected the extra port of the StimTracker to the PsychoPy PC parallel port (port address: 0x5FF8).

Codes:

from psychopy import parallel

#port setup
port = parallel.ParallelPort(0x5FF8) 

# pin 3 becomes 0 when left key is pressed
# pin 4 becomes 0 when right key is pressed
response1 = port.readPin(3) 
response2 = port.readPin(4)


# which button is pressed? 
# Note: On the StimTracker the TTL pulses are usually high. When a keypress is made the signal becomes low
while response1 == 1 and response2 ==1:
    if port.readPin(3) == 0:
        print("Left pressed")
        break

    if port.readPin(4) == 0:
        print("Right pressed")
        break
2 Likes

That’s great! Glad everything’s working. :clap:

1 Like