Move documentation ported to DocBook-3.1 out of docbook directory.

This commit is contained in:
David Schleef 2002-01-21 15:32:42 +00:00
parent 9a417c7282
commit 0be5b00513
15 changed files with 71 additions and 3831 deletions

View file

@ -1,9 +1,17 @@
locales = de
all:
sgml2html comedilib.sgml
sgml2txt comedilib.sgml
all: drivers.sgml funcref.sgml
-mkdir -p html
-mkdir -p man
-docbook2html -o html comedilib.sgml
-docbook2man -o man comedilib.sgml
funcref.sgml: funcref mkref
./mkref funcref >funcref.sgml
drivers.sgml: drivers.txt mkdr
./mkdr drivers.txt >drivers.sgml
messages: .phony
xgettext -k_ -k_s $(shell find .. -name '*.c')
@ -16,6 +24,9 @@ messages: .phony
distclean: clean
rm -f *.html *.txt
rm -rf locale
rm -rf html
rm -rf man
rm -f drivers.sgml funcref.sgml
clean:
for i in messages $(locales);do \

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
all: drivers.sgml funcref.sgml
-mkdir -p html
-mkdir -p man
-docbook2html -o html comedilib.sgml
-docbook2man -o man comedilib.sgml
funcref.sgml: funcref mkref
./mkref funcref >funcref.sgml
drivers.sgml: drivers.txt mkdr
./mkdr drivers.txt >drivers.sgml
clean:
-rm -rf html
-rm -rf man
-rm -f drivers.sgml funcref.sgml

View file

@ -1,66 +0,0 @@
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook V3.1//EN"
"docbook/dtd/3.1/docbook.dtd" [
<!ENTITY intro SYSTEM "intro.sgml">
<!ENTITY install SYSTEM "install.sgml">
<!ENTITY tutorial SYSTEM "tutorial.sgml">
<!ENTITY other SYSTEM "other.sgml">
<!ENTITY drivers SYSTEM "drivers.sgml">
<!ENTITY reference SYSTEM "reference.sgml">
<!ENTITY funcref SYSTEM "funcref.sgml">
]>
<article>
<artheader>
<title>
Comedi Documentation
</title>
<author>
<firstname>David</firstname>
<surname>Schleef</surname>
<affiliation>
<address>
ds@schleef.org
</address>
</affiliation>
</author>
<author>
<firstname>Frank</firstname>
<surname>Hess</surname>
<affiliation>
<address>
fmhess@uiuc.edu
</address>
</affiliation>
</author>
</artheader>
&intro
&install
&tutorial
&other
&drivers
<section>
<title>
Comedi Reference
</title>
<para>
Reference for functions, macros, and constants.
</para>
&reference
&funcref
</section>
</article>

File diff suppressed because it is too large Load diff

View file

@ -1,430 +0,0 @@
Comedi tutorial
0. Compiling and Installing
0. Insmod'ding the kernel module
0. Configuring comedi to use your hardware
0. Getting information from comedi
0. Your first comedi program
0. Converting samples to voltages
0. Compiling and Installing
needs to be written
0. Insmod'ding the kernel module
needs to be written
0. Configuring comedi to use your hardware
I assume that your hardware device is in your computer, and that
you know the relevant details about it, i.e., what kind of card
it is, the I/O base, the IRQ, jumper settings related to input
ranges, etc.
To tell the comedi kernel module that you have a particular device, and
some information about it, you will be running the 'comedi_config'
command. Perhaps you should read the man page now.
For this tutorial, I have two devices, a National Instruments AT-MIO-16E-10
and a Data Translation DT2821-F-8DI.
The NI board is plug-and-play, and the man page tells me that I need
to configure the PnP part of the board with isapnptools. The isapnptools
package is a little cryptic, but the concepts are simple. Once I
learned how to use it, I settled on a /etc/isapnp.conf file that
contained the lines:
# ANSI string -->National Instruments, AT-MIO-16E-10<--
(CONFIGURE NIC2400/10725401 (LD 0
(IO 0 (BASE 0x0260))
(INT 0 (IRQ 3 (MODE +E)))
# (DMA 0 (CHANNEL 5))
# (DMA 1 (CHANNEL 6))
(ACT Y)
))
It also contains a few lines about overall configuration and about my
sound card. I found out after a bit of trial-and-error that the NI
board does not always work with interrupts other than IRQ 3. YMMV.
Currently, the driver doesn't use DMA, but it may in the future, so
I commented out the DMA lines. It is a curious fact that the device
ignores the IRQ and DMA information given here, however, I keep the
information here to remind myself that the numbers aren't arbitrary.
When I run comedi_config (as root, of course), I provide the same
information. Since I want to have the board configured every time
I boot, I put the line
/usr/sbin/comedi_config /dev/comedi0 atmio-E 0x260,3
into /etc/rc.d/rc.local. You can, of course, run this command at
a command prompt. The man page tells me that the option list
is supposed to be "<I/O base>,<IRQ>", so I used the same numbers
as I put in /etc/isapnp.conf, i.e., 0x260,3.
For the Data Translation board, I need to have a list of the
jumper settings. Fortunately, I wrote them all down in the
manual -- I hope they are still correct. However, I had to
open the case to figure out which board in the series I had.
It is a DT2821-f-8di. The man page of comedi_config tells
me that I need to know the I/O base, IRQ, DMA 1, DMA 2. However,
since I wrote the driver, I know that it also recognizes the
differential/single-ended and unipolar/bipolar jumpers. As always,
the source is the final authority, and looking in module/dt282x.c
tells me that the options list is interpreted as:
i/o base
irq
1=differential, 0=single ended
ai 0=unipolar, 1=bipolar
ao0 0=unipolar, 1=bipolar
ao1 0=unipolar, 1=bipolar
dma1
dma2
(ai=analog input, ao=analog output.) From this, I decide that
the appropriate options list is
0x200,4,,1,1,1
I left the differential/single-ended number blank, since the
driver already knowns (from the board name), that it is
differential. I also left the DMA numbers blank, since I
don't want the driver to use DMA. (Don't want it to interfere
with my sound card -- life is full of difficult choices.)
Keep in mind that things commented in the source, but not in
the documentation are about as likely to change as the weather,
so I put good comments next to the following line when I put
it in rc.local.
/usr/sbin/comedi_config /dev/comedi1 dt2821-f-8di 0x200,4,,1,1,1
So now I think that I have my boards configured correctly.
Since data acquisition boards are not typically well-engineered,
comedi sometimes can't figure out if the board is actually there.
If it can't, it assumes you are right. Both of these boards
are well-made, so comedi will give me an error message if it
can't find them. The comedi kernel module, since it is a part
of the kernel, prints messages to the kernel logs, which you
can access through the command 'dmesg' or /var/log/messages.
Here is a configuration failure (from dmesg):
comedi0: ni_E: 0x0200 can't find board
When it does work, I get:
comedi0: ni_E: 0x0260 at-mio-16e-10 ( irq = 3 )
Note that it also correctly identified my board.
0. Getting information from comedi
So now that we have comedi talking to the hardware, we want to
talk to comedi. Here's some pretty low-level information --
it's sometimes useful for debugging:
cat /proc/comedi
Right now, on my computer, this command gives:
comedi version 0.6.4
format string
0: atmio-E at-mio-16e-10 7
1: dt282x dt2821-f-8di 4
This is a feature that is not well-developed yet. Basically, it
currently tells you driver name, device name, and number of
subdevices.
In the demo/ directory, there is a command called
'info', which provides information about each subdevice on the
board. The output of it is rather long, since I have 7
subdevices (4 or fewer is more common.)
Here's part of the output of the NI board (which
is on /dev/comedi0.) ('demo/info /dev/comedi0')
overall info:
version code: 0x000604
driver name: atmio-E
board name: at-mio-16e-10
number of subdevices: 7
subdevice 0:
type: 1 (unknown)
number of channels: 16
max data value: 4095
The overall info gives information about the device -- basically
the same information as /proc/comedi.
This board has 7 subdevices. Devices are separated into
subdevices that each have a distinct purpose -- e.g., analog
input, analog output, digital input/output. This board also
has an EEPROM and calibration DACs that are also subdevices.
Subdevice 0 is the analog input subdevice. You would have
known this from the 'type: 1 (unknown)' line, if I've updated
demo/info recently, because it would say 'type: 1 (analog input)'
instead. The other lines should be self-explanitory. Comedi
has more information about the device, but demo/info doesn't
currently display this.
0. Your first comedi program
This example requires a card that has analog or
digital input. Right to the source:
#include <stdio.h> /* for printf() */
#include <comedilib.h>
int subdev = 0; /* change this to your input subdevice */
int chan = 0; /* change this to your channel */
int range = 0; /* more on this later */
int aref = AREF_GROUND; /* more on this later */
int main(int argc,char *argv[])
{
comedi_t *it;
int chan=0;
lsampl_t data;
it=comedi_open("/dev/comedi0");
comedi_data_read(it,subdev,chan,range,aref,&data);
printf("%d\n",data);
return 0;
}
Should be understandable. Open the device, get the data,
print it out. This is basically the guts of demo/inp.c,
without error checking or fancy options. Including all
the appropriate headers is sometimes a little tricky.
Compile it using 'cc tut1.c -lcomedi -o tut1'. Hopefully
it works.
A few notes: The range variable tells comedi which gain
to use when measuring an analog voltage. Since we don't
know (yet) which numbers are valid, or what each means,
we'll use 0, because it won't cause errors. Likewise with
aref, which determines the analog reference used.
0. Converting samples to voltages
If you selected an analog input subdevice, you should notice
that the output of tut1 is a number between
0 and 4095, or 0 and 65535, depending on the number of bits
in the A/D converter. Comedi samples are *always* unsigned,
with 0 representing the lowest voltage of the ADC, and 4095
the highest. The hardware driver compensates for
anything else the manual for your device says. However,
you probably prefer to have this number translated to
a voltage. Naturally, as a good programmer, your first
question is: "How do I do this in a device-independent
manner?"
For each subdevice, the comedi kernel module keeps a
'range_type' variable. This variable contains the number
of available ranges (i.e., gains) that you can select,
along with an offset in a list of range information
structures. If you know the range_type variable, you
can use these macros:
RANGE_OFFSET(range_type)
RANGE_LENGTH(range_type)
to extract such information. However, you want the
actual voltage information, not some integer offset
in a table. Rather than messing with the library
internals, use the function
ptr=comedi_get_range(comedi_file,subdevice,channel,
range)
which returns a pointer to a comedi_range structure.
The comedi_range structure looks like
typedef struct{
double min;
double max;
unsigned int unit;
}comedi_range;
The element 'min' represents the voltage corresponding to
comedi_data_read() returning 0, and 'max' represents
comedi_data_read() returning 'maxdata', (i.e., 4095 for 12
bit A/C converters, 65535 for 16 bit, or, 1 for digital input
-- more on this in a bit.) The 'unit' entry tells you if min and
max refer to voltage, current, etc.
"Could it get easier?", you say. Well, yes. Use
the function comedi_to_phys(), which converts data
values to physical units. Call it using something like
volts=comedi_to_phys(it,data,range,maxdata);
and the opposite
data=comedi_from_phys(it,volts,range,maxdata);
You probably noticed (and were worried) that we haven't
discussed how to determine maxdata and range_type. Well,
you could ask the kernel this information each time you need
it, but since there are other variables, special cases,
and several subdevices to worry about, it would be nice
if the library could take care of this... (read on...)
0.
In addition to providing low level routines for data
access, the comedi library provides higher-level access,
much like the standard C library provides fopen(), etc.
as a high-level (and portable) alternative to the direct
UNIX system calls open(), etc. Similarily to fopen(),
we have comedi_open():
file=comedi_open("/dev/comedi0");
where file is of type (comedi_t *). This function
calls open(), like we did explicitly in a previous
section, but also fills the comedi_t structure with
lots of goodies -- information that we will need to use
soon.
Specifically, we needed to know maxdata for a specific
subdevice/channel. How about:
maxdata=comedi_get_maxdata(file,subdevice,channel);
Wow. How easy. And the range type?
range_type=comedi_get_rangetype(file,subdevice,channel);
Cool. Other information you need to know about a channel
can be gotten in a similar way.
0. Your second comedi program
Actually, this is the first comedi program again, just
that we've added what we've learned.
#include <stdio.h> /* for printf() */
#include <comedi.h> /* also included by comedilib.h */
#include <comedilib.h> /* for comedi_get() */
int subdev = 0; /* change this to your input subdevice */
int chan = 0; /* change this to your channel */
int range = 0; /* more on this later */
int aref = 0; /* more on this later */
int main(int argc,char *argv[])
{
comedi_t *cf;
int chan=0;
int data;
int maxdata,rangetype;
double volts;
cf=comedi_open("/dev/comedi0");
maxdata=comedi_get_maxdata(cf,subdev,chan);
rangetype=comedi_get_rangetype(cf,subdev,chan);
data=comedi_get(cf->fd,subdev,chan,range,aref);
volts=comedi_to_phys(data,rangetype,range,maxdata);
printf("%d %g\n",data,volts);
return 0;
}
By now, the comedi_read_data() line looks a little archaic, using
the UNIX file descriptor cf->fd instead of just cf. (By the
way, somewhere in the heart of comedi_open() is the line
cf->fd=open(filename,O_RDWR).) Well, there isn't one good
replacement, since it highly depends on your application
what additional features you might want in a comedi_get()
replacement. But this is the topic of a different section.
0. stuff
0. Slowly-varying inputs
Sometimes, your input channels change slowly enough that
you are able to average many sucessive input values to get a
more accurate measurement of the actual value. In general,
the more samples you average, the better your estimate
gets, roughly by a factor of sqrt(number_of_samples).
Obviously, there are limitations to this:
- you are ultimately limited by "spurious free dynamic range"
- you need to have _some_ noise on the input channel,
otherwise you will be averaging the same number N times.
- the more noise you have, the greater your SFDR, but it
takes many more samples to compensate for the increased
noise
- if you feel the need to average samples for 2 seconds,
your signal will need to be _very_ slowly-varying, i.e.,
not varying more than your target uncertainty for the
entire 2 seconds.
As you might have guessed, the comedi library has functions
to help you in your quest to accurately measure slowly varying
inputs. I use these functions to measure thermocouple voltages
-- actually, the library functions came from a section of code
that was previously part of the thermocouple reading program.
The comedi self-calibration utility also uses these functions.
On some hardware, it is possible to tell it to measure an
internal stable voltage reference, which is typically going
to be very slowly varying -- on the kilosecond time scale
or more. So it is reasonable to measure millions of samples,
to get a very accurate measurement of the A/D converter output
value that corresponds to the voltage reference. Sometimes,
however, this is overkill, since there is no need to
perform a part-per-million calibration to a standard that
is only accurate to part-per-thousand.