06-20-2012 03:48 PM
Hi, I have been trying in earnest over the past two days to find the best way to do this. I'm trying to generate a very accurate square wave, controlling duty cycle and frequency, with the DIO on the 9401 in a cRIO 9022 test bed.
I have a VI that nominally is capable of doing this, but anytime I try to go above 5 Hz or so, the duty cycle and frequency become inaccurate (as I watch them on an oscilloscope), varying much too much for my needs. I have a feeling that this is caused by my reliance on software controlled timing, with errors in times (on the order of ms) piling up as they get processed and the signal gets sent out. I attached a bit of code that shows the basic idea of what my VI's have in them.
I avoided the square wave generators built-in because I could never get them working to satisfaction, but I can work with them if that will fix my problems. The case and selection structures keep the user from overdoing their inputs. The unwaited while loop was just for testing.
I'm currently running the 9022 as a Real-Time target, but also tried running it as FPGA, and I was able to produce much more accurate signals using the FPGA square wave VI, outputting a boolean variable, but I couldn't see how best to get double precision variables to work with everything (and I do want more precision than the FXP variables and 40 MHz clock allowed).
I have a feeling there's just an error in my approach here. I have seen other threads where people were throwing around using the counters on-board the test bed to output a square wave, and I see the example VIs like Gen Dig Pulse Train - Continuous, I'm just not sure where to begin with using those DAQmx VIs for my situation (e.g. how to identify my counters, as they're clearly not Dev1/ctr0 as the default in those examples)
Solved! Go to Solution.
06-20-2012 04:35 PM
You're correct that the software timing of your cRIO's real-time operating system is likely to blame. You'll want to program the PWM functionality on the FPGA. There are multiple ways to implement PWM output on cRIO with the 9401.
It's worth mentioning that if run-time frequency control is not necessary, there's a shipping example showing the digital module in Specialty Pulse-Width Modulation mode: <labview>\examples\CompactRIO\NI Scan Engine\Advanced\Pulse Width Modulation\PWM - cRIO IO Scan.lvproj.
A PWM Output on FPGA can be implemented with the Square Wave Generator Express VI. This Express VI has inputs for both frequency and duty cycle.
If you prefer a manual implementation, check out this example program: Pulse Width Modulation (PWM) IP Core for LabVIEW FPGA.
cRIO is not programmed with the DAQmx API. Consider investing some time in the Getting Started with CompactRIO and LabVIEW tutorial. This tutorial demonstrates both cRIO I/O programming modes: Scan Interface and FPGA Interface. You can get an out-of-the-box DAQmx like experience by using the NI CompactRIO Waveform Reference Library. I do not suggest you get wrapped up in the waveform reference library for this simple PWM output task.
06-20-2012 06:26 PM
Well, if it has to be FPGA, the easiest thing to use is the square wave express VI, which I got working before, but is there anyway that I can make frequency and duty cycle selection a bit more standard? That is, instead of using a calculator to divide the desired frequency by 40e6 before you enter it, just have the VI do it? It doesn't let you use double or any other data type for entry it seems. I don't mind the output being 10.002 Hz instead of 10 Hz, etc., but it would be more than nice to just be able to enter "10" and have the program auto-correct that to whatever the device could actually handle.
06-20-2012 10:35 PM
Dealing with Fixed Point and Integer representation is a fact of life for LabVIEW FPGA <= 2011 programmers. You might build a small sub VI, such as the one attached, to encapsulate the frequency calculation, thereby abstracting the conversion formula and Fixed Point data type. You can adjust the properties of the floating point input control to accept only valid frequencies.
This implies the sub VI runs on the RT host, not on the FPGA target. So you'll also need some nodes from the FPGA Interface Palette to send the Fixed Point PWM Frequency from RT to FPGA. The complete frequency solution might look something like the following. It's common for FPGA programmers to build a collection of thesesub VIs, which constitute the API for the hardware.
Note that 40MHz is hard coded. For added flexibility, consider making the FPGA clock rate an input to the subVI with a default value of 40MHz.
06-21-2012 04:30 PM
You deserve to be paid in more than just kudos, Steve. I have got the main problems worked out and can continue my work now thanks to your help.
Just a quick question: I didn't get it working 'til I put the Open and Close FPGA reference constants outside of a loop, just as they had done in that PWM IP example you linked me. Is there a rule of thumb for why it has to be that way?
Thanks so much!
P.S. If you're curious, this is to control a gating signal to a laser we're using to foam plastic samples that have been saturated by high pressure CO2, hoping to create porous foam capable of culturing particular types of cells better than currently available meshes.
06-21-2012 05:08 PM
Glad to hear you're able to move forward with your project, which sounds pretty cool.
The rule of thumb is this: Initialize, Open/Start, <Read/Write>, Close/Stop, Check For Errors. < > is the loop. That rule applies to most references you'll use in LabVIEW, including DAQmx, FPGA, File I/O, etc. You can do it otherwise, but it's usually inefficient to do so. I don't know why the inefficient case did not work for you, unless the loop rate was so high you starved the cRIO or LabVIEW process.
Since you're not using any of the advanced features of the Timed Loop, I recommend replacing it with a While Loop and adding a 100 ms Wait function within.