Jump to content

As of July 17, 2015, the LabJack forums here at forums.labjack.com are shut down. New registrations, topics, and replies are disabled. All forums are in a read-only state for archive purposes.

Please visit our current forums at labjack.com/forums to view and make new posts. To post on the current forums, use your labjack.com login account. Your old LabJack forums login credentials have been retired. There are no longer separate logins for labjack.com and LabJack forums.


Photo

Using Labjack in Matlab under OS X


  • Please log in to reply
26 replies to this topic

#1 Iandol

Iandol
  • Members
  • 46 posts

Posted 27 August 2010 - 08:28 AM

Hi, just received our testing U3, and I can succesfully use loadlib in matlab to load the exodriver:
header='/usr/local/include/labjackusb.h';
loadlibrary('/usr/local/lib/liblabjackusb',header);
libfunctionsview liblabjackusb

I see 13 functions labelled, but realise I couldn't find any documentation apart from the header file. Is there any other documentation I missed which may help me (not being a C programmer). What I wanted to do in my first foray was the fastest possible switching of a digital I/O between low and high from Matlab (I have my U3 connected to a high speed USB hub). Does the exodriver provide the same functionality as the labjackUD (it has many more fucntions listed by matlab)?

Thanks, installing the drivers has been a beautiful experience compared to my piece-of-junk NI-6009!!!

#2 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 27 August 2010 - 09:25 AM

Hi, just received our testing U3, and I can succesfully use loadlib in matlab to load the exodriver:


Great job. In our limited Matlab experience, you finished the hardest part.

Does the exodriver provide the same functionality as the labjackUD (it has many more fucntions listed by matlab)?


No. The Exodriver is a thin layer around the hardware (think exoskeleton). It provides 4 primary functions: Open, Write, Read, and Close. A minimal program works something like this:

1. Open the U3 (LJUSB_OpenDevice)
2. Write a command to the U3 (LJUSB_Write)
3. Read the response (LJUSB_Read)
4. Repeat 2 and 3
5. Close when done (LJUSB_CloseDevice)

You use Section 5 of the U3 User's Guide to build the commands the U3 expects. There are lots of examples of how to do this C in and Python. The Exodriver examples has the C code. There's a u3.h that implements the UD driver "e-" functions. This is the difference between the Exodriver and the UD driver. The UD driver has those functions built-in, the Exodriver has implementations in user application code. If you know how you may be able to call eDO from u3.h if you build u3.c as a library and load it into Matlab. We've never done this, so we don't know if it would work. In your case, it sounds easier to us to just send the bytes your self rather than rely on the C code.

To know what bytes to write to the U3, we recommend grabbing a copy of LabJackPython. It is a great way to see the bytes coming and going to the U3. To set FIO4 to be output high and then output low:
>>> import u3
>>> d = u3.U3()
>>> d.debug = True
>>> d.getFeedback( u3.BitDirWrite(4, 1), u3.BitStateWrite(4, 1) )
Sent:  [0x1d, 0xf8, 0x3, 0x0, 0x20, 0x1, 0x0, 0xd, 0x84, 0xb, 0x84, 0x0]
Response:  [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
[None, None]
>>> d.getFeedback( u3.BitDirWrite(4, 1), u3.BitStateWrite(4, 0) )
Sent:  [0x9c, 0xf8, 0x3, 0x0, 0xa0, 0x0, 0x0, 0xd, 0x84, 0xb, 0x4, 0x0]
Response:  [0xfa, 0xf8, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]
[None, None]

In the code above, we're sending a feedback command which is documented in Section 5.2.5 of the U3 User's Guide. In the feedback command, we're sending BitDirWrite to set FIO4 to output, and BitStateWrite to set FIO4's state to high.

So to set FIO4 to output high from Matlab, all you would have to do is have a function that calls LJUSB_Write() with these bytes:

Sent:  [0x1d, 0xf8, 0x3, 0x0, 0x20, 0x1, 0x0, 0xd, 0x84, 0xb, 0x84, 0x0]

And then call LJUSB_Read() to read 10 bytes, which you can ignore since they don't tell you much.

It's a low-level interface, but it's very efficient, and it's explicit about what it's doing. Your application seems simple enough that you could hide the low level bytes to send in one or two functions.

Let us know how it goes. We'd like to know about more Mac OS X customers using their LabJacks with Matlab.

#3 Iandol

Iandol
  • Members
  • 46 posts

Posted 27 August 2010 - 01:32 PM

Sent:  [0x1d, 0xf8, 0x3, 0x0, 0x20, 0x1, 0x0, 0xd, 0x84, 0xb, 0x84, 0x0]

And then call LJUSB_Read() to read 10 bytes, which you can ignore since they don't tell you much.

It's a low-level interface, but it's very efficient, and it's explicit about what it's doing. Your application seems simple enough that you could hide the low level bytes to send in one or two functions.

Let us know how it goes. We'd like to know about more Mac OS X customers using their LabJacks with Matlab.


This is wonderful stuff, I love the Python interface, so elegant to have such a robust cross-platform tool. Sadly I left the U3 at work so won't be able to play till next week, however your post is incredibly helpful. Once I get the interface set up and working (maybe delayed a bit by other lab projects!), I'll post the Matlab wrapper class to github, and will contribute it to the Psychophysics toolbox (which will have to be cross-platform with windows). As this is a perennial problem for researchers using Macs, macresearch.org may also be an interesting place to post it.

#4 Iandol

Iandol
  • Members
  • 46 posts

Posted 31 August 2010 - 09:09 AM

I'm getting an immediate Matlab crash with LJUSB_Write when I try the following:
function setFIO4(obj,val)
	high = hex2dec(['1d'; 'f8'; '03'; '00'; '20'; '01'; '00'; '0d'; '84'; '0b'; '84'; '00'])';
	low = hex2dec(['9c'; 'f8'; '03'; '00'; 'a0'; '00'; '00'; '0d'; '84'; '0b'; '04'; '00'])';
	highPtr=libpointer('uint8Ptr',high);
	lowPtr=libpointer('uint8Ptr',low);
	if ~exist('val','var')
		val = 0;
	end
	if val == 1
		out = calllib('liblabjackusb', 'LJUSB_Write', obj.handle, highPtr, 12)
		in =  calllib('liblabjackusb', 'LJUSB_Read', obj.handle, inp, 10)
	else
		out = calllib('liblabjackusb', 'LJUSB_Write', obj.handle, lowPtr, 12)
		in =  calllib('liblabjackusb', 'LJUSB_Read', obj.handle, inp, 10)
	end	
end

According to libfunctions I must pass in a uint8Ptr.
[ulong, voidPtr, uint8Ptr] LJUSB_Write(voidPtr, uint8Ptr, ulong)

I assume I've passed values wrongly somewhere but can't figure out where!

#5 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 31 August 2010 - 11:17 AM

This section of the User's Guide on Passing a Pointer to the First Element of an Array suggests that the call to libpointer is optional. That is, you could try:

out = calllib('liblabjackusb', 'LJUSB_Write', obj.handle, high, 12)

I would double-check the obj.handle (voidPtr), too. This is returned from LJUSB_OpenDevice, right? Do you have a way to check if it's not null?

#6 Iandol

Iandol
  • Members
  • 46 posts

Posted 02 September 2010 - 02:52 PM

Right, I've removed and rebuilt both libusb and liblabjackusb, and rebooted. I can now use my class to toggle FIO4 from the matlab prompt (yay!), and sometimes when Matlab runs a script, but I'm still getting frequent crashes when running from a script. So my Write call is fine (you're right I didn't need to type cast to pointers, matlab does it for me). I'll give this a go on an old linux machine with matlab installed and see if I have instability there. For what its worth (probably not much), libusb is the first item in the matlab crash stack; I can send you a crash log though doubt you'd be able to use it.

#7 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 02 September 2010 - 03:45 PM

I'll give this a go on an old linux machine with matlab installed and see if I have instability there.


There's cause for optimism. The libusb-1.0 Linux-specific code is more mature and in our experience more robust than on Mac OS X. Both of them are great, though, and generally crash-free. We're thankful for implementations on both operating systems, without which the Exodriver wouldn't exist.

For what its worth (probably not much), libusb is the first item in the matlab crash stack; I can send you a crash log though doubt you'd be able to use it.


Yes, we would be happy to take a look.

#8 Iandol

Iandol
  • Members
  • 46 posts

Posted 03 September 2010 - 07:24 AM

There's cause for optimism.


Not too much as all our production machines stil use OS X, which is the optimal OS for the Psychophysics toolbox! :p

I've attached the crashlogs for 3 representative crashes.

One other thing I noticed (this is on a high speed hub on a high speed port) when running via the command line, if I toggle FIO4 a thousand times in a tight loop and divide total time by number of switches, I get about a 1.6ms to switch between levels, and about 0.4ms doing the same on a FTDI USB -> serial. Now of course my FTDI doesn't do all the cool things the LabJack does, but just wondered as 1.6ms is higher than you have measured. I'll try the same in LabJackPython and see if it is any faster.

Thanks again for all your help!

Attached Files



#9 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 03 September 2010 - 09:21 AM

There's cause for optimism.


Not too much as all our production machines stil use OS X


Of course. I meant optimism for tracking down the problem. Any news on Linux?

I've attached the crashlogs for 3 representative crashes.


Thanks. We'll have a look.

One other thing I noticed (this is on a high speed hub on a high speed port) when running via the command line, if I toggle FIO4 a thousand times in a tight loop and divide total time by number of switches, I get about a 1.6ms to switch between levels, and about 0.4ms doing the same on a FTDI USB -> serial. Now of course my FTDI doesn't do all the cool things the LabJack does, but just wondered as 1.6ms is higher than you have measured. I'll try the same in LabJackPython and see if it is any faster.


In LabJackPython we can get times consistent with Section 3.1 of the U3 User's Guide. That is, we can generally get about 0.6 ms with a hub and about 4 ms without a hub.

Here's without a hub:

>>> import u3
>>> from datetime import datetime
>>> d = u3.U3()
>>> def f():
...   t1 = datetime.now()
...   for i in range(1000):
...	 d.getFIOState(4)
...   t2 = datetime.now()
...   print (t2-t1)/1000
... 
>>> f()
0:00:00.004001
>>> f()
0:00:00.003999
>>> f()
0:00:00.004000

Here's after I plug in a crappy un-powered hub:

>>> d.close()
# Plug in crappy hub
>>> d = u3.U3()
>>> f()
0:00:00.001191
>>> f()
0:00:00.001191
>>> f()
0:00:00.001186

So in this case it runs at 1.2 ms, but with a good, powered hub it can go to 0.6 ms. The LabJackPython Examples/ directory has a file named u3allio.py that can measure the same thing:

$ python u3allio.py 1
Time difference:  0:00:01.171532
Time per iteration:  0:00:00.001171
Time per iteration in millis:  1.171
Latest readings:  [-8.9284480000000013]


#10 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 03 September 2010 - 10:46 AM

I've attached the crashlogs for 3 representative crashes.


The first three lines of the stack trace in matlab_crash_dump.41577 are:

Stack Trace:
  [0] libusb-1.0.0.dylib:libusb_get_device~(0, 0, 0xb49031c8, 0x07606890 "9MatrixRef") + 9 bytes
  [1] liblabjackusb.dylib:LJUSB_SetupTransfer~(0, 0x3796f7b0, 12, 0) + 17 bytes
  [2] liblabjackusb.dylib:LJUSB_Write~(0, 0x3796f7b0, 12, 0x075ec2bb) + 39 bytes

The most likely cause of a crash here is an invalid handle (i.e., the first argument to all three functions).

Here are the prototypes of LJUSB_Write() and LJUSB_SetupTransfer():

unsigned long LJUSB_Write(HANDLE hDevice, BYTE *pBuff, unsigned long count)
static unsigned long LJUSB_SetupTransfer(HANDLE hDevice, BYTE *pBuff, unsigned long count, enum LJUSB_TRANSFER_OPERATION operation)

In LJUSB_SetupTransfer() we call libusb_get_device() like this:

//First determine the device from handle.
	dev = libusb_get_device(hDevice);

and here is the prototype and code (it's very small) for libusb_get_device():

libusb_device *libusb_get_device(libusb_device_handle *dev_handle);

API_EXPORTED libusb_device *libusb_get_device(libusb_device_handle *dev_handle)
{
	return dev_handle->dev;
}

The only way I can understand that code failing is if the passed-in handle is invalid.

I can't read the stack trace well enough to know if a valid handle is passed in. The 12 in this line would match the count parameter:

[1] liblabjackusb.dylib:LJUSB_SetupTransfer~(0, 0x3796f7b0, 12, 0) + 17 bytes

If the first 0 in that list is supposed to be the handle, then that's my guess what the problem is. Do you have a way to log/debug what the handle you pass in? (I'm sure you have no cause to believe it changes.)

The Exodriver has a function:

bool LJUSB_IsHandleValid(HANDLE hDevice);

that you might consider during debugging. Its purpose is really to detect if a LabJack has been disconnected since the last time it was called, but it could work here.

#11 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 07 September 2010 - 11:35 AM

For other Matlab users who require only 10 Hz or slower sampling, LJFuse is a very simple way to get data from your LabJack into Matlab. The process would be

fid = fopen('MyU6/connection/AIN0');
A = fscanf(fid, '%f');
fclose(fid);


#12 Iandol

Iandol
  • Members
  • 46 posts

Posted 14 September 2010 - 02:19 AM

Yes, you are absolutely spot on, it seems sometimes the handle is invalid. Now I'm not sure why it sometimes clears the handle during use, but by simply checking the handle is valid before calling a write, I don't see any more crashes. Still have to test it in Linux for C-R times, I've bought a brand new high-speed powered hub so lets see how Matlab and LabJackPython compare for command-response times (when I get time).

#13 Iandol

Iandol
  • Members
  • 46 posts

Posted 23 November 2010 - 03:27 PM

For anyone who wants it, my wrapper class to toggle FIO4 and FIO5 of the U3 in Matlab on OS X (and I assume Linux) is attached.

To use:

>> st = sendTTL %initialise new object, by default it will auto-open a connection to the U3
>> st.setFIO4(1) %set FIO4 high
>> st.toggleFIO4 %toggle this line
>> st.verbosity = 0 %don't write results to the command window
>> st.close

You can pass a structure of settings, and my constructor will ignore unknown settings:

>> st = sendTTL(struct('verbosity',0,'openNow',0,'header','/mypath/llj.h'))
>> st.open
>> st.toggleFIO4 %toggle this line
>> st.close

Attached File  sendTTL.m   7.33KB   1235 downloads

#14 Jamesce

Jamesce
  • Members
  • 4 posts

Posted 07 September 2012 - 01:27 PM

For anyone who wants it, my wrapper class to toggle FIO4 and FIO5 of the U3 in Matlab on OS X (and I assume Linux) is attached.
Attached File  sendTTL.m   7.33KB   1235 downloads


I saw your post on psychtoolbox, and I'm trying to look into the possibility of using labjack to send triggers to either a biosemi or brain products device from a mac, and I'm not familiar, at all, with I/O devices. From what I could tell, it seems like we should be able to use your code to send the trigger. Though, I wanted to double check that we would be able to send this from the parallel port on the U6, as this is how we have previously connected to the acquisition machine.

Thanks for any help you an provide in this regard.

~James

#15 Iandol

Iandol
  • Members
  • 46 posts

Posted 11 September 2012 - 05:52 AM

For anyone who wants it, my wrapper class to toggle FIO4 and FIO5 of the U3 in Matlab on OS X (and I assume Linux) is attached.
Attached File  sendTTL.m   7.33KB   1235 downloads


I saw your post on psychtoolbox, and I'm trying to look into the possibility of using labjack to send triggers to either a biosemi or brain products device from a mac, and I'm not familiar, at all, with I/O devices. From what I could tell, it seems like we should be able to use your code to send the trigger. Though, I wanted to double check that we would be able to send this from the parallel port on the U6, as this is how we have previously connected to the acquisition machine.

Thanks for any help you an provide in this regard.

~James


Yes, that should be no problem, if you know what pin you want, you can send a TTL on that pin easily, or do you need to send more than a TTL? My updated code is available here:

https://raw.github.c...ation/labJack.m

You can send a TTL on any FIO, EIO or CIO pin, or you can send an 11bit strobed word on EIO and CIO which are most conveniently located on the LabJack DB15 connector. We use the strobed word from the DB15 to a Plexon omniplex DB25.

examples:
l = labJack('verbose',true);
l.timedTTL(0,500) %send a 500ms long TTL on FIO0
l.timedTTL(9,5) %send a 5ms long TTL on EIO1

l.setDIO([9,9,9]) % set FIO EIO and CIO channel 0 and 3 high

l.toggleFIO(4) % toggle FIO4 between low<>high

l.prepareStrobe(567,[],1) %send the value 567 via a strobed word on EIO and CIO


#16 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 11 September 2012 - 01:27 PM

For documentation on the DB37, DB15 and their connector pinouts, refer to these sections in the User's Guide:

http://labjack.com/s...sers-guide/2.11
http://labjack.com/s...sers-guide/2.12

For specifications on the digital I/O lines look at Appendix A:

http://labjack.com/s...uide/appendix-a

#17 Jamesce

Jamesce
  • Members
  • 4 posts

Posted 17 September 2012 - 04:43 PM

Ok. Like I said, I have no experience with I/O devices. So, I need to get an output from the labjack that is going to similar to the standard parallel port, particularly with the 8 data output lines. I found the following device, but am a bit worried about how to actually set this up and if this interface will cause delays in the signal. Suggestions?

#18 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 18 September 2012 - 07:15 AM

So, I need to get an output from the labjack that is going to similar to the standard parallel port, particularly with the 8 data output lines.

What were you doing with the parallel port? Sending multiple bytes using a standard parallel port API, or using some low-level API to toggle a single bit or multiple bits?

The U3 or U6 both have enough digital I/O to do things similar to a parallel port. You would call matlab commands to change the state of various digital I/O in the sequence you need. You can do this on the order of milliseconds, but the estimated time depends on the exact sequence of I/O operations you need.

#19 Jamesce

Jamesce
  • Members
  • 4 posts

Posted 18 September 2012 - 09:09 AM

We were sending a variable 8-bit code at different times throughout an experiment.

Here is some information from the eeg company:
http://www.biosemi.c...ger_signals.htm

Given that there are enough dio's, what would you recommend to do on the hardware side of things? What additional hardware might I need.

Best,
~James

#20 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 18 September 2012 - 09:44 AM

I am not real clear on what the Biosemi thing is or does, but the link does mention that it has 10k pull-ups. I suggest you take a digital I/O from the U3/U6 and try it. I would try EIO0, so connect EIO0 to one of the trigger inputs. Use the test panel in LJControlPanel (on Windows) to change the state of EIO0 and see if it causes the desired result on your device. Digital I/O have 3 states: Input => Should result in high on your device Output-High => Should result in high on your device Output-Low => Should result in low on your device

#21 Jamesce

Jamesce
  • Members
  • 4 posts

Posted 18 September 2012 - 10:17 AM

Sorry, but I am going to be shamelessly ignorant. How do I connect one EIO from the labjack to the db37 input of the device of interest? Really . . . I know absolutely nothing in this regard.

#22 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 18 September 2012 - 10:48 AM

You want to make a connection from EIO0 to your device pin any way you can. You also most likely want to connect GND on the LabJack to ground on your device.

On the LabJack side, EIO0 is on the DB15 connector of the U3 or U6:

http://labjack.com/s...sers-guide/2.11

The most common way to connect a wire to EIO0 would be to use a CB15 terminal board. Another way is to buy a DB15 cable, cut one end off, and pigtail the wires.

As for your device, if it has a DB37 connector try a google search for "db37 breakout screw-terminals" to find various options.

#23 zim_bob

zim_bob
  • Members
  • 4 posts

Posted 09 November 2012 - 11:12 AM

Hi Ian, Using your matlab code, is the TTL pulse positive logic when the line is at 0V and negative when the line is at 5V? Also, I can't seem to figure out how to read the voltage on an input line, i.e., I have a digital line in from my device that tells me when it's ready and I'm trying to read it from one of the FIOs. Any help would be greatly appreciated!!! ~z

#24 Iandol

Iandol
  • Members
  • 46 posts

Posted 12 November 2012 - 08:55 AM

Using your matlab code, is the TTL pulse positive logic when the line is at 0V and negative when the line is at 5V? Also, I can't seem to figure out how to read the voltage on an input line, i.e., I have a digital line in from my device that tells me when it's ready and I'm trying to read it from one of the FIOs.
Any help would be greatly appreciated!!!


I only ever have grounded lines and pulse to +V so haven't written anything to pull a +V line to ground as a "signal". And you are correct, I don't have a method to read a digital line as I never need to. It should be trivial to add a method to do that, but I don't have the time to add those functions for the next couple of weeks at least, I'd be more than happy for you to make such modifications if you had the time. I will put it on my to-do for the future.

#25 LabJack Support

LabJack Support
  • Admin
  • 8677 posts

Posted 12 November 2012 - 02:33 PM

If you want to read a single digital line take a look at this topic as it provides a quick C low-level example along with some documentation links:

https://forums.labja...?showtopic=5971

That should help with setting up the command and how to read the response packets/arrays. Take a look through Ian's source code to see how to write/read USB packets and calculate checksums in MATLAB.

C low-level examples are provided in the Exodriver source code and low-level documentation is in section 5 of the User's Guide.


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users