Digital I/O

cancel
Showing results for 
Search instead for 
Did you mean: 

6556 - Hardware Compare (HWC) in C#

Howdy,

 

I'm trying to implement hardware compare in C# and I can't seem to figure out the way to do it.

 

In this link: http://zone.ni.com/reference/en-XX/help/370520K-01/hsdio/hwc_in_hw/ it says to use "Hardware Compare Mode" property or the "NIHSDIO_ATTR_HWC_HARDWARE_COMPARE_MODE" attribute.  However, there isn't a method to set the property and there isn't a SetAttribute* method available in the C# wrapper to set an actual attribute.  Are these approaches the only way to enable HWC?

 

(I should note the version of the manual I have on my computer says "Supported Data States" property and "NIHSDIO_ATTR_SUPPORTED_DATA_STATES" attribute, but the method to set that property doesn't exist either...and the there still isn't a SetAttribute method. 🙂 )

 

When looking inside of the niHSDIO.dll one can see that niHSDIO_SetAttributeViBoolean, niHSDIO_SetAttributeViInt32, niHSDIO_SetAttributeViReal64, niHSDIO_SetAttributeViSession, and niHSDIO_SetAttributeViString exists.  Has anybody had any success breaking these out into the wrapper?  Or using the niHSDIO.dll file without the wrapper?

 

Any guidance would certainly be appreciated.

 

Thanks,

Harold

0 Kudos
Message 1 of 19
(6,787 Views)

Have you tried using HWC_FetchSampleErrors that is in the file attached to this KB? 

http://digital.ni.com/public.nsf/allkb/F8A3A2E8A356B0C686257A5A006BD845

 

Will that function satisfy what you are trying to do? Are you using this wrapper or are you using another wrapper? 

Noah | Applications Engineer | National Instruments
0 Kudos
Message 2 of 19
(6,754 Views)

Hey Noah,

 

Thanks for replying to my message.

 

I haven't been able to implement HWC using C# as of yet.  From what I can tell, HWC_FetchSampleErrors is used to retrieve data from a HWC measurement, which I haven't done yet.

 

To generalize my question, if you were to implement HWC using C#, what is the series of commands you would use?

 

Also, I'm using the wrapper you linked to.  I've also tried version 2.0 as well.

 

Thanks for you help on this.

 

Harold

0 Kudos
Message 3 of 19
(6,735 Views)

Hi Noah,

 

Another thread cleared up the SetAttribute issue I mentioned in my previous post.

 

I'll get it a shot and see what I get.

 

Thanks,

Harold

0 Kudos
Message 4 of 19
(6,712 Views)

Hi Harold,

 

There is a bit of confusion here, even as I was looking into it, so I wanted to drop in and explain things a little better.

 

That attribute is not in the C# wrapper because it no longer exists inthe C DLL for our niHSDIO driver API. We obsoleted the function in favor of a secondary naming: NIHSDIO_ATTR_SUPPORTED_DATA_STATES. You correctly identified that is what you found as well. If you use NIHSDIO_ATTR_SUPPORTED_DATA_STATES, you should be able to set up your HWC mode correctly. I apologize for the confusion, and I'll report the issues internally here so we can sort this out for future use.

 

I also see your other post resolved the issue with not finding the attributes. Glad to see that they have been located!

Kyle A.
National Instruments
Senior Applications Engineer
0 Kudos
Message 5 of 19
(6,708 Views)

Hi Kyle,

 

I've tried to implement HWC, but I'm running into an issue I can't seem to get around.  A phone call to tech support might allow an easier explanation, but I thought I would post anyway.

 

I'm fairly sure my code (posted below) is correct because I'm basing it off of the C based examples provided with the niHSDIO install.

 

  • What characters should the digital word to generate and acquire use?  From what I read, I was under the impression the generate characters could be 0,1,Z and the acquire characters could be L,H,X.  However, since the WriteNamedWaveformWDT() method requires the digital word to be passed in as a type byte array, there isn't a byte value that can represent any of the non-numeric characters.  I was getting errors when trying to load other byte values into the card's memory when the values were something different than 0 and 1.  So I swept the potential value range from 0 through 255 and found out the card can take values of 0, 1, 2, 3, 4, and 5.  So it can take six different values.  Do those line up w/ 0, 1, Z, L, H, and X?  I tried a small truth table using different combinations of 0,1,2 for the generate data and 3,4,5 for the acquire data, but couldn't get the results I expected.
  • Also, I found that if my data to be generated is over three bits long and my expected acquired data matches the generated data length, then the C# wrapper throws an error when trying to load the data using the WriteNamedWaveformWDT() method.  Very strange.
  • Am I right concatenating the generate and acquire data and loading into the card memory w/ WriteNamedWaveformWDT()?  Am I also right setting the channelList for the generate session to include both the generate and acquire pins?


Also, I've been able to successfully generate and acquire data of arbitrary long patterns when HWC is turned off.

 

Thanks,
Harold

 

 

            niHSDIO pxiBoxGenerate;
            niHSDIO pxiBoxAcquire;

            //Resource name set in NI Max
            string resourceName = "Dev2";
            //Channel list for generating digital patterns
            string channelListGenerate = "0";
            //Channel list for acquiring digital patterns
            string channelListAcquire = "15";
            //Sample clock rate in Hz
            double sampleClockRate = 100000;

            //Digital word to generate
            string digitalWordGenerateString = "110";
            //Digital word to acquire
            string digitalWordAcquireString = "334";
            //string digitalWordAcquireString = "HHHHLLLL";

            //Digital word to generate and expected word to acquire concatenated
            //Word to generate: 11110000111000110010
            //Word to acquire: 11110000111000110010
            //Is this correct?  Are they supposed to be concatenated together?
            string digitalWordString = digitalWordGenerateString + digitalWordAcquireString;

            //Converts digitalWordString (in type string) to type byte to meets the argument requirements
            //of the WriteNamedWaveformWDT method.
            byte[] digitalWordByte = digitalWordString.Select(n => Convert.ToByte(char.GetNumericValue(n))).ToArray();
            
            //Creating a generation session
            pxiBoxGenerate = niHSDIO.InitGenerationSession(resourceName, true, true, "");
            //Creating an acquisition session
            pxiBoxAcquire = niHSDIO.InitAcquisitionSession(resourceName, true, true, "");

            //Assigning dynamic channels to the generation session.  Assigning both channel lists;
            //the generation channel list and the acquisition channel list.  This is required in order
            //load the expected acquisition data pattern into the hardware compare session.  Is
            //this correct?
            pxiBoxGenerate.AssignDynamicChannels(channelListGenerate + "," + channelListAcquire);
            //Assigning dynamic channels to the acquisition session.  Only assigning acquisition
            //channel list.
            pxiBoxAcquire.AssignDynamicChannels(channelListAcquire);

            //Configuring sample clock of the system.  Using on board clock.
            pxiBoxGenerate.ConfigureSampleClock(niHSDIOConstants.OnBoardClockStr, sampleClockRate);
            //Configures system to take a loaded waveform as opposed to a scripted waveform.
            pxiBoxGenerate.ConfigureGenerationMode(niHSDIOConstants.Waveform);
            //Configures system to generate a single pattern.
            pxiBoxGenerate.ConfigureGenerationRepeat(niHSDIOConstants.Finite, 1);
            //Configures system to trigger off of a software trigger.
            pxiBoxGenerate.ConfigureSoftwareStartTrigger();
            //Exporting the sample clock to the DDC CLK OUT pin on the VHDCI connector.  This pin is shorted
            //to the STROBE pin on the VHDCI connector.  This is required to synchronize the clock signal
            //between the generation and acquisition sessions.
            pxiBoxGenerate.ExportSignal(niHSDIOConstants.SampleClock, "", niHSDIOConstants.DdcClkOutStr);
            //Exporting the Data Active event to the PFI1 pin on the VHDCI connector.  This pin is shorted
            //to the PFI2 pin on the VHDCI connector.  This is required to synchronize the trigger between 
            //the generation and acquisition sessions.
            pxiBoxGenerate.ExportSignal(niHSDIOConstants.DataActiveEvent, "", niHSDIOConstants.Pfi1Str);
            //Enables the system for hardware compare.  The particular constant selected configures hardware 
            //compare to compare generated data against acquried data.  This has to be set on both the generate
            //and acquire sessions.
            pxiBoxGenerate.SetInt32(niHSDIOProperties.SupportedDataStates, niHSDIOConstants.States_0_1_Z_L_H_X);
            //Loads the generation bit pattern and the expected bit pattern into the card's memory.
            pxiBoxGenerate.WriteNamedWaveformWDT("Test", digitalWordByte.Length, niHSDIOConstants.GroupByChannel, digitalWordByte);
            //Configuring the sample clock the acquisition session will use.  The clock signal actually comes
            //from the sample clock of the generation session exported onto the DDC CLK OUT pin.  STROBE is 
            //physically shorted to DDC CLK OUT on the VHDCI connector.
            pxiBoxAcquire.ConfigureSampleClock(niHSDIOConstants.StrobeStr, sampleClockRate);
            //Configuring the trigger the acquisition session will use to signal when to start acquiring data.
            //The trigger signal is actually the exported Data Active event signal on PFI1 pin.  PFI2 is physically
            //connected to PFI1 at the VHDCI connector.
            pxiBoxAcquire.ConfigureDigitalEdgeStartTrigger(niHSDIOConstants.Pfi2Str, niHSDIOConstants.RisingEdge);
            //Enables the system for hardware compare.  The particular constant selected configures hardware 
            //compare to compare generated data against acquried data.  This has to be set on both the generate
            //and acquire sessions.
            pxiBoxAcquire.SetInt32(niHSDIOProperties.SupportedDataStates, niHSDIOConstants.States_0_1_Z_L_H_X);
            //Setting the number of bits the acquisition session should acquire
            pxiBoxAcquire.ConfigureAcquisitionSize(3, 1);

            //Initiating the acquisition session so that it's waiting on the Data Active event trigger.
            pxiBoxAcquire.Initiate();
            //Initiating the generation session so that it's waiting on the software trigger.
            pxiBoxGenerate.Initiate();

            //Executes the software trigger.
            pxiBoxGenerate.SendSoftwareEdgeTrigger(niHSDIOConstants.StartTrigger, "");
            //Holds the program until the acquisition session has completed acquiring.
            pxiBoxAcquire.WaitUntilDone(-1);
            
            int numberOfSampleErrorsRead;
            double[] sampleNumber = {0,0,0};
            uint[] errorBits = {0,0,0};
            uint[] errorRepeatCounts = {0,0,0};
            uint reserved1;
            uint reserved2;

            int error = pxiBoxAcquire.HWC_FetchSampleErrors(3, 0, out numberOfSampleErrorsRead, sampleNumber,
                errorBits, errorRepeatCounts, out reserved1, out reserved2);

            //Deletes loaded waveforms from the IO card's memory.
            pxiBoxGenerate.DeleteNamedWaveform("Test");

 

 

 

0 Kudos
Message 6 of 19
(6,660 Views)

Hi Harold,

 

I do apologize, our C#.NET documentation is not as strong as it could be, so finding this information is probably more difficult than it should be. I'll help you out with your questions and hopefully this can serve as a place for others to receive help programming in C#.NET.

 

  1. We provide a conversion in our niHSDIO.h header file for the C DLL that we are wrapping with the C#.NET wrapper that changes L, H, and X to their proper decimal values:

#define NI_DIO_0 0
#define NI_DIO_1 1
#define NI_DIO_Z 2
#define NI_DIO_L 3
#define NI_DIO_H 4
#define NI_DIO_X 5

 

So you can see that L = 3, H = 4, and X = 5 when putting together HWC data to load. This isn't included in the wrapper, so you would need to either define the constants in the wrapper manually, or use the raw value representing LHX.

 

2.  Can you explain more about this error? What message do you receive? Error code?

3.  Looking at the code you provided:

//Digital word to generate
            string digitalWordGenerateString = "110";
            //Digital word to acquire
            string digitalWordAcquireString = "334";
            //string digitalWordAcquireString = "HHHHLLLL";

            //Digital word to generate and expected word to acquire concatenated
            //Word to generate: 11110000111000110010
            //Word to acquire: 11110000111000110010
            //Is this correct?  Are they supposed to be concatenated together?
            string digitalWordString = digitalWordGenerateString + digitalWordAcquireString;

The way you load data into HSDIO depends on the format you use. For instance, if I wanted to generate 0101 0110 and acquire that same word back, it would look like this for ch 0:

 

generation data: 0101 0110 LHLH LHHL

 

By using LHX states, the driver understands you are loading these values into the hardware compare FIFO onboard and not generating these values. This is only for bidirectional data on one channel. If you were generating on ch 0 and acquiring the response on ch 1, you would not concatenate but load the data in a WDT array where ch 0 would have generation 0101 0110 and ch 1 would have LHLH LHHL.

 

The gen session should include the channels you generate on, as well as the channels you are comparing on. The reason you include the compare channels in the generation session is because you have to download the HWC data to the HWC FIFO, which the only way we can download to memory with the driver is through writenamedwaveform, a generation session method. If you are acquiring data and not using HWC, you do not include those channels in the generation session.

 

Below are more links to help your understanding with using HWC. I would also strongly suggest referencing the help guide for the HSDIO driver, as it has a lot of good information:

 

Advanced Features of High-Speed Digital I/O devices: Hardware Compare

Hardware Compare with Scripting on a National Instruments High-Speed Digital I/O Board

National Instruments High-Speed Digital ATE and Stimulus Response Features

NI Digital Waveform Generator/Analyzer Help - March 2009 edition, online HTML

NI Digital Waveform Generator/Analyzer Help - March 2012 edition, NI-HSDIO 1.9 version, .chm downloa...

High-Speed Digital Real-time Hardware Compare

 

 

Kyle A.
National Instruments
Senior Applications Engineer
0 Kudos
Message 7 of 19
(6,657 Views)

Hi Kyle,

 

Thanks for the explanation and the links you provided.  I've read through quite a few examples, but I think I'm missing some of the finer details.

 

I'll wait to explain the error in item 2 when I've tried everything you've mentioned...it could be due to my misunderstanding.

 

When generating on two separate channels without HWC enabled one still concatenates the two channels' data into a type byte array before passing it in to WriteNamedWaveformWDT(), correct?  It's the number of channels assigned in AssignDynamicChannels() and the pattern length defined in WriteNamedWaveformWDT() that allows the concatenated array to be split up correctly within the card's FIFO, right?  Is this the same process that's taking place when HWC is enabled?

 

For example, in my code listed above, I'm generating on channel 0 and acquiring on channel 15.  If I create a generation pattern of 101 and acquisition pattern of 434, should I used the following pseudo-code?

 

generate.AssignDynamicChannels("0,15");

generate.SetInt32(niHSDIOConstants.States_0_1_Z_L_H_X);

generate.WriteNamedWaveformWDT("waveformName", 3, byChannel, "101434");

 

If not, how would you do it?

 

Thanks for your help,

Harold

 

 

 

 

0 Kudos
Message 8 of 19
(6,638 Views)

Kyle,

 

I think I found the error in my code.  I was putting the total array length into the WriteNamedWavefromWDT() method instead of the length of the data.

 

I believe everything is working correctly the way I have it configured now.

 

I appreciate your help.  🙂

 

Harold

0 Kudos
Message 9 of 19
(6,634 Views)

Can u please show the error message u were getting here as I am also trying to generate LVDS signal but coudnt due to some format error in WriteNamedWavefromWDT(). and u have written that u were  "putting the total array length into the WriteNamedWavefromWDT() method instead of the length of the data" but as in the code above both looks same to me. So can u elaborate it. Please correct me if  I am wrong somewhere. Thanks....

 

 

0 Kudos
Message 10 of 19
(6,465 Views)