2 This demo uses an analog output subdevice in timed
3 mode (mode 2) to generate a waveform. The waveform
4 in this example is a sine wave (surprise!), but this
5 can be easily changed to make a general function
8 The function generation algorithm is the same as
9 what is typically used in digital function generators.
10 A 32-bit accumulator is incremented by a phase factor,
11 which is the amount (in radians) that the generator
12 advances each time step. The accumulator is then
13 shifted right by 20 bits, to get a 12 bit offset into
14 a lookup table. The value in the lookup table at
15 that offset is then put into a buffer for output to
18 [ Actually, the accumulator is only 26 bits, for some
19 reason. I'll fix this sometime. ]
21 On the comedi side of things, the setup for mode 2
22 is similar to analog input, except for the TRIG_WRITE
23 flag. Once you have issued the command, comedi then
24 expects you to keep the buffer full of data to output
25 to the DAC. This is done by write(). Since there
26 may be a delay between the ioctl() and a subsequent
27 write(), you should fill the buffer using write() before
28 you call ioctl(), as is done here.
30 Also NOTE! The lseek() to offset 1 is used to tell
31 comedi that you want to write to subdevice 1. This
32 is not needed for analog input, since AI is usually on
37 #include <comedilib.h>
41 #include <sys/ioctl.h>
47 #define dds_init dds_init_pseudocycloid
50 /* frequency of the sine wave to output */
51 double waveform_frequency = 100.0;
53 /* update rate for the DAC, typically much higher than
54 the frequency of the sine wave. */
55 double update_frequency = 50000.0;
57 /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
58 double amplitude = 4000;
60 /* offset, in DAC units */
63 /* This is the size of chunks we deal with when creating and
64 outputting data. This *could* be 1, but that would be
73 int channels[] = { 0 };
75 int aref = AREF_GROUND;
76 int external_trigger_number = 0;
78 sampl_t data[BUF_LEN];
80 void dds_output(sampl_t *buf,int n);
81 void dds_init_sine(void);
82 void dds_init_pseudocycloid(void);
84 int main(int argc, char *argv[])
93 unsigned int chan[N_CHANS];
96 waveform_frequency=atof(argv[1]);
101 dev = comedi_open(fn);
103 subdevice = comedi_find_subdevice_by_type(dev,COMEDI_SUBD_AO,0);
105 it.subdev = subdevice;
107 it.flags = TRIG_WRITE;
114 /* convert the frequency into a timer value */
115 comedi_get_timer(dev,subdevice,update_frequency,&it.trigvar,&actual_freq);
116 fprintf(stderr,"primary actual frequency=%g timer value=%d\n",actual_freq,it.trigvar);
118 /* pack the channel list */
119 for(i=0;i<N_CHANS;i++){
120 chan[i] = CR_PACK(channels[i], range, aref);
125 dds_output(data,BUF_LEN);
126 dds_output(data,BUF_LEN);
128 lseek(comedi_fileno(dev),subdevice,SEEK_SET);
129 m=write(comedi_fileno(dev),data,BUF_LEN*sizeof(sampl_t));
134 if ((err = comedi_trigger(dev, &it)) < 0) {
139 dds_output(data,BUF_LEN);
140 n=BUF_LEN*sizeof(sampl_t);
142 m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
147 //printf("m=%d\n",m);
151 //printf("%d\n",total);
159 #define WAVEFORM_SHIFT 16
160 #define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
161 #define WAVEFORM_MASK (WAVEFORM_LEN-1)
164 sampl_t waveform[WAVEFORM_LEN];
173 adder=waveform_frequency/update_frequency*(1<<16)*(1<<WAVEFORM_SHIFT);
177 /* this is due to a bug in the NI-E driver */
179 for(i=0;i<WAVEFORM_LEN;i++){
185 void dds_init_sine(void)
189 for(i=0;i<WAVEFORM_LEN;i++){
190 waveform[i]=rint(offset+0.5*amplitude*cos(i*2*M_PI/WAVEFORM_LEN));
194 /* Yes, I know this is not the proper equation for a
196 void dds_init_cycloid(void)
201 for(i=0;i<WAVEFORM_LEN/2;i++){
202 t=2*((double)i)/WAVEFORM_LEN;
203 waveform[i]=rint(offset+amplitude*sqrt(1-4*t*t));
205 for(i=WAVEFORM_LEN/2;i<WAVEFORM_LEN;i++){
206 t=2*(1-((double)i)/WAVEFORM_LEN);
207 waveform[i]=rint(offset+amplitude*sqrt(1-t*t));
211 void dds_init_sawtooth(void)
215 for(i=0;i<WAVEFORM_LEN;i++){
216 waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);
220 void dds_output(sampl_t *buf,int n)
226 *p=waveform[(acc>>16)&WAVEFORM_MASK];