Digital I/O

cancel
Showing results for 
Search instead for 
Did you mean: 

C code control of NI USB-6501 compared to NI PCI-DIO-96

I received my NI USB-6501 recently and so far, so good.  I am able to make and run the NI-DAQmx Base dio example, readDigPort.  Just two simple questions:
 
1.  Is it normal for the green LED on the NI USB-6501 to be blinking steadily at about 2 Hz all the time regardless of whether or not a program is communicating with it?  I noticed this when plugged into an older PowerBook G4 and a brand new Power Mac G5.
 
2.  When running the readDigPort example, is it normal for the DAQmxBaseCreatTask command to take a long time?  About 11 or 12 seconds on the PowerBook G4 (667 MHz, 512 MB SDRAM) and about 5 or 6 seconds on the Power Mac G5 (Dual 2.3 GHz, 1 GB SDRAM).  All other commands that follow in that example seem to execute very rapidly.
 
Daniel Shima
Vanderbilt Vision Research Center
0 Kudos
Message 11 of 18
(4,043 Views)
Daniel,

Yes this is normal behavior on both counts. The blinking LED is just indicating that the device is receiving power and operation normally. In fact there is a KB that describes this.

Now the reason that the DAQmx Base Create Task is taking so long is that once a Base call (which ever the first base call) is made it (the system) needs to load the drivers and the runtime engine, and this takes a bit as you have noticed. That is also why on a faster computer, you can load these things faster, there for you wait time is cut down. And then once those are loaded everything moves fast from there.

Hope that explains things for you. Good luck with your project.

-GDE
0 Kudos
Message 12 of 18
(4,027 Views)

I've looked at the C manual, but it is not really helping.  This is what I want to do, and it doesn't seem to work:

With the 6501, I need to put single bit signals out on the ports (about 12 lines), and read one bit in.  The bit I am reading in is actually just a continuity check and should just be a readback of one of the output bits.  I need to do bitwise addressing, so I wrote functions to read the ports in, do a logical and / or, then write the ports back out.

This is my setup:

 char chan0[] = "Dev1/port0";
 char chan1[] = "Dev1/port1";
 char chan2[] = "Dev1/port2";

 DAQmxBaseCreateTask("",&taskHandle);
 DAQmxBaseCreateDOChan(taskHandle,chan0,"",DAQmx_Val_ChanForAllLines);
 DAQmxBaseCreateDOChan(taskHandle,chan1,"",DAQmx_Val_ChanForAllLines);
 DAQmxBaseCreateDIChan(taskHandle,chan2,"",DAQmx_Val_ChanForAllLines);

These are my read / write functions (they are bit funny since I use them at a higher level to do bitwise reads / writes):

int write_dio(unsigned char port0_data, unsigned char port1_data, unsigned char port2_data)
{
 int32 written;
 int32 return_val;
 unsigned char port_data[3];

 port_data[0] = port0_data;
 port_data[1] = port1_data;
 port_data[2] = port2_data;

 return_val = DAQmxBaseWriteDigitalU8(taskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,port_data,&written,NULL);
 return return_val;
}

int read_dio(unsigned char *port0_data,unsigned char *port1_data,unsigned char *port2_data)
{
 int32 read;
 int32 return_val;
 unsigned char port_data[3];

 return_val = DAQmxBaseReadDigitalU8(taskHandle,1,10.0,DAQmx_Val_GroupByChannel,port_data,3,&read,NULL);

 *port0_data = port_data[0];
 *port1_data = port_data[1];
 *port2_data = port_data[2];

 return return_val;
}

I really don't understand how channels are written / read when there is no channel parameter in the read / write functions.  If possible, I'd like to set each line to be a channel, and then just write each one individually, but it looks like I have to write at least 8 bits at a time since the function writes to 8 bit ports.

I have not used any LabView stuff before, and am doing this only in C (on Linux), so maybe my unfamiliarity with LabView is an issue.  Also, is there a better primer for the C interface than just the API reference?  It really doesn't help much with concepts, like tasks.  Can't I just address the pins directly for reading and writing without setting up tasks?

Thanks,

David

 

 

0 Kudos
Message 13 of 18
(3,886 Views)
Hello Sileas,

I have taken a look at your code below, and I have a couple comments.  First, you are creating tasks for port0, 1 and 2 on your USB-6501.  This means that each task will have 8 lines you are writing to. When you create a task you are given a handle to that task.  When you want to perform a read or write to a specific port you need to send the DAQmxBaseWriteDigitalU8 or the DAQmxBaseReadDigitalU8 the taskhandle you created before.  The task handle is how you reference the channels, since you added the channels to that task.

In your case it seems that you are read and write tasks are separate, so you might want to create two or three tasks (one for reading and one/two for writing data).

You also mentioned that you wish to read and write to a single bit.  In DAQmx and DAQmx base these bits are called lines.  You can specify a single line when you create your DO or DI channel by adding some extra information to your channel string.  For example below you specify char chan0[] = "Dev1/port0";  instead you could use char chan0[] = "Dev1/port0/line0";  or chan0[] = "Dev1/port0/line0:1" for lines 0 and 1.

This information is given in the manual.  If you look under the DAQmxCreateDOChan help under the lines parameter you will see the following description:  "The names of the digital lines used to create a virtual channel. You can specify a list or range of lines such as the following: Dev1/port0:1 or Dev1/port0,Dev1/port2 or Dev1/port0/line0:4 "

The help file, along with the examples that ship with daqmxbase are the best resource for information.  The examples are typically located under /usr/local/natinst/nidaqmxbase/examples/

Regards,

Jesse O.
Applications Engineering
National Instruments

Message Edited by Jesse O on 08-07-2006 12:30 PM

Jesse O. | National Instruments R&D
0 Kudos
Message 14 of 18
(3,850 Views)
Thanks for the comments, but I am still quite confused as to how a 8 bit read / write function is supposed to address individual bits (or lines).  I would have expected the read / write functions to use some sort of channel handle, but instead they have task handles. 
 
Tell me what happens in this case:
 
I set up a task and three output channels.  The 3 channels are Dev1/port0, Dev1/port1/line0:3, and Dev1/port2/line1
 
Say I want to write a "1" Dev1/port2/line1 (i.e. channel 3) - what do I do?  What about writing to just the 4 lines of port 1 (i.e. channel 2)?
 
Looking at the writeU8 function, it has "samples per channel", which appears to be how many different samples in time to write, which doesn't help.  The "writeArray" (which is an array of unsigned chars) is how I put my data in to the function, but how is that arranged?  Is is packed, or per port?
 
Example:  Write 0xAA to Channel 1, 1111b to Channel 2, and 1 to Channel 3. 
Is writeArray = 0xAA 0x0F 0x01, one byte with the appropriate bits filled in?
Is writeArray = 0xAA 0x1F, meaning packed (i.e. there a a total of 13 bits across 3 channels, so put their values in an array large enough to hold 13 bits)?
 
Same thing for reads.  What if I have defined two input channels, say one on Dev1/port0/line0 and Dev1/port0/line1? When I read, do I get both back in a single byte, line 0 in bit 0 and line 1 in bit 1, or do I get two bytes, with line 0 in bit 0 of byte 0 and line 1 in bit 0 (or 1?) of byte 1?
 
Also, I am very concerned that if I want to just write an individual line on a port that the other lines do not get affected.  I am controlling lines for relays to test equipment and momentary glitches on lines I am not intending to write could be very bad for the setup.
 
The documentation, which is just an API description (which does not constitute a real help file, with concepts, explanations, examples, etc.) does not go into this.  Neither does the example code, which is very simple reading a writing of entire ports, and not lines.  I would expect many people to be interested in reading and writing lines.  Is there not a "programming manual" somewhere that explains all this?  If I can't address my individual channels in reads and writes, then what is the point of having them?  Shouldn't I just work with tasks only, and just make a single channel per task?
 
Again, forgive me if I seem to not understand how all this works, as I have never used LabView.  I assumed that the USB-6501 module would allow me to do bit (line) level access from C in a very straightforward manner (like just reading / writing bits directly, or at least ports directly like a microcontroller), but apparently it is intended more for someone familiar with LabView.
 
 
Message 15 of 18
(3,795 Views)

Hello Sileas,

I'm sorry you have been having problems setting up your application.  Unfortunately I need to clarify something from my last post.  Although you can create a channel for Dev1/port1/line0:3 for the 6008/9 and 6501 you need to use port operations in DAQmx Base.  Therefore when you create a channel for dev1/port1 you send an 8bit (or 32) value to the device.  Each of the least significant 8 bits corresponds to one line.  Therefore to send a value to port1/line0 you would send a 0 or 1.  To send a value to port1/line3 you would send 0 or 4.  To set port1/line0, port1/line1, and port1/line2 all to high you would send 7 to the channel. 

So the easiest way to control two output ports and one input port is to create three tasks. 

For example if you had the following code:

uInt32      w_data [1];
int32       written;

w_data[0] = 0x07;

DAQmxErrChk (DAQmxBaseCreateTask ("", &taskHandle));
DAQmxErrChk (DAQmxBaseCreateDOChan(taskHandle,"Dev1/port1","",DAQmx_Val_ChanForAllLines));
DAQmxErrChk (DAQmxBaseWriteDigitalU32(taskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,w_data,&written,NULL));

You would write to update all 8 lines of port1.  Lines 0, 1 and 2 would be high and the rest would be low.  Unfortunately, since you are limited to port operations when you update port0/line0 you could change port0/line1.  To get around this you will want to keep the last value you wrote in memory and only change the bit you need to update on the device. 

However if you create two tasks for your digital output, when you update task 1 it will not change the digital lines associated with task 2.

With regards to your sample pre channel question, the samples per channel you will specify a value of 1.  The value you write will stay on the port until you update the port. 

The same logic applies for digital input, where each line corresponds to a single bit in the returned number.

I again apologize for any confusion you have.  The documentation available is the function reference you have already seen, shipping examples, discussion forums, and possibly more online examples (found here).  If I did not answer your questions completely please let me know.  I will try to answer you the best I can.

Regards,

Jesse O.
Applications Engineering
National Instruments

Jesse O. | National Instruments R&D
0 Kudos
Message 16 of 18
(3,764 Views)

Thanks for the additional help.  I finally gave up this weekend and just created a task per line, 16 Out and 8 In.  That seems to work, except I am having issues through NIDAQmxBase 1.5 C API configuring pins to Push-Pull (but that is on a different thread right now http://forums.ni.com/ni/board/message?board.id=70&message.id=5339)

Thanks.

 

0 Kudos
Message 17 of 18
(3,748 Views)

Hi,

I'm starting writing code (in C) for the NI USB-6501 and it seems like I'm facing the same issue where writing to lines on one port will affect lines on another port.  I'm probably doing something wrong...

 

For example, what I am trying to acheive is simple: I want to either set the 0 first bits of port0 or the 3 first bits of port1.  So for example, at one point my code will set the port0 lines to 00000010, then a bit later set the port1 lines to 00000001 (but I want to keep port0 as-is).

 

So when I write the 3 first bits of port 0, all good, the bits are set correctly.

 

But then when I write the 3 first bits of port 1, the 3 first bits of port 1 are set correctly ** but the 3 first bits of port 0 are also affected and they all change to 1's?! **

 

Is this normal?

 

My code looks like this:

 

void set_start(uInt8 bits)
{
// Task parameters
int32 error = 0;
TaskHandle taskHandle = 0;
char errBuff[2048];

// Channel parameters
char chan[64];

// Write parameters
uInt8 w_data [1];
int32 written;


sprintf(chan, "Dev1/port%i/line0:3", 0);
printf("Channel: %s\n", chan);

// Create Digital Output (DO) Task and Channel
error = DAQmxBaseCreateTask ("", &taskHandle);
handle_DAQ_error(error, taskHandle);
printf("TaskHandle: %i\n", taskHandle);

error = DAQmxBaseCreateDOChan(taskHandle,chan,"",DAQmx_Val_ChanForAllLines);
handle_DAQ_error(error, taskHandle);

error = DAQmxBaseStartTask (taskHandle);
handle_DAQ_error(error, taskHandle);


w_data[0] = bits;

error = DAQmxBaseWriteDigitalU8(taskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,w_data,&written,NULL);
handle_DAQ_error(error, taskHandle);


if (taskHandle != 0)
{
DAQmxBaseStopTask (taskHandle);
DAQmxBaseClearTask (taskHandle);
}

return;
}

 

void set_stop(uInt8 bits)
{
// Task parameters
int32 error = 0;
TaskHandle taskHandle = 0;
char errBuff[2048];

// Channel parameters
char chan[64];

// Write parameters
uInt8 w_data [1];
int32 written;


sprintf(chan, "Dev1/port%i/line0:3", 1);
printf("Channel: %s\n", chan);


// Create Digital Output (DO) Task and Channel
error = DAQmxBaseCreateTask ("", &taskHandle);
handle_DAQ_error(error, taskHandle);
printf("TaskHandle: %i\n", taskHandle);

error = DAQmxBaseCreateDOChan(taskHandle,chan,"",DAQmx_Val_ChanForAllLines);
handle_DAQ_error(error, taskHandle);

error = DAQmxBaseStartTask (taskHandle);
handle_DAQ_error(error, taskHandle);

w_data[0] = bits;

error = DAQmxBaseWriteDigitalU8(taskHandle,1,1,10.0,DAQmx_Val_GroupByChannel,w_data,&written,NULL);
handle_DAQ_error(error, taskHandle);

if (taskHandle != 0)
{
DAQmxBaseStopTask (taskHandle);
DAQmxBaseClearTask (taskHandle);
}

return;
}

 

0 Kudos
Message 18 of 18
(1,639 Views)