05-07-2013 02:14 PM
I have an application written in C# that uses imported functions from legacy nidaq32.dll to read/write an I2C interface. I've been tasked to rehost the application on a Windows 7 machine and use the C# API of NI-DAQmx. This is my first experience with DIO harware and NI-DAQ, so any assistance understanding what the current software is doing and how to convert that to DAQmx calls would be very helpful.
Here are the nidaq32.dll calls being used by the legacy software to set up the DIO-32HS hardware:
private void ConfigDaqDevice()
{
short boardtype = 211;
short status;
short DaqDev = 1;
Init_DA_Brds(DaqDev, ref boardtype);
/*_______________Config Input____________________________*/
status = Set_DAQ_Device_Info(DaqDev, ND_CLOCK_REVERSE_MODE_GR2, ND_ON);
/* Configure group of ports as input, with handshaking. */
status = DIG_Grp_Config(DaqDev, InGrp, 2, PortC, Input);
/*Configure REQ line polarity for falling edge on input */
status = DIG_Grp_Mode(DaqDev, InGrp, 1, 1, 1, 0, 2);
/* Configure internally timed pattern generation using external clock,
and no external gating. */
status = DIG_Block_PG_Config(DaqDev, InGrp, 1, 1, -3, 2, 0);
status = Align_DMA_Buffer(DaqDev, 12, ReadBuf, In_Buf_Size / 2, In_Buf_Size, ref ulAlignIndex);
/* Turn ON software double-buffered mode, with half-buffer
overwrite protection (iOldDataStop). */
status = DIG_DB_Config(DaqDev, InGrp, 1, 1, 1);
/*___________________Config Output________________________*/
Set_DAQ_Device_Info(DaqDev, ND_CLOCK_REVERSE_MODE_GR1, ND_ON);
/* Configure port size and direction */
status = DIG_Grp_Config(DaqDev, OutGrp, 2, PortA, Output);
/* Configure internally timed pattern generation with timebase 0,
interval 2, and no external gating.
IMPORTANT: If the number sample (currently 2 is changed, then
the output frequency will changed and all timing will
not be correct. */
status = DIG_Block_PG_Config(DaqDev, OutGrp, 2, 0, -3, 2, 0);
status = Align_DMA_Buffer(DaqDev, 11, WriteBuf, Out_Buf_Size / 2, Out_Buf_Size, ref ulAlignIndex);
}
Ports A and B are configured as outputs, and C and D are inputs.
The pin assigments are as follows. Anything not listed can be considered N/C:
Output Port
DIO A2 --> DIO D1. The legacy software uses the output port to drive the RX clock for the input port.
DIO A3 --> unit under test. I2C data line direction bit
DIO A4 <--> DIO C0 <--> unit under test. I2C serial data line output to UUT.
DIO A5 --> unit under test - I2C TX/RX clock for uut
Input Port
DIO C0 <--> DIO A4 <--> unit under test. I2C serial data line. Reads reply data from unit under test
DIO D1 <-- DIO A2. RX clock from output port.
The basic theory of operation appears to be that A3 stays high while A4 and A5 clock data to the I2C device. When the device is expected to assert the data line, A3 goes low, A4 is held high, A5 clock the data back from the I2C device, and A2 clocks that data into the Input Port (C+D).
The method (not shown) that sends and receives data make a (I'm assuming asynchronous) call to DIG_Block_In() followed by DIG_Block_Out() and then loops until DIG_Block_Check indicates that whole data buffer has been written.
I have the basic data patterns figured out, but I'm not sure how to proceed with implementation in NI-DAQmx.
05-08-2013 05:21 PM
Hi Spiehler,
You may find it useful to search each of the functions in the program that you inherited and see if you can figure out what their function is. I have included some information on the first function in your program, Init_DA_Brds. I have also included some broader text based DAQ links as well to give you some more information. Hopefully this helps and can get you started!
http://digital.ni.com/public.nsf/allkb/11FD10E72E3D0D9786256F280078789B - Is There a DAQmx Equivalent for the Device Number Code from Init_DA_Brds Traditional DAQ Function in LabWindows/CVI?
http://digital.ni.com/public.nsf/websearch/F0FD13D2DD0C433986256D9C00468D29?OpenDocument - Programming NI-DAQ in Visual C# .NET
http://www.ni.com/white-paper/6999/en#.NETAI - Text Based NI-DAQmx Data Acquisition Examples
Regards,
06-22-2013 03:18 PM
This is my first cut at trying to re-create the funcationality from the legacy software. At this point I'm just trying to do a loopback test to make sure that my clock signal on my output task is used as the input clock on my input task.
I'm cycling port0/line2 with the sequence 0,1,1,0 to simulate a clock and port0/line4 is my data out line. In the example below I'm trying to clock out 0xFFFF through port0/line4 and read it back through port2_16.
ushort[] rxData;
byte[64] outputBuffer = /* {0x10,0x14,0x14,0x10} repeated 16 times */
Task txTask = new Task();
Task rxTask = new Task();
try
{
// port0/line2 (clock out) is physically tied to port3/line1 (clock in)
// port0/line4 (data out) is physically tied to port2/line0 (data in)
// RX task setup
rxTask.DIChannels.CreateChannel("DEV1/port2_16", "RxChannel",
ChannelLineGrouping.OneChannelForAllLines);
// I only want one sample per clock, on the rising edge, but I get a
// an exception if I don't set the rising and falling edge channels to
// be the same. I can live with two samples per clock and just use even
// or odd indexes.
rxTask.Timing.ConfigureChangeDetection("DEV1/port3/line1",
"DEV1/port3/line1", SampleQuantityMode.ContinuousSamples,
samplesPerChannel: 1000);
rxTask.Control(TaskAction.Verify);
DigitalSingleChannelReader rxReader =
new DigitalSingleChannelReader(rxTask.Stream);
rxReader.SynchronizeCallbacks = true;
IAsyncResult result = rxReader.BeginReadMultiSamplePortUInt16(-1, null, null);
// TX task setup
txTask.DOChannels.CreateChannel("DEV1/port0/line0:7", "TxChannel",
ChannelLineGrouping.OneChannelForAllLines);
txTask.Timing.ConfigureHandshaking(SampleQuantityMode.FiniteSamples,
outputBuffer.Count());
txTask.Timing.ConfigureSampleClock("", sendClock,
SampleClockActiveEdge.Rising,
SampleQuantityMode.FiniteSamples, outputBuffer.Count());
txTask.Control(TaskAction.Verify);
DigitalSingleChannelWriter txWriter =
new DigitalSingleChannelWriter(txTask.Stream);
// perform a synchronous write
txWriter.WriteMultiSamplePort(autoStart: true, data: outputBuffer);
txTask.WaitUntilDone(millisecToWait: 5000);
// Read RX data after tx task is completed
rxData = rxReader.EndReadMultiSamplePortUInt16(result);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
txTask.Dispose();
rxTask.Dispose();
}
Unfortunately rxData ends up being a zero-length array instead of the 16 or 32 element array I was expecting. I don't have a logic analyzer on-hand to see what's actually coming out of the DIO card.
06-24-2013 11:46 AM
Oscilloscope confirms that I'm getting tx clock and data sent out of DEV1/port0. Haven't been able to probe to verify rx clock on port0/line2, but I'm fairly confident that it's changing along with tx clock.
As a test I changed my rxtask to be port2 only and set the change detection to port2/line0 which is tied to my data out line (port0/line4), but still only got an empty array back from EndReadMultiSamplePortUInt16(). Can someone knowledgable please shed some light on why my rxtask isn't working?
Thanks.