Change email address, add Comedi version and device name
[comedilib.git] / doc / tutorial
1
2 Comedi tutorial
3
4 0.  Compiling and Installing
5 0.  Insmod'ding the kernel module
6 0.  Configuring comedi to use your hardware
7 0.  Getting information from comedi
8 0.  Your first comedi program
9 0.  Converting samples to voltages
10
11
12
13 0.  Compiling and Installing
14
15 needs to be written
16
17
18
19
20 0.  Insmod'ding the kernel module
21
22 needs to be written
23
24
25
26 0.  Configuring comedi to use your hardware
27
28
29 I assume that your hardware device is in your computer, and that
30 you know the relevant details about it, i.e., what kind of card
31 it is, the I/O base, the IRQ, jumper settings related to input
32 ranges, etc.
33
34 To tell the comedi kernel module that you have a particular device, and
35 some information about it, you will be running the 'comedi_config'
36 command.  Perhaps you should read the man page now.
37
38 For this tutorial, I have two devices, a National Instruments AT-MIO-16E-10
39 and a Data Translation DT2821-F-8DI.
40
41 The NI board is plug-and-play, and the man page tells me that I need
42 to configure the PnP part of the board with isapnptools.  The isapnptools
43 package is a little cryptic, but the concepts are simple.  Once I
44 learned how to use it, I settled on a /etc/isapnp.conf file that
45 contained the lines:
46
47
48 # ANSI string -->National Instruments, AT-MIO-16E-10<--
49 (CONFIGURE NIC2400/10725401 (LD 0
50         (IO 0 (BASE 0x0260))
51         (INT 0 (IRQ 3 (MODE +E)))
52 #       (DMA 0 (CHANNEL 5))
53 #       (DMA 1 (CHANNEL 6))
54         (ACT Y)
55 ))
56
57
58 It also contains a few lines about overall configuration and about my
59 sound card.  I found out after a bit of trial-and-error that the NI
60 board does not always work with interrupts other than IRQ 3.  YMMV.
61 Currently, the driver doesn't use DMA, but it may in the future, so
62 I commented out the DMA lines.  It is a curious fact that the device
63 ignores the IRQ and DMA information given here, however, I keep the
64 information here to remind myself that the numbers aren't arbitrary.
65
66 When I run comedi_config (as root, of course), I provide the same
67 information.  Since I want to have the board configured every time
68 I boot, I put the line
69
70    /usr/sbin/comedi_config /dev/comedi0 atmio-E 0x260,3
71
72 into /etc/rc.d/rc.local.  You can, of course, run this command at
73 a command prompt.  The man page tells me that the option list
74 is supposed to be "<I/O base>,<IRQ>", so I used the same numbers
75 as I put in /etc/isapnp.conf, i.e., 0x260,3.
76
77 For the Data Translation board, I need to have a list of the
78 jumper settings.  Fortunately, I wrote them all down in the
79 manual -- I hope they are still correct.  However, I had to
80 open the case to figure out which board in the series I had.
81 It is a DT2821-f-8di.  The man page of comedi_config tells
82 me that I need to know the I/O base, IRQ, DMA 1, DMA 2.  However,
83 since I wrote the driver, I know that it also recognizes the
84 differential/single-ended and unipolar/bipolar jumpers.  As always,
85 the source is the final authority, and looking in module/dt282x.c
86 tells me that the options list is interpreted as:
87
88         i/o base
89         irq
90         1=differential, 0=single ended
91         ai 0=unipolar, 1=bipolar
92         ao0 0=unipolar, 1=bipolar
93         ao1 0=unipolar, 1=bipolar
94         dma1
95         dma2
96
97 (ai=analog input, ao=analog output.)  From this, I decide that
98 the appropriate options list is
99
100         0x200,4,,1,1,1
101
102 I left the differential/single-ended number blank, since the
103 driver already knowns (from the board name), that it is
104 differential.  I  also left the DMA numbers blank, since I
105 don't want the driver to use DMA.  (Don't want it to interfere
106 with my sound card -- life is full of difficult choices.)
107 Keep in mind that things commented in the source, but not in
108 the documentation are about as likely to change as the weather,
109 so I put good comments next to the following line when I put
110 it in rc.local.
111
112    /usr/sbin/comedi_config /dev/comedi1 dt2821-f-8di 0x200,4,,1,1,1
113
114 So now I think that I have my boards configured correctly.
115 Since data acquisition boards are not typically well-engineered,
116 comedi sometimes can't figure out if the board is actually there.
117 If it can't, it assumes you are right.  Both of these boards
118 are well-made, so comedi will give me an error message if it
119 can't find them.  The comedi kernel module, since it is a part
120 of the kernel, prints messages to the kernel logs, which you
121 can access through the command 'dmesg' or /var/log/messages.
122 Here is a configuration failure (from dmesg):
123
124   comedi0: ni_E: 0x0200 can't find board
125
126 When it does work, I get:
127
128   comedi0: ni_E: 0x0260 at-mio-16e-10 ( irq = 3 )
129
130 Note that it also correctly identified my board.
131
132
133
134
135 0.  Getting information from comedi
136
137
138 So now that we have comedi talking to the hardware, we want to
139 talk to comedi.  Here's some pretty low-level information --
140 it's sometimes useful for debugging:
141
142    cat /proc/comedi
143
144 Right now, on my computer, this command gives:
145
146    comedi version 0.6.4
147    format string
148     0: atmio-E              at-mio-16e-10           7
149     1: dt282x               dt2821-f-8di            4
150
151 This is a feature that is not well-developed yet.  Basically, it
152 currently tells you driver name, device name, and number of
153 subdevices.
154
155 In the demo/ directory, there is a command called
156 'info', which provides information about each subdevice on the
157 board.  The output of it is rather long, since I have 7
158 subdevices  (4 or fewer is more common.)
159 Here's part of the output of the NI board (which
160 is on /dev/comedi0.)  ('demo/info /dev/comedi0')
161
162 overall info:
163   version code: 0x000604
164   driver name: atmio-E
165   board name: at-mio-16e-10
166   number of subdevices: 7
167 subdevice 0:
168   type: 1 (unknown)
169   number of channels: 16
170   max data value: 4095
171
172
173 The overall info gives information about the device -- basically
174 the same information as /proc/comedi.
175
176 This board has 7 subdevices.  Devices are separated into
177 subdevices that each have a distinct purpose -- e.g., analog
178 input, analog output, digital input/output.  This board also
179 has an EEPROM and calibration DACs that are also subdevices.
180
181 Subdevice 0 is the analog input subdevice.  You would have
182 known this from the 'type: 1 (unknown)' line, if I've updated
183 demo/info recently, because it would say 'type: 1 (analog input)'
184 instead.  The other lines should be self-explanitory.  Comedi
185 has more information about the device, but demo/info doesn't
186 currently display this.
187
188
189
190 0.  Your first comedi program
191
192 This example requires a card that has analog or
193 digital input.  Right to the source:
194
195 #include <stdio.h>      /* for printf() */
196 #include <comedilib.h>
197
198 int subdev = 0;         /* change this to your input subdevice */
199 int chan = 0;           /* change this to your channel */
200 int range = 0;          /* more on this later */
201 int aref = AREF_GROUND; /* more on this later */
202
203 int main(int argc,char *argv[])
204 {
205         comedi_t *it;
206         int chan=0;
207         lsampl_t data;
208         
209         it=comedi_open("/dev/comedi0");
210         
211         comedi_data_read(it,subdev,chan,range,aref,&data);
212         
213         printf("%d\n",data);
214         
215         return 0;
216 }
217
218
219 Should be understandable.  Open the device, get the data,
220 print it out.  This is basically the guts of demo/inp.c,
221 without error checking or fancy options.  Including all
222 the appropriate headers is sometimes a little tricky.
223 Compile it using 'cc tut1.c -lcomedi -o tut1'.  Hopefully
224 it works.
225
226 A few notes:  The range variable tells comedi which gain
227 to use when measuring an analog voltage.  Since we don't
228 know (yet) which numbers are valid, or what each means,
229 we'll use 0, because it won't cause errors.  Likewise with
230 aref, which determines the analog reference used.
231
232
233 0.  Converting samples to voltages
234
235
236 If you selected an analog input subdevice, you should notice
237 that the output of tut1 is a number between
238 0 and 4095, or 0 and 65535, depending on the number of bits
239 in the A/D converter.  Comedi samples are *always* unsigned,
240 with 0 representing the lowest voltage of the ADC, and 4095
241 the highest.  The hardware driver compensates for
242 anything else the manual for your device says.  However,
243 you probably prefer to have this number translated to
244 a voltage.  Naturally, as a good programmer, your first
245 question is: "How do I do this in a device-independent
246 manner?"
247
248 For each subdevice, the comedi kernel module keeps a
249 'range_type' variable.  This variable contains the number
250 of available ranges (i.e., gains) that you can select,
251 along with an offset in a list of range information
252 structures.  If you know the range_type variable, you
253 can use these macros:
254
255    RANGE_OFFSET(range_type)
256    RANGE_LENGTH(range_type)
257
258 to extract such information.  However, you want the
259 actual voltage information, not some integer offset
260 in a table.  Rather than messing with the library
261 internals, use the function
262
263    ptr=comedi_get_range(comedi_file,subdevice,channel,
264         range)
265
266 which returns a pointer to a comedi_range structure.
267 The comedi_range structure looks like
268
269    typedef struct{
270            double min;
271            double max;
272            unsigned int unit;
273    }comedi_range;
274
275 The element 'min' represents the voltage corresponding to
276 comedi_data_read() returning 0, and 'max' represents
277 comedi_data_read() returning 'maxdata', (i.e., 4095 for 12
278 bit A/C converters, 65535 for 16 bit, or, 1 for digital input
279 -- more on this in a bit.)  The 'unit' entry tells you if min and
280 max refer to voltage, current, etc.
281
282 "Could it get easier?", you say.  Well, yes.  Use
283 the function comedi_to_phys(), which converts data
284 values to physical units.  Call it using something like
285
286    volts=comedi_to_phys(it,data,range,maxdata);
287
288 and the opposite
289
290    data=comedi_from_phys(it,volts,range,maxdata);
291
292 You probably noticed (and were worried) that we haven't
293 discussed how to determine maxdata and range_type.  Well,
294 you could ask the kernel this information each time you need
295 it, but since there are other variables, special cases,
296 and several subdevices to worry about, it would be nice
297 if the library could take care of this...  (read on...)
298
299
300
301 0.
302
303
304 In addition to providing low level routines for data
305 access, the comedi library provides higher-level access,
306 much like the standard C library provides fopen(), etc.
307 as a high-level (and portable) alternative to the direct
308 UNIX system calls open(), etc.  Similarily to fopen(),
309 we have comedi_open():
310
311         file=comedi_open("/dev/comedi0");
312
313 where file is of type (comedi_t *).  This function
314 calls open(), like we did explicitly in a previous
315 section, but also fills the comedi_t structure with
316 lots of goodies -- information that we will need to use
317 soon.
318
319 Specifically, we needed to know maxdata for a specific
320 subdevice/channel.  How about:
321
322    maxdata=comedi_get_maxdata(file,subdevice,channel);
323
324 Wow.  How easy.  And the range type?
325
326    range_type=comedi_get_rangetype(file,subdevice,channel);
327
328 Cool.  Other information you need to know about a channel
329 can be gotten in a similar way.
330
331
332
333 0. Your second comedi program
334
335
336 Actually, this is the first comedi program again, just
337 that we've added what we've learned.
338
339
340 #include <stdio.h>      /* for printf() */
341 #include <comedi.h>     /* also included by comedilib.h */
342 #include <comedilib.h>  /* for comedi_get() */
343
344 int subdev = 0;         /* change this to your input subdevice */
345 int chan = 0;           /* change this to your channel */
346 int range = 0;          /* more on this later */
347 int aref = 0;           /* more on this later */
348
349 int main(int argc,char *argv[])
350 {
351         comedi_t *cf;
352         int chan=0;
353         int data;
354         int maxdata,rangetype;
355         double volts;
356
357         cf=comedi_open("/dev/comedi0");
358
359         maxdata=comedi_get_maxdata(cf,subdev,chan);
360
361         rangetype=comedi_get_rangetype(cf,subdev,chan);
362
363         data=comedi_get(cf->fd,subdev,chan,range,aref);
364
365         volts=comedi_to_phys(data,rangetype,range,maxdata);
366
367         printf("%d %g\n",data,volts);
368
369         return 0;
370 }
371
372
373 By now, the comedi_read_data() line looks a little archaic, using
374 the UNIX file descriptor cf->fd instead of just cf.  (By the
375 way, somewhere in the heart of comedi_open() is the line
376 cf->fd=open(filename,O_RDWR).)  Well, there isn't one good
377 replacement, since it highly depends on your application
378 what additional features you might want in a comedi_get()
379 replacement.  But this is the topic of a different section.
380
381
382 0. stuff
383
384
385
386 0. Slowly-varying inputs
387
388
389 Sometimes, your input channels change slowly enough that
390 you are able to average many sucessive input values to get a
391 more accurate measurement of the actual value.  In general,
392 the more samples you average, the better your estimate
393 gets, roughly by a factor of sqrt(number_of_samples).
394 Obviously, there are limitations to this:
395
396  - you are ultimately limited by "spurious free dynamic range"
397
398  - you need to have _some_ noise on the input channel,
399    otherwise you will be averaging the same number N times.
400
401  - the more noise you have, the greater your SFDR, but it
402    takes many more samples to compensate for the increased
403    noise
404
405  - if you feel the need to average samples for 2 seconds,
406    your signal will need to be _very_ slowly-varying, i.e.,
407    not varying more than your target uncertainty for the
408    entire 2 seconds.
409
410 As you might have guessed, the comedi library has functions
411 to help you in your quest to accurately measure slowly varying
412 inputs.  I use these functions to measure thermocouple voltages
413 -- actually, the library functions came from a section of code
414 that was previously part of the thermocouple reading program.
415
416 The comedi self-calibration utility also uses these functions.
417 On some hardware, it is possible to tell it to measure an
418 internal stable voltage reference, which is typically going
419 to be very slowly varying -- on the kilosecond time scale
420 or more.  So it is reasonable to measure millions of samples,
421 to get a very accurate measurement of the A/D converter output
422 value that corresponds to the voltage reference.  Sometimes,
423 however, this is overkill, since there is no need to
424 perform a part-per-million calibration to a standard that
425 is only accurate to part-per-thousand.
426
427
428
429
430