Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

DAQmxCfgSampClkTiming NICARD 6031 E PCI and Visual C++ 6.0

Solved!
Go to solution
To the attention of the support department or someone else wellcome! -):

I am using an NICARD 6031 E PCI. I am also using Visual C++ 6.0.

I declared a variable for an external ANALOG SAMPLE CLOCK. I am supplying
this CLOCK signal to the input PIN /Dev1/PFI7

//, m_sSampClk(_T("ai/SampleClock"))

I am not using this variable now and this is why is commented. Instead, I
just call /Dev1/PFI7 below in the routine.

I am using the following routine to SAMPLE input values based on the
external CLOCK signal entering the /Dev1/PFI7 PIN

nErrorCode = DAQmxCfgSampClkTiming (m_hAnalogTask, //task handle
"/Dev1/PFI7", //Sample Clock from ATMEGA88 (AI SAMP CLK)
50000, //Sampling rate (float64) points per second
DAQmx_Val_Rising, //Acquire samples on rising edges of the
Sample Clock.
DAQmx_Val_FiniteSamps, //Finite mode for buffered hardware
timing acquisition
128); //128 samples per channel


if(nErrorCode!=0) //error encountered
{
DAQmxGetErrorString(nErrorCode, szErrorMsg, 1024);
AfxMessageBox(szErrorMsg);
}

Can you please let me know if my routine is correct and I do not need to
declare a variable for the SAMPLE CLOCK because I call it on the routine
directly? I searched examples on your website but I only find LABVIEW and
not Visual C++ examples.

Regards,

Javier Contreras.
0 Kudos
Message 1 of 32
(8,336 Views)

Hi Javier,

 

The source parameter on DAQmxCfgSampClkTiming() is declared as const char source[], so passing a string literal is fine. The DAQmx ANSI C shipping example Acq-ExtClk.c does the same thing.

 

Here's a knowledgebase that explains where to find the DAQmx ANSI C shipping examples: Location of ANSI C NI-DAQmx Shipping Examples and DAQmx Library File for Windows

 

I noticed that your code uses TCHAR. If you compile with _UNICODE defined, passing TCHAR-based strings to/from DAQmx will require conversion.

 

Brad

---
Brad Keryan
NI R&D
0 Kudos
Message 2 of 32
(8,305 Views)

Hi Brad,

 

Thanks for your help. I place a few comments below yours:

 

The source parameter on DAQmxCfgSampClkTiming() is declared as const char source[], so passing a string literal is fine. The DAQmx ANSI C shipping example Acq-ExtClk.c does the same thing.

 

Here's a knowledgebase that explains where to find the DAQmx ANSI C shipping examples: Location of ANSI C NI-DAQmx Shipping Examples and DAQmx Library File for Windows

 

OK. I will have a look at these examples.

 

 

I noticed that your code uses TCHAR. If you compile with _UNICODE defined, passing TCHAR-based strings to/from DAQmx will require conversion.

 

 

I am not an expert in programming so I do not understand properly what you mean about TCHAR and _UNICODE

Can you explain in a BASIC manner so that I can understand? 

It is important to know what you mean because if I need some kind of conversion in my routine, then this is probably why I am not getting the right data in my user interface when I input data from a sensor.

 

I am trying to acquire data in the following manner with DAQmxCfgSampClkTiming:

 

- External CLOCK signal entering the /Dev1/PFI7 pin

 

I provide an external CLOCK with 129 CLOCKS or RISE times or highs/low. The gap between the first clock and the second clock is for example 70us but after one instant of time it changes to 50us and then back to 70us. This should not affect the NICARD Sample Clock timing acquisition of values, should it?   

 

The data acquisition should work in the following way in the NICARD: Everytime the NICARD see a RISE time from my external clock then it should acquire a value.

 

Since I have 129 CLOCKs then it shoudl acquire 129 values.

 

However, I am only interested in 128 values because my last 129th clock is used only to reset some other component I have in my circuit.

 

So this is why I defined the BUFFER of the sample clock acquisition to 128 values (see below)

 

nErrorCode = DAQmxCfgSampClkTiming (m_hAnalogTask, //task handle
"/Dev1/PFI7", //Sample Clock from ATMEGA88 (AI SAMP CLK)
50000, //Sampling rate (float64) points per second
DAQmx_Val_Rising, //Acquire samples on rising edges of the
Sample Clock.
DAQmx_Val_FiniteSamps, //Finite mode for buffered hardware
timing acquisition
128); //128 samples per channel

 

Therefore I should get a value on every rise time for the 128 CLOCK rise times ignoring the 129th CLOCK rise time

 

And since I have a finite mode for buffered hardware, then the routine DAQmxCfgSampClkTiming should be placing those 128 values in a BUFFER for me to access later.

 

So do you have an idea if I am doing things properly. I seem to get wrong data on my user interface after acquring the buffer of 128 values. Do you want to check my CODE just for my NIDAQmx cpp file?

 

Thanks a lot.

 

Javier.

 

0 Kudos
Message 3 of 32
(8,292 Views)

Hi Javier,

 

Here is an article on MSDN explaining what TCHAR is for and how to use it: Generic-Text Mappings in TCHAR.H. The functions in NIDAQmx.h use "char", not "TCHAR", so passing TCHAR strings like _T("ai/SampleClock") to DAQmx may or may not compile depending on your project settings. If you don't need to compile your program for ANSI, multi-byte, and Unicode using the same source, it may be easier to just use char or wchar_t, whichever is appropriate.

 

Having a variable clock rate like you described should work, because using an external sample clock with a variable rate is supported by E Series devices. When calling DAQmxCfgSampClkTiming(), you must specify a sample clock rate that is equal or higher than the external sample clock's maximum expected rate. If the expected clock period ranges from 50 us to 70 us, then the maximum expected rate is 1 / 50 us = 20000 Hz, so specifying 50000 should be fine.

 

Programming the E Series device to acquire less samples than the number of sample clocks you are sending it is also fine. It will ignore the additional clock pulses.

 

I don't know what's causing you to get wrong data on your user interface. I recommend using the debugger or adding calls to OutputDebugString() or printf() to determine whether the problem is related to DAQmx programming or UI programming. If it's related to DAQmx programming, then please describe what results you're getting and how they differ from what you're expecting, in addition to posting your code.

 

Brad

---
Brad Keryan
NI R&D
0 Kudos
Message 4 of 32
(8,275 Views)

 

Hi Brad,

 

Thanks a lot for your help! Let me answer by placing comments below yours in your last email:

 

 

"Hi Javier,

 

Here is an article on MSDN explaining what TCHAR is for and how to use it: Generic-Text Mappings in TCHAR.H. The functions in NIDAQmx.h use "char", not "TCHAR", so passing TCHAR strings like _T("ai/SampleClock") to DAQmx may or may not compile depending on your project settings. If you don't need to compile your program for ANSI, multi-byte, and Unicode using the same source, it may be easier to just use char or wchar_t, whichever is appropriate."

 

I went over that article but I do not understand many things. I do understand that I should change the names to char type. May be you can help me on that when you look at the code I attach in this POST. I will look again at the name types. I do not appear to have any problems when I compile the code. Have a look at the code if you want and try to compile it using Visual C++ 6.0 and perhaps using a virtual (through measurement and automation explorer?) 6031 E PCI NIcardwith DAQmx drivers installed?

 

"Having a variable clock rate like you described should work, because using an external sample clock with a variable rate is supported by E Series devices. When calling DAQmxCfgSampClkTiming(), you must specify a sample clock rate that is equal or higher than the external sample clock's maximum expected rate. If the expected clock period ranges from 50 us to 70 us, then the maximum expected rate is 1 / 50 us = 20000 Hz, so specifying 50000 should be fine."

 

Ok thanks. I am glad I am doing something properly! -)

 

 

"Programming the E Series device to acquire less samples than the number of sample clocks you are sending it is also fine. It will ignore the additional clock pulses."

 

Great. Looking good then.

 

"I don't know what's causing you to get wrong data on your user interface. I recommend using the debugger or adding calls to OutputDebugString() or printf() to determine whether the problem is related to DAQmx programming or UI programming."

 

Well I believe it is wrong data but I might be wrong and it might be OK. I still need to make a change on the WAVEFORM I generate to see if the data changes. I am not sure yet which data is right or wrong so I am confused. But I know that when I plugin a position sensitive detector the data did not change when it should have done so it could be an electronics issue of course.What I wanted is to at least make sure that it was not a NIDAQmx programming problem or User Interface problem.

I cannot remember how to use the debugger properly (sorry about that) and I do not know how to add calls to OutputDebugString() or printf(). May be you can tell me how to do it? Or you can try to have a look at the code too?

 

 

"If it's related to DAQmx programming, then please describe what results you're getting and how they differ from what you're expecting, in addition to posting your code"

 
I can make PRINTSCREENS of what I get on my screen (user interface) when I am acquiring the BUFFER and values and send it through if you want. I should be getting values from 0 to about 1.8 volts. At the moment I see values near 0 and so they could be ok but they should be varying when I input a current of the order of nanoAmps.
I am POSTING the code here and let us try to go step by step slowly to clear ideas.
 
Thanks very much.
 
Javier.
 
 
 

 

Message Edited by Support on 02-01-2010 08:44 AM
0 Kudos
Message 5 of 32
(8,240 Views)

Hi Javier,

 

To debug a system with multiple possible points of failure, it really helps to break it down into smaller, easily verifiable pieces.

 

For example:

  1. Connect a known good signal. If you don't know if your position detector works correctly, then connect something else in its place for now, like a battery or a function generator. Once you have verified that you can correctly measure a battery or a signal from a function generator, then connect your position detector and figure out how to get results that you expect from it.
  2. Verify that the signal is connected correctly using the device test panels in MAX. (Or the DAQ Assistant in MAX, which allows external clocks and other settings that the device test panel does not. To get there, right-click "Data Neighborhood", select "Create New...", select "DAQmx Task", etc.)
  3. Write your DAQmx code separately from your UI code. Acquire the data and display it in a simple, easily verifiable manner (hence OutputDebugString or printf or the debugger). Make sure you get the results you expect.
  4. Write your UI code separately from your DAQmx code. Feed it fake data and make sure it gets displayed correctly.
  5. Once all of the pieces work in isolation, put them together and see if they work together.

Looking at your NIWrapper.cpp, here are some specific things you should check:

  • You are setting the min/max expected values to -2 and 0. Are those correct? If you always read -2 or you always read 0, then you should try a wider range, like -10 and 10. If you're expecting 0-1.8 V, then 0 to 2 would be better.
  • You are setting the terminal configuration to DAQmx_Val_Diff. Make sure you have your signals connected to ACH0/ACH8 and ACH1/ACH9 and that the signals are within +/-10 V of AIGND.
  • DAQmx ignores external sample clocks that happen before the task is started. If you need to send a serial command to start your external device (I don't know, I didn't read your whole program), it would be better to start the DAQmx task, send the serial command, and then read from the DAQmx task, so that you don't miss any external sample clocks.
  • You're passing -1 as the timeout for DAQmxWaitUntilTaskDone(). This will cause DAQmx to wait forever if you don't get enough external sample clocks, hanging your program.

 

Brad

---
Brad Keryan
NI R&D
0 Kudos
Message 6 of 32
(8,214 Views)

Hi Brad

First of all , thanks very much for your help, it is very much appreciatedI reply below your comments for clarity.

 

Hi Javier,

To debug a system with multiple possible points of failure, it really helps to break it down into smaller, easily verifiable pieces.

For example:

Connect a known good signal. If you don't know if your position detector works correctly, then connect something else in its place for now, like a battery or a function generator. Once you have verified that you can correctly measure a battery or a signal from a function generator, then connect your position detector and figure out how to get results that you expect from it

 

Ok. I could connect a power supply with a resistance and then I would be injecting a current to the system. In that way I would see on the screen the expected current I am injecting. 

 

Verify that the signal is connected correctly using the device test panels in MAX. (Or the DAQ Assistant in MAX, which allows external clocks and other settings that the device test panel does not. To get there, right-click "Data Neighborhood", select "Create New...", select "DAQmx Task", etc.)

 

Thanks. I already checked whether the connections are properly done in Measurement and Automation Explorer. Never used the DAQ Assistant in Measurement and Automation Explorer but I will try it too. However the connections are correct. Differential with CH0 (PINs 3 and 4 on the 100 pin connector) and CH1 ((PINs 5 and 6 on the 100 pin connector), which is the declared in my code as m_sChannels(_T("Dev1/ai0,Dev1/ai1")). I need differential.

 

Write your DAQmx code separately from your UI code. Acquire the data and display it in a simple, easily verifiable manner (hence OutputDebugString or printf or the debugger). Make sure you get the results you expect.

 

In the past and now I am using the same UI code to display properly other values from very similar circuits and other circuits, so I believe my UI is working properly for sure.

 

Write your UI code separately from your DAQmx code. Feed it fake data and make sure it gets displayed correctly.

 

Again, I am using exactly the same base UI code for other setups and it works fine. 


  1. Once all of the pieces work in isolation, put them together and see if they work together.

 

I am pretty sure that my UI code works perfectly from other setups.


Looking at your NIWrapper.cpp, here are some specific things you should check:

  • You are setting the min/max expected values to -2 and 0. Are those correct? If you always read -2 or you always read 0, then you should try a wider range, like -10 and 10. If you're expecting 0-1.8 V, then 0 to 2 would be better.

 

Yes, may be I should change it to 0 to 2. However, to be on the safe side just in case my signal polarity is changed, can I use -2 to 2?

 

You are setting the terminal configuration to DAQmx_Val_Diff. Make sure you have your signals connected to ACH0/ACH8 and ACH1/ACH9 and that the signals are within +/-10 V of AIGND.

 

s(Yes the signals are connected properly as I checked in Measurement and Automation Explorer. I declared them as m_sChannels(_T("Dev1/ai0,Dev1/ai1")). Signals within +-10V of AIGND. AIGND is connected to the GND of my circuit as it should. What happened to the UNICODE, etc conversion ISSUE we talked last time? Do I need conversion, etc as you said? I do not have a clue on this conversion issue even after reading your link! -) 

 

DAQmx ignores external sample clocks that happen before the task is started. If you need to send a serial command to start your external device (I don't know, I didn't read your whole program), it would be better to start the DAQmx task, send the serial command, and then read from the DAQmx task, so that you don't miss any external sample clocks.

 

Yes, this is another issue I was working on. I was trying to send a char, 'r' over the RS232 to synchronise as I did in another code in the past which worked fine.

 

However, I did not seem to make the MAX232 component do what I wanted. I am using the MAX232a from MAXIM and I attach the datasheet in this email. From my UI code, I first send a char 'r' to an ATMEGA128 microcontroller, and if the ATMEGA128 sees the char 'r' then it starts the sending of data from another component and sends the external CLOCK to the NICARD AIsample pin.

 

However, the char 'r' from my UI code did not seem to arrive to the ATMEGA128 since it did not start the data acquisition or the clock. I already used this char 'r' approach in the past with the ATMEGA128 too and it worked fine with another type of SMD MAX232. Would it be fine if I measured the voltage values of the MAX232 pins while transmitting the char and then LET you know these values for you to check if the MAX232 works fine?

 

I also tried another approach to synchronise which is to set from the UI code one pin from the NICARD to HIGH, and then ATMEGA checks if this pin was HIGH and if it was then it transmitted. However, this PIN seemed to stay HIGH and the approach did not work. Of course I would like to synchronise but I have not managed, so I have the ATMEGA128 code sending inside a FOR loop on every iteration.

 

And the NICARD of course will be receiving sets of 129 CLOCKs on every iteration but spaced with a GAP of 10ms. I wish I could synchronise but it is not working. Can you check the values of the voltages of the MAX232a if I send you the values myself while it is transmitting char 'r'? Just for you to check of course.

 

 

  • You're passing -1 as the timeout for DAQmxWaitUntilTaskDone(). This will cause DAQmx to wait forever if you don't get enough external sample clocks, hanging your program.

 

Yes, I am passing -1. But I am providing enough CLOCK samples (129). I have the CLOCK waveform on a photo I made of the oscilloscope. This hanging of the program was the case, when the ATMEGA128 did not send anything because the PIN remained in the one state HIGH or LOW without changing everytime as it should, in order to inform the ATMEGA128 that it could send data.

 

I attach the MAX232 component datasheet.

 

Thanks and best regards.

 

Javier.

0 Kudos
Message 7 of 32
(8,183 Views)

Hi Javier,

 

Your analog connections sound like they are correct. Presumably you also have PFI7 (pin 46) connected to the appropriate pin on your microcontroller. Did you also connect the PCI-6031E's DGND pin appropriately? AIGND and DGND are tied together, but it's better to connect the appropriate grounds to reduce noise.

 

One way to verify the clock connection is to use one of the PCI-6031E's counter/timers to count the number of pulses. You can do this by opening the test panel in MAX, selecting the "Counter I/O" tab, setting "Mode" to "Edge Counting", and setting "Edge Source" to "/Dev1/PFI7". The test panel is hardcoded to count rising edges, but that's okay because your program uses DAQmx_Val_Rising.

 

After you verify the edge count, try creating an analog voltage input task in the DAQ Assistant, and use the "Advanced Timing" tab to configure PFI7 as an external sample clock. This will verify that the PCI-6031E analog input is working correctly with the timing provided by the microcontroller.

 

Once you see the data you expect in the DAQ Assistant, do you see the same (expected) data in your application? If so, then it sounds like your DAQmx code is interfacing to your UI code correctly.

 

As for the min/max values, the PCI-6031E doesn't support a -2 V to 0 V range in hardware, so DAQmx coerces the min/max to +/-2 V. The NI-DAQmx Help file (located on the Start Menu under National Instruments >> NI-DAQ) has more info if you search for "input limit coercion".

 

The Unicode conversion issue (actually TCHAR -> char conversion) is only a problem if you change your project settings to use Unicode. If it was, it would cause a compiler error, so don't worry about it. If you have to switch to Unicode later, you can worry about it then.

 

Also, this is the NI DAQ forum (well, counter/timer, actually). If your microcontroller or MAX232 isn't working correctly, figuring out what's wrong with it is outside the scope of this forum, so I can't help you there.

 

Brad

---
Brad Keryan
NI R&D
0 Kudos
Message 8 of 32
(8,164 Views)

Hi BRAD,

 

It is better I write in a different colour to differ our comments. I reply below your comments:

 

Your analog connections sound like they are correct. Presumably you also have PFI7 (pin 46) connected to the appropriate pin on your microcontroller. Did you also connect the PCI-6031E's DGND pin appropriately? AIGND and DGND are tied together, but it's better to connect the appropriate grounds to reduce noise.

 

 

The grounds are connected together. Everything is ok.

 

 

One way to verify the clock connection is to use one of the PCI-6031E's counter/timers to count the number of pulses. You can do this by opening the test panel in MAX, selecting the "Counter I/O" tab, setting "Mode" to "Edge Counting", and setting "Edge Source" to "/Dev1/PFI7". The test panel is hardcoded to count rising edges, but that's okay because your program uses DAQmx_Val_Rising.

 

 

Yes. At the moment I checked my CLOCK using the oscilloscope. Before the first CLOCK rising I do not have any gaps. Then between the first CLOCK high and second clock HIGH it is around 30us and between second and third and third and fourth, etc, it is always around 60us but I can reduce it or increase any of those times as I want.

 

I will try the option of MAX that you told me to have a look too.

 

 

After you verify the edge count, try creating an analog voltage input task in the DAQ Assistant, and use the "Advanced Timing" tab to configure PFI7 as an external sample clock. This will verify that the PCI-6031E analog input is working correctly with the timing provided by the microcontroller.

 

 

I amd not using PFI7 anymore. Now I am sending a CHAR "r" from the PC to my microcontroller and when my microcontroller sees the CHAR "r", then the SENDING of the external sample CLOCK starts and DATA to the NIDAQ starts to be sent.

At the moment I am almost there. I get the typical message to set ADC conversions to the right SAMPLES per second (e.g. 50000). And then I change it but then it tells me to change the sample rate or that the NIDAQ did not have enough time to read all data (128 values) and so I am trying now to solve this problem. I think it is just placing the right sample rate but then may be something else. I am not sure what it could be now. Any thoughts?

 

In my user interface code on the pc i send the char "r" before I call READ from NICARD. AS you said last time I have it waiting FOR EVER any thoughts on this? If I place READ before sending the CHAR it blocks cos no data comes but if I place READ after sending CHAR "r" then it tells me the messages mentioned above. What is that parameter that u say WAITING for ever when READING? What other options are there for that parameter? May be it has to do with that parameter.

 

Thanks very much,
 
Javier.

0 Kudos
Message 9 of 32
(7,829 Views)

Hi Javier,

 

If sending 'r' to the MCU starts the clock, you should call DAQmxStartTask(), then send the 'r', then call DAQmxReadAnalogF64().

 

The DAQmx timeout is controlled by the timeout parameter on DAQmxReadAnalogF64(). Set it to the number of seconds that you expect the read to take. If you set the timeout to -1.0, DAQmx will wait forever, but if you use this functionality, be careful: you cannot cancel the wait without aborting the task or resetting the device.

 

Brad

---
Brad Keryan
NI R&D
0 Kudos
Message 10 of 32
(7,791 Views)