08-20-2008 03:27 PM
Hi guys,
I have a problem that, given my limited experience with NI hardware, I think is similar to that of the original poster. Therefore I thought I'd put it here.
I have the same PCI6602 board. I use two of its counters for recording output of an APD photodetector (basically it generates an edge each time a photon hits it). Since the data should be expressed in Counts/sec I need to do my counting in a very well defined timeframe, typically in the 2 ms range.
Looking at some examples in the Daqmx install I came up with the following code (for brevity with only one APD detector implemented);
try
{
NationalInstruments.DAQmx.Task _tskCountTask = new Task();
// The guy actually counting what is coming from the APD
_tskCountTask.CIChannels.CreateCountEdgesChannel("/Dev2/Ctr0", "Count APD0", Rising, 0, Up);
// Define a pause trigger for the APD counter
_tskCountTask.Triggers.PauseTrigger.ConfigureDigitalLevelTrigger("/Dev2/Ctr1InternalOutput", Low);
// This guy will generate an x ms pulse with a certain delay...
NationalInstruments.DAQmx.Task _tskPulseTask = new Task();
_tskPulseTask.COChannels.CreatePulseChannelTicks("/Dev2/Ctr1", "CounterTicks", "/Dev2/80MHzTimebase", Low, 80, 80, 80000);
// I assume starting the APD counter now will have it sitting around doing nothing because Ctr1InternalOutput is in fact LOW? _tskCountTask.Start();
// Generate the pulse, while the pulse is there the APD counter will count, when it goes low again, it wil be paused
_tskPulseTask.Start();
// Some code to read the APD counter and put it somewhere will go here...
// Tidy up.
_tskCountTask.Dispose();
_tskPulseTask.Dispose();
}
Am I correct in assuming this will work?? I won't have access to the actual hardware for another two weeks so I can only run against simulated hardware but I really would like to know well before if this will work so I can finish my software early...
Cheers,
Kris
08-21-2008 05:47 PM
Hi Kris
Your program looks good, and I was able to run in on my hardware (without a detector), however it is difficult to tell if it will work exactly how you want it to without explicitly testing it.
One thing that I want to point out is you are basically creating a frequency counter, so you could use the measure digital frequency example program that is prebuilt which might be easier.
Once you get the hardware we can ensure that it is functioning exactly how you have planned.
08-22-2008 04:07 AM
Hello Chris,
Thanks already for your reply. I'll look into using a freq. Ctr. directly as you mentioned.
I did some further coding since the last post and I noticed that it is not generating errors against simulated hardware, which is already good. However, the timed counting I'm doing is being run in a loop. When doing so the code becomes _very_ slow, mainly because of daqmx.task.start() and daqmx.task.stop calls.
Because I was a bit impatient and because I didn't know if anybody was going to read my post in this thread I posted about it here;
http://forums.ni.com/ni/board/message?board.id=232&thread.id=7537
This should explain in more detail what my aim is and it also contains my current code in attachment, together with an analysis by ANTS profiler.
I will also attach them here...
08-25-2008 12:02 PM
Hi Kris
I have had a look at you other post and I think that moving the task configurations outside the loop will significantly improve the time it takes to complete measurements. There is also one more thing that you can try to improve the speed of the Start and Stop calls. They really should not be taking that long, but if you configure and then commit the task outside of the loop and then just call the start task in the loop your code should run a lot faster.
For instance configure the counter tasks that you are using, and then call
myTask.Control(TaskAction.Commit);this will commit the counter tasks, and then in the function call that you make when taking the photon readings you can just call the start task.
I am not sure why you are seeing such slow execution with simulated software, but this will help significantly when you do get your hardware.
More information on the task state model can be found in the DAQmx Help file if you search for Commit
Regards
Chris_K_
08-25-2008 06:02 PM
Hi Chris,
I thought about your recommendations for a while.
I updated my code to implement the starting of tasks outside of the loops for the most part (updated and cleaned up source is attached). This indeed gives me a massive speed increase. However, there are still to problems that remain;
The counter that handles photon counting for the APD obviously has a maximum amount of counts it can handle before it will overflow. Although unlikely that this will happen with the samples I intend to measure I think it is good practice to take this eventuality into account. Therefore I would like to reset the counter right before I start a new 2 or whatever milisecond acquisition. I'm afraid this will not be possible to do without actually stopping the counting task and restarting it which would again be a huge performance hit... It appears strange to me that there is seems to be no obviousway to do this.
The second problem involves the counter that creates my milisecond pulse to start and pause counting for the APD. To avoid multiple Start() Stop() calls for this task I now defined it as retriggerable = true. The idea being that I could thus create multiple milisecond pulses whenever needed. But again I only see hardware events to set as a trigger and no way to trigger the task from software. Probably hardware triggering is the most robust way to trigger a task, but sometimes software events are enough... So for now I still use a Start() Stop() pair inside my loop for this. As expected the Stop() call slows down the code execution...
Am I missing things to solve these remaining issues?
Thanks already for the help!
08-26-2008 01:41 PM
Hi Kris
The only way to reset the count of a counter task is to stop and start it. As long as the tasks have been configured outside of the loop, you should be able to start and stop them without a significant performance drop. Further more if you configure and commit the tasks, as I have explained earlier, and then start and stop them in the loop your code will run even faster. For more information about this along with an example have a look at the following link.
http://digital.ni.com/public.nsf/allkb/65E3DBC715998C3286256E900075B7F8?OpenDocument
As for your second question, I don’t think you will suffer a significant decrease in performance starting and stopping the task in order to generate the pulse as long as it is configured outside the loop.
Chris_K
08-26-2008 03:09 PM
Hi Chris,
I just had the chance to give my software a go on the actual hardware.
I followed your recommendations about the whole task setup and commit thing outside of the loop with ony a start() stop() pair inside the loop for my pulse task. On simulated hardware this still runs relatively slow but oddly enough it is _very_ fast on the actual hardware! So all my troubles are hereby solved!
One last thing I wondered about:
Can I use an RTSI cable to sync my PCI6602 and PCI6731 to make stage movement and APD counting perfectly synced?
08-27-2008 10:21 PM
09-25-2008 03:18 PM
Hello Chris,
I had significant time to play with the hardware by now.
My program works very well in a synchronous way. I can create all my tasks, count from the APD, store everything in an array and when all my tasks have finished running, I can transfer the counted data to an onscreen image.
However, the current program is not very convenient. I would like to continually update the UI with the latest acquired pixels from my scan. Also I would like to have the whole scan operation run in a timed way.
Currently this is what I have:
1) Create a two channel AO task to drive X-Y motion of my piezo stage
2) Create a continuous countertask that generates a 200 Hz pulsetrain, this is the global timing source. Every tick the stage should move to a new position.
3) Set timing for the AO tasks (1) to the countertask
4) Use a normal Multichannel writer to write multiple precalculated "coordinate" voltages to the stage.
Running both tasks in a thread seperate from the UI threadworks perfectly, the stage moves in a timed way and the UI remains updatable with data from a dummy routine...
I choose not to use the daqmx begin and endwrite funcionality since this gave me weird results (basically, not all points were written, not even when I tried to use IsDone on the task). I do not understand properly when writing to the DAQ buffer is finished. (Is there documentation on the various timing issues/pitfalls with the asynchronous methods in Daqmx?)
Anyway, my way of doing it seems to work smoothly.
The problem now is however, that I want to use the global timing task to do the following:
1) Trigger a second retriggerable counter task that outputs a well defined 2 ms pulse.
2) The 2 ms pulse (acquisition timer) should be the pausetrigger for the third counter that counts TTL's from my APD detector. This 2 ms pulse will have an initial delay to allow the stage ample time to physically move. The general scheme is (global timing pulse tick -> write one AO sample and start the delayed 2ms pulse).
I then would like to read the APD counts acquired during the 2 ms high time of the APD acquisition timer and put them in an array.
This is where trouble starts:
I initially wanted to add a pause trigger to the APD TTL counter and use a timingsource as well (to sync the APD counting with stage movement). This way I could have the APD counter count in short 2 ms bursts and latch the count values to the buffer of the counter and read them from buffer whenever I felt like it (using a readmultisample, reading 1 or more samples at a time).I would then also haveconfigured the sampling to be finite on the APD counter (limit it to the number of moves or pixels).
However, Daqmx does not allow sampleclocks to be used together with pause triggers (I don't see why this shouldn't be a valid usage scenario).
So I am totally lost now. My stage is moving in a timed way, it stays in every position for 5 ms and I would like to do a photon count in every position for 2 ms and read out the counted values every 10 or so positions to push them to the UI. However, I cannot for the life of me think of a way to do this.
Could you help me out or point me to somebody who can. I really, really need to finish this project as soon as possible :s My dissertation depends on it 🙂
Cheers,
09-26-2008 09:38 AM - edited 09-26-2008 09:40 AM
With a 6602 and several available counters, I strongly suspect we can find a way to generate the right timing signals. Let me first restate what I think your timing needs and problems are:
1. AO is updated every 5 msec (200 Hz) to generate a positional change to a piezo stage.
2. Within each 5 msec interval, you want to wait 2 or so msec for motion response time, then collect APD counts for exactly 2 msec.
3. Problem: you'd like to generate a delayed 2 msec pulse that the counter task uses as a pause trigger superimposed on your buffered counting task. The buffered counting task counts APD pulses as its source input and uses the 200 Hz master timing clock as its sample clock (gate input). DAQmx doesn't seem to allow pause-triggering in this task.
Solution possibilities:
A. This'll sound weird but bear with me. Instead of doing buffered edge counting on the APD pulses, configure a buffered semi-period measurement. You'll need to config the task to use the APD signal as the timebase source signal, and to use the retriggerable single pulse as the input signal whose semi-periods are being measured. Set your units to be "ticks" or "counts" rather than "seconds". Config the retriggerable single pulse with a low time and initial delay of 2 msec, and a high time of 2 msec. This will place the pulse from the 2 to 4 msec offset within your master 5 msec intervals.
Deep breath. In semi-period measurement mode, count values are buffered on both rising and falling edges of the input signal. In this case, rising and falling edges of the retriggerable pulse. The APD, acting as the timebase, causes the count register to increment within each interval. So the DAQmx measurement buffer will contain alternating values representing APD counts during the 2 msec you care about and the 3 msec you don't care about. In post-processing, you can simply ignore the meaningless 1/2 of the values.
Note that the count automatically resets to 0 on each buffering action rather than accumulating. If you need cumulative counts, that's an easy post-processing step too.
B. Add another even-more-master clock at, say, 20 kHz. Generate your 200 Hz clock by dividing down the 20 kHz clock -- this will help guarantee that they stay in sync, especially if you need to divide these functions across different DAQ boards. Use the 20 kHz clock as the APD sample clock. Now you'll get 100 measurements per 5 msec interval. If you only want 40 of them (2 msec worth), you can do some post-processing to extract a particular subset of 40 out of each group of 100. The nice thing about this approach is that it may give you some additional information about response transients by breaking each 5 msec interval up into small time slices.
There may be some other ways too, but first see what you think of these two.
-Kevin P.
P.S. With both of these approaches, you may need to be careful about configuring the "Duplicate Count Prevention" property on your APD counter task.