RTXI 1.3
comedilib/demo/ao_waveform.c
Go to the documentation of this file.
00001 /*
00002  * Asynchronous Analog Output Example
00003  * Part of Comedilib
00004  *
00005  * Copyright (c) 1999,2000 David A. Schleef <ds@schleef.org>
00006  *
00007  * This file may be freely modified, distributed, and combined with
00008  * other software, as long as proper attribution is given in the
00009  * source code.
00010  */
00011 
00012 /*
00013  * Requirements: Analog output device capable of
00014  *    asynchronous commands.
00015  *
00016  * This demo uses an analog output subdevice with an
00017  * asynchronous command to generate a waveform.  The
00018  * demo hijacks for -n option to select a waveform from
00019  * a predefined list.  The default waveform is a sine
00020  * wave (surprise!).  Other waveforms include sawtooth,
00021  * square, triangle and cycloid.
00022  *
00023  * The function generation algorithm is the same as
00024  * what is typically used in digital function generators.
00025  * A 32-bit accumulator is incremented by a phase factor,
00026  * which is the amount (in radians) that the generator
00027  * advances each time step.  The accumulator is then
00028  * shifted right by 20 bits, to get a 12 bit offset into
00029  * a lookup table.  The value in the lookup table at
00030  * that offset is then put into a buffer for output to
00031  * the DAC.
00032  *
00033  * [ Actually, the accumulator is only 26 bits, for some
00034  * reason.  I'll fix this sometime. ]
00035  *
00036  */
00037 
00038 #include <stdio.h>
00039 #include <comedilib.h>
00040 #include <fcntl.h>
00041 #include <stdlib.h>
00042 #include <unistd.h>
00043 #include <errno.h>
00044 #include <getopt.h>
00045 #include <ctype.h>
00046 #include <math.h>
00047 #include <string.h>
00048 #include "examples.h"
00049 
00050 
00051 /* frequency of the sine wave to output */
00052 double waveform_frequency       = 10.0;
00053 
00054 /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
00055 double amplitude                = 4000;
00056 
00057 /* offset, in DAC units */
00058 double offset                   = 2048;
00059 
00060 /* This is the size of chunks we deal with when creating and
00061    outputting data.  This *could* be 1, but that would be
00062    inefficient */
00063 #define BUF_LEN 0x8000
00064 
00065 int external_trigger_number = 0;
00066 
00067 sampl_t data[BUF_LEN];
00068 
00069 void dds_output(sampl_t *buf,int n);
00070 void dds_init(double waveform_frequency, double update_frequency, int fn);
00071 
00072 void dds_init_sine(void);
00073 void dds_init_pseudocycloid(void);
00074 void dds_init_cycloid(void);
00075 void dds_init_ramp_up(void);
00076 void dds_init_ramp_down(void);
00077 void dds_init_triangle(void);
00078 void dds_init_square(void);
00079 void dds_init_blancmange(void);
00080 
00081 static void (* const dds_init_function[])(void) = {
00082         dds_init_sine,
00083         dds_init_ramp_up,
00084         dds_init_ramp_down,
00085         dds_init_triangle,
00086         dds_init_square,
00087         dds_init_cycloid,
00088         dds_init_blancmange,
00089 };
00090 
00091 #define NUMFUNCS        (sizeof(dds_init_function)/sizeof(dds_init_function[0]))
00092 
00093 int main(int argc, char *argv[])
00094 {
00095         comedi_cmd cmd;
00096         int err;
00097         int n,m;
00098         int total=0;
00099         comedi_t *dev;
00100         unsigned int chanlist[16];
00101         unsigned int maxdata;
00102         comedi_range *rng;
00103         int ret;
00104         struct parsed_options options;
00105         int fn;
00106 
00107         init_parsed_options(&options);
00108         options.subdevice = -1;
00109         options.n_chan = 0;     /* default waveform */
00110         parse_options(&options, argc, argv);
00111 
00112         /* Use n_chan to select waveform (cheat!) */
00113         fn = options.n_chan;
00114         if(fn < 0 || fn >= NUMFUNCS){
00115                 fn = 0;
00116         }
00117 
00118         /* Force n_chan to be 1 */
00119         options.n_chan = 1;
00120 
00121         if(options.value){
00122                 waveform_frequency = options.value;
00123         }
00124 
00125         dev = comedi_open(options.filename);
00126         if(dev == NULL){
00127                 fprintf(stderr, "error opening %s\n", options.filename);
00128                 return -1;
00129         }
00130         if(options.subdevice < 0)
00131                 options.subdevice = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_AO, 0);
00132 
00133         maxdata = comedi_get_maxdata(dev, options.subdevice, options.channel);
00134         rng = comedi_get_range(dev, options.subdevice, options.channel, options.range);
00135 
00136         offset = (double)comedi_from_phys(0.0, rng, maxdata);
00137         amplitude = (double)comedi_from_phys(1.0, rng, maxdata) - offset;
00138 
00139         memset(&cmd,0,sizeof(cmd));
00140         cmd.subdev = options.subdevice;
00141         cmd.flags = CMDF_WRITE;
00142         cmd.start_src = TRIG_INT;
00143         cmd.start_arg = 0;
00144         cmd.scan_begin_src = TRIG_TIMER;
00145         cmd.scan_begin_arg = 1e9 / options.freq;
00146         cmd.convert_src = TRIG_NOW;
00147         cmd.convert_arg = 0;
00148         cmd.scan_end_src = TRIG_COUNT;
00149         cmd.scan_end_arg = options.n_chan;
00150         cmd.stop_src = TRIG_NONE;
00151         cmd.stop_arg = 0;
00152 
00153         cmd.chanlist = chanlist;
00154         cmd.chanlist_len = options.n_chan;
00155 
00156         chanlist[0] = CR_PACK(options.channel, options.range, options.aref);
00157         //chanlist[1] = CR_PACK(options.channel + 1, options.range, options.aref);
00158 
00159         dds_init(waveform_frequency, options.freq, fn);
00160 
00161         dump_cmd(stdout,&cmd);
00162 
00163         err = comedi_command_test(dev, &cmd);
00164         if (err < 0) {
00165                 comedi_perror("comedi_command_test");
00166                 exit(1);
00167         }
00168 
00169         err = comedi_command_test(dev, &cmd);
00170         if (err < 0) {
00171                 comedi_perror("comedi_command_test");
00172                 exit(1);
00173         }
00174 
00175         if ((err = comedi_command(dev, &cmd)) < 0) {
00176                 comedi_perror("comedi_command");
00177                 exit(1);
00178         }
00179 
00180         dds_output(data,BUF_LEN);
00181         n = BUF_LEN * sizeof(sampl_t);
00182         m = write(comedi_fileno(dev), (void *)data, n);
00183         if(m < 0){
00184                 perror("write");
00185                 exit(1);
00186         }else if(m < n)
00187         {
00188                 fprintf(stderr, "failed to preload output buffer with %i bytes, is it too small?\n"
00189                         "See the --write-buffer option of comedi_config\n", n);
00190                 exit(1);
00191         }
00192         printf("m=%d\n",m);
00193 
00194         ret = comedi_internal_trigger(dev, options.subdevice, 0);
00195         if(ret < 0){
00196                 perror("comedi_internal_trigger\n");
00197                 exit(1);
00198         }
00199 
00200         while(1){
00201                 dds_output(data,BUF_LEN);
00202                 n=BUF_LEN*sizeof(sampl_t);
00203                 while(n>0){
00204                         m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
00205                         if(m<0){
00206                                 perror("write");
00207                                 exit(0);
00208                         }
00209                         printf("m=%d\n",m);
00210                         n-=m;
00211                 }
00212                 total+=BUF_LEN;
00213                 //printf("%d\n",total);
00214         }
00215 
00216         return 0;
00217 }
00218 
00219 
00220 
00221 #define WAVEFORM_SHIFT 16
00222 #define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
00223 #define WAVEFORM_MASK (WAVEFORM_LEN-1)
00224 
00225 
00226 sampl_t waveform[WAVEFORM_LEN];
00227 
00228 unsigned int acc;
00229 unsigned int adder;
00230 
00231 void dds_init(double waveform_frequency, double update_frequency, int fn)
00232 {
00233         adder = waveform_frequency / update_frequency * (1 << 16) * (1 << WAVEFORM_SHIFT);
00234 
00235         (*dds_init_function[fn])();
00236 }
00237 
00238 void dds_output(sampl_t *buf,int n)
00239 {
00240         int i;
00241         sampl_t *p=buf;
00242 
00243         for(i=0;i<n;i++){
00244                 *p=waveform[(acc>>16)&WAVEFORM_MASK];
00245                 p++;
00246                 acc+=adder;
00247         }
00248 }
00249 
00250 /* Defined for x in [0,1] */
00251 static inline double triangle(double x)
00252 {
00253         return (x > 0.5) ? 1.0 - x : x;
00254 }
00255 
00256 void dds_init_sine(void)
00257 {
00258         int i;
00259         double ofs = offset;
00260         double amp = 0.5 * amplitude;
00261 
00262         if(ofs < amp){
00263                 /* Probably a unipolar range.  Bump up the offset. */
00264                 ofs = amp;
00265         }
00266         for(i=0;i<WAVEFORM_LEN;i++){
00267                 waveform[i]=rint(ofs+amp*cos(i*2*M_PI/WAVEFORM_LEN));
00268         }
00269 }
00270 
00271 /* Yes, I know this is not the proper equation for a
00272    cycloid.  Fix it. */
00273 void dds_init_pseudocycloid(void)
00274 {
00275         int i;
00276         double t;
00277 
00278         for(i=0;i<WAVEFORM_LEN/2;i++){
00279                 t=2*((double)i)/WAVEFORM_LEN;
00280                 waveform[i]=rint(offset+amplitude*sqrt(1-4*t*t));
00281         }
00282         for(i=WAVEFORM_LEN/2;i<WAVEFORM_LEN;i++){
00283                 t=2*(1-((double)i)/WAVEFORM_LEN);
00284                 waveform[i]=rint(offset+amplitude*sqrt(1-t*t));
00285         }
00286 }
00287 
00288 void dds_init_cycloid(void)
00289 {
00290         enum { SUBSCALE = 2 };  /* Needs to be >= 2. */
00291         int h, i, ni;
00292         double t, x, y;
00293 
00294         i = -1;
00295         for (h = 0; h < WAVEFORM_LEN * SUBSCALE; h++){
00296                 t = (h * (2 * M_PI)) / (WAVEFORM_LEN * SUBSCALE);
00297                 x = t - sin(t);
00298                 ni = (int)floor((x * WAVEFORM_LEN) / (2 * M_PI));
00299                 if (ni > i) {
00300                         i = ni;
00301                         y = 1 - cos(t);
00302                         waveform[i] = rint(offset + (amplitude * y / 2));
00303                 }
00304         }
00305 }
00306 
00307 void dds_init_ramp_up(void)
00308 {
00309         int i;
00310 
00311         for(i=0;i<WAVEFORM_LEN;i++){
00312                 waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);
00313         }
00314 }
00315 
00316 void dds_init_ramp_down(void)
00317 {
00318         int i;
00319 
00320         for(i=0;i<WAVEFORM_LEN;i++){
00321                 waveform[i]=rint(offset+amplitude*((double)(WAVEFORM_LEN-1-i))/WAVEFORM_LEN);
00322         }
00323 }
00324 
00325 void dds_init_triangle(void)
00326 {
00327         int i;
00328 
00329         for (i = 0; i < WAVEFORM_LEN; i++) {
00330                 waveform[i] = rint(offset + amplitude * 2 * triangle((double)i / WAVEFORM_LEN));
00331         }
00332 }
00333 
00334 void dds_init_square(void)
00335 {
00336         int i;
00337 
00338         for (i = 0; i < WAVEFORM_LEN / 2; i++) {
00339                 waveform[i] = rint(offset);
00340         }
00341         for ( ; i < WAVEFORM_LEN; i++) {
00342                 waveform[i] = rint(offset + amplitude);
00343         }
00344 }
00345 
00346 void dds_init_blancmange(void)
00347 {
00348         int i, n;
00349         double b, x;
00350 
00351         for (i = 0; i < WAVEFORM_LEN; i++) {
00352                 b = 0;
00353                 for (n = 0; n < 16; n++) {
00354                         x = (double)i / WAVEFORM_LEN;
00355                         x *= (1 << n);
00356                         x -= floor(x);
00357                         b += triangle(x) / (1 << n);
00358                 }
00359                 waveform[i] = rint(offset + amplitude * 1.5 * b);
00360         }
00361 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines