2 * Asynchronous Analog Output Example
5 * Copyright (c) 1999,2000 David A. Schleef <ds@schleef.org>
7 * This file may be freely modified, distributed, and combined with
8 * other software, as long as proper attribution is given in the
13 * Requirements: Analog output device capable of
14 * asynchronous commands.
16 * This demo uses an analog output subdevice with an
17 * asynchronous command to generate a waveform. The
18 * waveform in this example is a sine wave (surprise!),
19 * but this can be easily changed to make a generic
22 * The function generation algorithm is the same as
23 * what is typically used in digital function generators.
24 * A 32-bit accumulator is incremented by a phase factor,
25 * which is the amount (in radians) that the generator
26 * advances each time step. The accumulator is then
27 * shifted right by 20 bits, to get a 12 bit offset into
28 * a lookup table. The value in the lookup table at
29 * that offset is then put into a buffer for output to
32 * [ Actually, the accumulator is only 26 bits, for some
33 * reason. I'll fix this sometime. ]
35 * On the Comedi side of things, the setup for mode 2
36 * is similar to analog input, except for the TRIG_WRITE
37 * flag. Once you have issued the command, comedi then
38 * expects you to keep the buffer full of data to output
39 * to the DAC. This is done by write(). Since there
40 * may be a delay between the comedi_command() and a subsequent
41 * write(), you should fill the buffer using write() before
42 * you call comedi_command(), as is done here.
47 #include <comedilib.h>
59 /* frequency of the sine wave to output */
60 double waveform_frequency = 10.0;
62 /* peak-to-peak amplitude, in DAC units (i.e., 0-4095) */
63 double amplitude = 4000;
65 /* offset, in DAC units */
68 /* This is the size of chunks we deal with when creating and
69 outputting data. This *could* be 1, but that would be
71 #define BUF_LEN 0x8000
74 int external_trigger_number = 0;
76 sampl_t data[BUF_LEN];
78 void dds_output(sampl_t *buf,int n);
81 /* This define determines which waveform to use. */
82 #define dds_init_function dds_init_sine
84 void dds_init_sine(void);
85 void dds_init_pseudocycloid(void);
86 void dds_init_sawtooth(void);
88 int comedi_internal_trigger(comedi_t *dev, unsigned int subd, unsigned int trignum)
93 memset(&insn, 0, sizeof(comedi_insn));
94 insn.insn = INSN_INTTRIG;
101 return comedi_do_insn(dev, &insn);
105 int main(int argc, char *argv[])
112 unsigned int chanlist[16];
113 unsigned int maxdata;
117 parse_options(argc,argv);
119 /* Force n_chan to be 1 */
123 waveform_frequency = value;
126 dev = comedi_open(filename);
128 fprintf(stderr, "error opening %s\n", filename);
131 subdevice = comedi_find_subdevice_by_type(dev,COMEDI_SUBD_AO,0);
133 maxdata = comedi_get_maxdata(dev,subdevice,0);
134 rng = comedi_get_range(dev,subdevice,0,0);
136 offset = (double)comedi_from_phys(0.0,rng,maxdata);
137 amplitude = (double)comedi_from_phys(1.0,rng,maxdata) - offset;
139 memset(&cmd,0,sizeof(cmd));
140 cmd.subdev = subdevice;
142 cmd.start_src = TRIG_INT;
144 cmd.scan_begin_src = TRIG_TIMER;
145 cmd.scan_begin_arg = 1e9/freq;
146 cmd.convert_src = TRIG_NOW;
148 cmd.scan_end_src = TRIG_COUNT;
149 cmd.scan_end_arg = n_chan;
150 cmd.stop_src = TRIG_NONE;
153 cmd.chanlist = chanlist;
154 cmd.chanlist_len = n_chan;
156 chanlist[0] = CR_PACK(channel,range,aref);
157 chanlist[1] = CR_PACK(channel+1,range,aref);
161 dump_cmd(stdout,&cmd);
163 err = comedi_command_test(dev, &cmd);
165 comedi_perror("comedi_command_test");
169 err = comedi_command_test(dev, &cmd);
171 comedi_perror("comedi_command_test");
175 if ((err = comedi_command(dev, &cmd)) < 0) {
176 comedi_perror("comedi_command");
180 dds_output(data,BUF_LEN);
181 n = BUF_LEN * sizeof(sampl_t);
182 m = write(comedi_fileno(dev), (void *)data, n);
188 fprintf(stderr, "failed to preload output buffer with %i bytes, is it too small?\n"
189 "See the --write-buffer option of comedi_config\n", n);
194 ret = comedi_internal_trigger(dev, subdevice, 0);
196 perror("comedi_internal_trigger\n");
201 dds_output(data,BUF_LEN);
202 n=BUF_LEN*sizeof(sampl_t);
204 m=write(comedi_fileno(dev),(void *)data+(BUF_LEN*sizeof(sampl_t)-n),n);
213 //printf("%d\n",total);
221 #define WAVEFORM_SHIFT 16
222 #define WAVEFORM_LEN (1<<WAVEFORM_SHIFT)
223 #define WAVEFORM_MASK (WAVEFORM_LEN-1)
226 sampl_t waveform[WAVEFORM_LEN];
233 adder=waveform_frequency/freq*(1<<16)*(1<<WAVEFORM_SHIFT);
238 void dds_output(sampl_t *buf,int n)
244 *p=waveform[(acc>>16)&WAVEFORM_MASK];
251 void dds_init_sine(void)
255 for(i=0;i<WAVEFORM_LEN;i++){
256 waveform[i]=rint(offset+0.5*amplitude*cos(i*2*M_PI/WAVEFORM_LEN));
260 /* Yes, I know this is not the proper equation for a
262 void dds_init_pseudocycloid(void)
267 for(i=0;i<WAVEFORM_LEN/2;i++){
268 t=2*((double)i)/WAVEFORM_LEN;
269 waveform[i]=rint(offset+amplitude*sqrt(1-4*t*t));
271 for(i=WAVEFORM_LEN/2;i<WAVEFORM_LEN;i++){
272 t=2*(1-((double)i)/WAVEFORM_LEN);
273 waveform[i]=rint(offset+amplitude*sqrt(1-t*t));
277 void dds_init_sawtooth(void)
281 for(i=0;i<WAVEFORM_LEN;i++){
282 waveform[i]=rint(offset+amplitude*((double)i)/WAVEFORM_LEN);