It doesn't make sense to keep regenerating these in CVS. They are
generated in the release script now.
This commit is contained in:
parent
76e6cf0404
commit
646587b1ea
8 changed files with 0 additions and 3719 deletions
|
@ -1,24 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.8.1">
|
||||
<TITLE>Comedi Documentation: Introduction</TITLE>
|
||||
<LINK HREF="comedilib-2.html" REL=next>
|
||||
|
||||
<LINK HREF="comedilib.html#toc1" REL=contents>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<A HREF="comedilib-2.html">Next</A>
|
||||
Previous
|
||||
<A HREF="comedilib.html#toc1">Contents</A>
|
||||
<HR>
|
||||
<H2><A NAME="s1">1.</A> <A HREF="comedilib.html#toc1">Introduction</A></H2>
|
||||
|
||||
<P>This is preliminary documentation for Comedi and Comedilib.</P>
|
||||
|
||||
<HR>
|
||||
<A HREF="comedilib-2.html">Next</A>
|
||||
Previous
|
||||
<A HREF="comedilib.html#toc1">Contents</A>
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -1,241 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.8.1">
|
||||
<TITLE>Comedi Documentation: Installation and configuration</TITLE>
|
||||
<LINK HREF="comedilib-3.html" REL=next>
|
||||
<LINK HREF="comedilib-1.html" REL=previous>
|
||||
<LINK HREF="comedilib.html#toc2" REL=contents>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<A HREF="comedilib-3.html">Next</A>
|
||||
<A HREF="comedilib-1.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc2">Contents</A>
|
||||
<HR>
|
||||
<H2><A NAME="s2">2.</A> <A HREF="comedilib.html#toc2">Installation and configuration</A></H2>
|
||||
|
||||
|
||||
<P>This section covers compiling, installing, and configuring
|
||||
comedi and comedlib.</P>
|
||||
|
||||
|
||||
<H2><A NAME="ss2.1">2.1 Compiling and Installing</A>
|
||||
</H2>
|
||||
|
||||
|
||||
<P>This section has not been written.</P>
|
||||
|
||||
|
||||
<H2><A NAME="ss2.2">2.2 Insmod'ding the kernel module</A>
|
||||
</H2>
|
||||
|
||||
|
||||
<P>This section has not been written.</P>
|
||||
|
||||
|
||||
<H2><A NAME="ss2.3">2.3 Configuring comedi for your hardware</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
<P>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.</P>
|
||||
<P>To tell the comedi kernel module that you have a particular device, and
|
||||
some information about it, you will be running the <CODE>comedi_config</CODE>
|
||||
command. Perhaps you should read the man page now.</P>
|
||||
<P>In this tutorial, I will go through the process of configuring comedi
|
||||
for two devices, a National Instruments AT-MIO-16E-10
|
||||
and a Data Translation DT2821-F-8DI.</P>
|
||||
<P>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:</P>
|
||||
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
# 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)
|
||||
))
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
|
||||
<P>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.</P>
|
||||
<P>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</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
/usr/sbin/comedi_config /dev/comedi0 atmio-E 0x260,3
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>into <CODE>/etc/rc.d/rc.local</CODE>. 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.</P>
|
||||
<P>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:</P>
|
||||
<P>
|
||||
<UL>
|
||||
<LI>I/O base</LI>
|
||||
<LI>IRQ</LI>
|
||||
<LI>1=differential, 0=single ended</LI>
|
||||
<LI>ai 0=unipolar, 1=bipolar</LI>
|
||||
<LI>ao0 0=unipolar, 1=bipolar</LI>
|
||||
<LI>ao1 0=unipolar, 1=bipolar</LI>
|
||||
<LI>dma1</LI>
|
||||
<LI>dma2</LI>
|
||||
</UL>
|
||||
</P>
|
||||
<P>(ai=analog input, ao=analog output.) From this, I decide that
|
||||
the appropriate options list is</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
0x200,4,,1,1,1
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>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.</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
/usr/sbin/comedi_config /dev/comedi1 dt2821-f-8di 0x200,4,,1,1,1
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>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):</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
comedi0: ni_E: 0x0200 can't find board
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>When it does work, I get:</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
comedi0: ni_E: 0x0260 at-mio-16e-10 ( irq = 3 )
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>Note that it also correctly identified my board.</P>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss2.4">2.4 Getting information from comedi</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
<P>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:</P>
|
||||
|
||||
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
cat /proc/comedi
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>Right now, on my computer, this command gives:</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
comedi version 0.6.4
|
||||
format string
|
||||
0: atmio-E at-mio-16e-10 7
|
||||
1: dt282x dt2821-f-8di 4
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>This is a feature that is not well-developed yet. Basically, it
|
||||
currently tells you driver name, device name, and number of
|
||||
subdevices.</P>
|
||||
<P>In the <CODE>demo/</CODE> directory, there is a command called
|
||||
<CODE>info</CODE>, 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 common for other boards.)
|
||||
Here's part of the output of the NI board (which
|
||||
is on <CODE>/dev/comedi0</CODE>.) ('demo/info /dev/comedi0')</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
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
|
||||
</PRE>
|
||||
|
||||
...
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>The overall info gives information about the device -- basically
|
||||
the same information as /proc/comedi.</P>
|
||||
<P>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.</P>
|
||||
<P>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.</P>
|
||||
|
||||
|
||||
<HR>
|
||||
<A HREF="comedilib-3.html">Next</A>
|
||||
<A HREF="comedilib-1.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc2">Contents</A>
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -1,40 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.8.1">
|
||||
<TITLE>Comedi Documentation: Individual drivers</TITLE>
|
||||
<LINK HREF="comedilib-4.html" REL=next>
|
||||
<LINK HREF="comedilib-2.html" REL=previous>
|
||||
<LINK HREF="comedilib.html#toc3" REL=contents>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<A HREF="comedilib-4.html">Next</A>
|
||||
<A HREF="comedilib-2.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc3">Contents</A>
|
||||
<HR>
|
||||
<H2><A NAME="s3">3.</A> <A HREF="comedilib.html#toc3">Individual drivers</A></H2>
|
||||
|
||||
|
||||
<P>This section contains information that is specific to each
|
||||
hardware driver. The most current information about a driver
|
||||
is included in the comedi source.</P>
|
||||
|
||||
<H2><A NAME="ss3.1">3.1 National Instruments AT-MIO E series</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss3.2">3.2 Data Translation</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<HR>
|
||||
<A HREF="comedilib-4.html">Next</A>
|
||||
<A HREF="comedilib-2.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc3">Contents</A>
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -1,247 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.8.1">
|
||||
<TITLE>Comedi Documentation: Writing programs that use comedi and comedilib</TITLE>
|
||||
<LINK HREF="comedilib-5.html" REL=next>
|
||||
<LINK HREF="comedilib-3.html" REL=previous>
|
||||
<LINK HREF="comedilib.html#toc4" REL=contents>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<A HREF="comedilib-5.html">Next</A>
|
||||
<A HREF="comedilib-3.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc4">Contents</A>
|
||||
<HR>
|
||||
<H2><A NAME="s4">4.</A> <A HREF="comedilib.html#toc4">Writing programs that use comedi and comedilib</A></H2>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss4.1">4.1 Your first comedi program</A>
|
||||
</H2>
|
||||
|
||||
|
||||
<P>This example requires a card that has analog or
|
||||
digital input. Right to the source:</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
#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;
|
||||
lsampl_t data;
|
||||
|
||||
it=comedi_open("/dev/comedi0");
|
||||
|
||||
comedi_data_read(it,subdev,chan,range,aref,&data);
|
||||
|
||||
printf("%d\n",data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
|
||||
<P>Should be understandable: open the device, get the data,
|
||||
print it out. This is basically the guts of <CODE>demo/inp.c</CODE>,
|
||||
without error checking or fancy options.
|
||||
Compile it using</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
cc tut1.c -lcomedi -o tut1
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>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.</P>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss4.2">4.2 Converting samples to voltages</A>
|
||||
</H2>
|
||||
|
||||
|
||||
<P>If you selected an analog input subdevice, you probably noticed
|
||||
that the output of <CODE>tut1</CODE> 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 <B>always</B> unsigned,
|
||||
with 0 representing the lowest voltage of the ADC, and 4095
|
||||
the highest. Comedi 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?"</P>
|
||||
<P>Most devices give you a choice of gain and unipolar/bipolar
|
||||
input, and Comedi allows you to select which of these to
|
||||
use. This parameter is called the "range parameter", since
|
||||
it specifies the "input range" for analog input (or "output range"
|
||||
for analog output.) The range parameter represents both the gain
|
||||
and the unipolar/bipolar aspects.</P>
|
||||
<P>Comedi keeps the number of available ranges and the largest
|
||||
sample value for each subdevice/channel combination. (Some
|
||||
devices allow different input/output ranges for different
|
||||
channels in a subdevice.)</P>
|
||||
<P>The largest sample value can be found using the function:</P>
|
||||
<P>comedi_get_maxdata()</P>
|
||||
<P>The number of available ranges can be found using the function:</P>
|
||||
<P>comedi_get_n_ranges()</P>
|
||||
<P>For each value of the range parameter for a particular
|
||||
subdevice/channel, you can get range information using the
|
||||
function:</P>
|
||||
<P>ptr=comedi_get_range(comedi_file,subdevice,channel,
|
||||
range)</P>
|
||||
<P>which returns a pointer to a comedi_range structure.
|
||||
The comedi_range structure looks like</P>
|
||||
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
typedef struct{
|
||||
double min;
|
||||
double max;
|
||||
unsigned int unit;
|
||||
}comedi_range;
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>The structure 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.</P>
|
||||
<P>"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</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
volts=comedi_to_phys(it,data,range,maxdata);
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>and the opposite</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
data=comedi_from_phys(it,volts,range,maxdata);
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss4.3">4.3 Another section</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
<P>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():</P>
|
||||
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
file=comedi_open("/dev/comedi0");
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>where file is of type <CODE>(comedi_t *)</CODE>. This function
|
||||
calls <CODE>open()</CODE>, like we did explicitly in a previous
|
||||
section, but also fills the <CODE>comedi_t</CODE> structure with
|
||||
lots of goodies -- information that we will need to use
|
||||
soon. </P>
|
||||
<P>Specifically, we needed to know maxdata for a specific
|
||||
subdevice/channel. How about:</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
maxdata=comedi_get_maxdata(file,subdevice,channel);
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>Wow. How easy. And the range type?</P>
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
range_type=comedi_get_rangetype(file,subdevice,channel);
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
<P>Cool. Other information you need to know about a channel
|
||||
can be gotten in a similar way.</P>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss4.4">4.4 Your second comedi program</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
<P>Actually, this is the first comedi program again, just
|
||||
that we've added what we've learned.</P>
|
||||
|
||||
<P>
|
||||
<BLOCKQUOTE><CODE>
|
||||
<PRE>
|
||||
#include <stdio.h> /* for printf() */
|
||||
#include <comedi.h> /* also included by comedilib.h */
|
||||
#include <comedilib.h> /* 'cuz we're using comedilib */
|
||||
|
||||
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;
|
||||
lsampl_t 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);
|
||||
|
||||
comedi_data_read(cf->fd,subdev,chan,range,aref,&data);
|
||||
|
||||
volts=comedi_to_phys(data,rangetype,range,maxdata);
|
||||
|
||||
printf("%d %g\n",data,volts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
</PRE>
|
||||
</CODE></BLOCKQUOTE>
|
||||
</P>
|
||||
|
||||
|
||||
|
||||
<HR>
|
||||
<A HREF="comedilib-5.html">Next</A>
|
||||
<A HREF="comedilib-3.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc4">Contents</A>
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -1,262 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.8.1">
|
||||
<TITLE>Comedi Documentation: Application-specific functions</TITLE>
|
||||
<LINK HREF="comedilib-6.html" REL=next>
|
||||
<LINK HREF="comedilib-4.html" REL=previous>
|
||||
<LINK HREF="comedilib.html#toc5" REL=contents>
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<A HREF="comedilib-6.html">Next</A>
|
||||
<A HREF="comedilib-4.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc5">Contents</A>
|
||||
<HR>
|
||||
<H2><A NAME="s5">5.</A> <A HREF="comedilib.html#toc5">Application-specific functions</A></H2>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss5.1">5.1 Digital Input/Output</A>
|
||||
</H2>
|
||||
|
||||
|
||||
<P>Many boards supported by comedi have digital input and output
|
||||
channels. Some boards allow the direction of a channel to be
|
||||
specified in software.</P>
|
||||
<P>Comedi groups digital channels into subdevice, which is a group
|
||||
of digital channels that have the same characteristics. For
|
||||
example, digital output lines will be grouped into a digital
|
||||
output subdevice, bidirectional digital lines will be grouped
|
||||
into a digital I/O subdevice. Thus, there can be multiple
|
||||
digital subdevices on a particular board.</P>
|
||||
<P>Individual digital lines can be read and written using the
|
||||
functions</P>
|
||||
<P><CODE>comedi_dio_read(device,subdevice,channel,unsigned int *bit);</CODE>
|
||||
<CODE>comedi_dio_write(device,subdevice,channel,unsigned int bit);</CODE></P>
|
||||
<P>The direction of bidirectional lines can be configured using
|
||||
the function</P>
|
||||
<P><CODE>comedi_dio_config(device,subdevice,channel,unsigned int dir);</CODE></P>
|
||||
<P>The parameter <CODE>dir</CODE> should be either COMEDI_INPUT or COMEDI_OUTPUT.
|
||||
Many digital I/O subdevices group channels into blocks for
|
||||
configuring direction. Changing one channel in a block changes
|
||||
the entire block.</P>
|
||||
<P>Multiple channels can be read and written simultaneously using the
|
||||
function</P>
|
||||
<P><CODE>comedi_dio_bitfield(device,subdevice,unsigned int write_mask,unsigned int *bits);</CODE></P>
|
||||
<P>Each channel is assigned to a bit in the <CODE>write_mask</CODE> and <CODE>bits</CODE>
|
||||
bitfield. If a bit in <CODE>write_mask</CODE> is set, the corresponding bit
|
||||
in <CODE>*bits</CODE> will be written to the corresponding digital output line.
|
||||
Each digital line is then read and placed into <CODE>*bits</CODE>. The value
|
||||
of bits in <CODE>*bits</CODE> corresponding to digital output lines is
|
||||
undefined and device-specific. Channel 0 is the least significant
|
||||
bit in the bitfield; channel 31 is the most significant bit. Channels
|
||||
higher than 31 cannot be accessed using this method.</P>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="ss5.2">5.2 Slowly-varying inputs</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
<P>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:</P>
|
||||
|
||||
<P>
|
||||
<UL>
|
||||
<LI>you are ultimately limited by "spurious free dynamic range"
|
||||
</LI>
|
||||
<LI>you need to have _some_ noise on the input channel,
|
||||
otherwise you will be averaging the same number N times.
|
||||
</LI>
|
||||
<LI>the more noise you have, the greater your SFDR, but it
|
||||
takes many more samples to compensate for the increased
|
||||
noise
|
||||
</LI>
|
||||
<LI>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.
|
||||
</LI>
|
||||
</UL>
|
||||
</P>
|
||||
<P>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.</P>
|
||||
<P>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.</P>
|
||||
|
||||
|
||||
|
||||
<H2><A NAME="command_section"></A> <A NAME="ss5.3">5.3 Commands</A>
|
||||
</H2>
|
||||
|
||||
|
||||
|
||||
<P>Many data acquisition devices have the capability to directly
|
||||
control acquisition using either an on-board timer or an external
|
||||
triggering input. Comedi commands are used to control this kind
|
||||
of acquisition. The
|
||||
<A HREF="comedilib-6.html#comedi_cmd">comedi_cmd</A> structure is
|
||||
used to control acquisition and query the capabilities of a device
|
||||
(see also
|
||||
<A HREF="comedilib-6.html#comedi_command">comedi_command()</A>,
|
||||
<A HREF="comedilib-6.html#comedi_command_test">comedi_command_test()</A>, and
|
||||
<A HREF="comedilib-6.html#comedi_get_cmd_src_mask">comedi_get_cmd_src_mask()</A>).</P>
|
||||
<P>Commands specify a particular data acquisition sequence, which
|
||||
is comprised of a number of scans. Each scan is comprised of
|
||||
a number of conversions, which usually corresponds to a single
|
||||
A/D or D/A conversion. The start and end of the sequence, and
|
||||
the start and end of each scan, and each conversion is called an
|
||||
event.</P>
|
||||
<P>Each of these 5 types of events are caused by a triggering
|
||||
source, specified through the <CODE>*_src</CODE> members of the
|
||||
<A HREF="comedilib-6.html#comedi_cmd">comedi_cmd</A> structure. The source types are:</P>
|
||||
<P>
|
||||
<UL>
|
||||
<LI>TRIG_NONE: don't ever cause an event</LI>
|
||||
<LI>TRIG_NOW: cause event to occur immediately</LI>
|
||||
<LI>TRIG_FOLLOW: see notes below</LI>
|
||||
<LI>TRIG_TIME: cause event to occur at a particular time</LI>
|
||||
<LI>TRIG_TIMER: cause event to occur repeatedly at a specific rate</LI>
|
||||
<LI>TRIG_COUNT: cause event when count reaches specific value</LI>
|
||||
<LI>TRIG_EXT: external signal causes event</LI>
|
||||
<LI>TRIG_INT: internal signal causes event</LI>
|
||||
<LI>TRIG_OTHER: driver-specific meaning</LI>
|
||||
</UL>
|
||||
</P>
|
||||
<P>Not all triggers are applicable to all events. Supported triggers
|
||||
for specific events depend significantly on your particular
|
||||
device. The
|
||||
<A HREF="comedilib-6.html#comedi_get_cmd_src_mask">comedi_get_cmd_src_mask()</A>
|
||||
function is useful for determining what triggers a subdevice supports.</P>
|
||||
<P>For every trigger, there is a corresponding
|
||||
argument (the <CODE>*_arg</CODE> members of the
|
||||
<A HREF="comedilib-6.html#comedi_cmd">comedi_cmd</A>
|
||||
structure) whose meaning depends on the type of trigger. The meanings
|
||||
of the arguments are as follows:</P>
|
||||
<P>TRIG_NONE is typically used only as a <CODE>stop_src</CODE>. The argument for TRIG_NONE
|
||||
is reserved and should be set to 0.</P>
|
||||
<P>TRIG_NOW is most often used as a <CODE>start_src</CODE>. The argument for TRIG_NOW is
|
||||
the number of nanoseconds between when the command is issued and when
|
||||
the event should occur. In the case of using TRIG now as a <CODE>start_src</CODE>,
|
||||
it indicates a delay between issuing the command and the start of
|
||||
acquisition. Most drivers only support a delay of 0.</P>
|
||||
<P>TRIG_FOLLOW is a special type of trigger for events that trigger on
|
||||
the completion of some other, logically connected event. The argument
|
||||
is reserved and should be set to 0. When used
|
||||
as a <CODE>scan_begin_src</CODE>, it indicates that a trigger should occur as a
|
||||
logical continuation of convert events. This is done in order to
|
||||
properly describe boards that do not have separate timers for
|
||||
convert and scan_begin events. When used as a <CODE>start_src</CODE> for analog
|
||||
output subdevices, it indicates that conversion of output samples
|
||||
should begin when samples are written to the buffer.</P>
|
||||
<P>TRIG_TIME is reserved for future use.</P>
|
||||
<P>TRIG_TIMER is most often used as a <CODE>convert_src</CODE>, a <CODE>scan_begin_src</CODE>, or
|
||||
both. It indicates that triggers should occur at a specific rate.
|
||||
The argument specifies the interval between triggers in nanoseconds.</P>
|
||||
<P>TRIG_COUNT is used for <CODE>scan_end_src</CODE> and <CODE>stop_src</CODE>. It indicates that
|
||||
a trigger should occur when the specified number of corresponding
|
||||
lower-level triggers (convert and scan_begin, respectively) occur.
|
||||
The argument is the count of lower-level triggers.</P>
|
||||
<P>TRIG_EXT can be useful as any of the trigger sources. It indicates
|
||||
that an external digital line should be used to trigger the event.
|
||||
The exact meaning of digital line is device-dependent. Some devices
|
||||
have one dedicated line, others may allow generic digital input
|
||||
lines to be used. The argument indicates the particular external
|
||||
line to use as the trigger.</P>
|
||||
<P>TRIG_INT is typically used as a <CODE>start_src</CODE>. This trigger occurs when
|
||||
the application performs an INSN_INTTRIG instruction. Using TRIG_INT
|
||||
is a method by which the application can accurately record the time of
|
||||
the start of acquisition, since the parsing and setup time of a
|
||||
particular command may be significant. The argument associated with
|
||||
TRIG_INT is reserved and should be set to 0.</P>
|
||||
<P>TRIG_OTHER can be useful as any of the trigger sources. The exact
|
||||
meaning of TRIG_OTHER is driver-specific, and implements a feature
|
||||
that otherwise does not fit into the command interface. Configuration
|
||||
of TRIG_OTHER features are done by INSN_CONFIG insns. The argument
|
||||
is reserved and should be set to 0.</P>
|
||||
<P>Ths <CODE>subdev</CODE> member of the
|
||||
<A HREF="comedilib-6.html#comedi_cmd">comedi_cmd</A>
|
||||
structure is the index of the subdevice the command is intended for. The
|
||||
<A HREF="comedilib-6.html#comedi_find_subdevice_by_type">comedi_find_subdevice_by_type()</A>
|
||||
function can be useful in discovering the index of your desired subdevice.</P>
|
||||
<P>The <CODE>chanlist</CODE> member of the
|
||||
<A HREF="comedilib-6.html#comedi_cmd">comedi_cmd</A>
|
||||
structure should point to an array whose number of elements is specificed by <CODE>chanlist_len</CODE>
|
||||
(this will generally be the same as the scan_end_arg).
|
||||
The chanlist specifies the sequence of channels and gains (and analog references)
|
||||
that should be stepped through for each scan. The elements of the chanlist array
|
||||
should be initialized by packing the channel, range and reference information
|
||||
together with the
|
||||
<A HREF="comedilib-6.html#CR_PACK">CR_PACK()</A> macro.</P>
|
||||
<P>The <CODE>data</CODE> and <CODE>data_len</CODE> members can be safely ignored when issueing commands
|
||||
from a user-space program. They only have meaning when a command is sent from a kernel
|
||||
module using the kcomedilib interface, in which case they specify the buffer where
|
||||
the driver should write/read its data to/from.</P>
|
||||
<P>The final member of the
|
||||
<A HREF="comedilib-6.html#comedi_cmd">comedi_cmd</A> structure is <CODE>flags</CODE>.
|
||||
The following flags are valid, and can be bitwise-or'd together.</P>
|
||||
<P>
|
||||
<UL>
|
||||
<LI>TRIG_BOGUS: do the motions??</LI>
|
||||
<LI>TRIG_DITHER: enable dithering??</LI>
|
||||
<LI>TRIG_DEGLITCH: enable deglitching??</LI>
|
||||
<LI>TRIG_RT: ask driver to use a hard real-time interrupt handler. This will
|
||||
reduce latency in handling interrupts from your data aquisition hardware. It can
|
||||
be useful if you are sampling at high frequency, or if your hardware has a small onboard
|
||||
fifo. You must have a real-time kernel (RTAI or RTLinux) and must compile
|
||||
comedi with real-time support or this flag will do nothing.</LI>
|
||||
<LI>TRIG_CONFIG: perform configuration, not triggering. This is a legacy of the
|
||||
deprecated comedi_trig_struct, and has no function at present.</LI>
|
||||
<LI>TRIG_WAKE_EOS: some drivers will change their behaviour when this flag is set,
|
||||
trying to transfer data at the end of every scan (instead of, for example, passing
|
||||
data in chunks whenever the board's onboard fifo is half full). This flag
|
||||
may degrade a driver's performance at high frequencies.</LI>
|
||||
<LI>TRIG_WRITE: write to bidirectional devices. Could be useful in principle, if someone
|
||||
wrote a driver that supported commands for a digital i/o device that could do either
|
||||
input or output.</LI>
|
||||
</UL>
|
||||
|
||||
There are also a few flags that indicate how timing arguments should be rounded
|
||||
if the hardware cannot achieve the exact timing requested.
|
||||
<UL>
|
||||
<LI>TRIG_ROUND_NEAREST: round to nearest supported timing period, the default.</LI>
|
||||
<LI>TRIG_ROUND_DOWN: round period down.</LI>
|
||||
<LI>TRIG_ROUND_UP: round period up.</LI>
|
||||
<LI>TRIG_ROUND_UP_NEXT: this one doesn't do anything, and I don't know what it was intended
|
||||
to do??</LI>
|
||||
</UL>
|
||||
</P>
|
||||
|
||||
|
||||
<P>The typical sequence for executing a command is to first send
|
||||
the command through
|
||||
<A HREF="comedilib-6.html#comedi_command_test">comedi_command_test()</A>
|
||||
once or twice. The test will check that the command is valid for the particular
|
||||
device, and often makes some adjustments to the command arguments, which
|
||||
can then be read back by the user to see the actual values used. The
|
||||
command is executed with
|
||||
<A HREF="comedilib-6.html#comedi_command">comedi_command()</A>. For input/output commands, data
|
||||
is read from or written to the device file /dev/comedi[0..3] you are using.</P>
|
||||
|
||||
<HR>
|
||||
<A HREF="comedilib-6.html">Next</A>
|
||||
<A HREF="comedilib-4.html">Previous</A>
|
||||
<A HREF="comedilib.html#toc5">Contents</A>
|
||||
</BODY>
|
||||
</HTML>
|
1019
doc/comedilib-6.html
1019
doc/comedilib-6.html
File diff suppressed because it is too large
Load diff
|
@ -1,42 +0,0 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META NAME="GENERATOR" CONTENT="LinuxDoc-Tools 0.9.8.1">
|
||||
<TITLE>Comedi Documentation</TITLE>
|
||||
<LINK HREF="comedilib-1.html" REL=next>
|
||||
|
||||
|
||||
</HEAD>
|
||||
<BODY>
|
||||
<A HREF="comedilib-1.html">Next</A>
|
||||
Previous
|
||||
Contents
|
||||
<HR>
|
||||
<H1>Comedi Documentation</H1>
|
||||
|
||||
<H2>David Schleef <CODE>ds@stm.lbl.gov</CODE>,
|
||||
Frank Hess <CODE>fmhess@uiuc.edu</CODE></H2>
|
||||
<P>
|
||||
<H2><A NAME="toc1">1.</A> <A HREF="comedilib-1.html">Introduction</A></H2>
|
||||
|
||||
<P>
|
||||
<H2><A NAME="toc2">2.</A> <A HREF="comedilib-2.html">Installation and configuration</A></H2>
|
||||
|
||||
<P>
|
||||
<H2><A NAME="toc3">3.</A> <A HREF="comedilib-3.html">Individual drivers</A></H2>
|
||||
|
||||
<P>
|
||||
<H2><A NAME="toc4">4.</A> <A HREF="comedilib-4.html">Writing programs that use comedi and comedilib</A></H2>
|
||||
|
||||
<P>
|
||||
<H2><A NAME="toc5">5.</A> <A HREF="comedilib-5.html">Application-specific functions</A></H2>
|
||||
|
||||
<P>
|
||||
<H2><A NAME="toc6">6.</A> <A HREF="comedilib-6.html">Libcomedi Reference</A></H2>
|
||||
|
||||
<HR>
|
||||
<A HREF="comedilib-1.html">Next</A>
|
||||
Previous
|
||||
Contents
|
||||
</BODY>
|
||||
</HTML>
|
1844
doc/comedilib.txt
1844
doc/comedilib.txt
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue