comedilib/doc/other.xml

2513 lines
87 KiB
XML
Raw Permalink Normal View History

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
<!ENTITY % comedilib_entities SYSTEM "comedilib.ent">
%comedilib_entities;
]>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<section id="acquisitionfunctions">
2002-01-21 15:17:12 +00:00
<title>
2003-07-07 22:34:18 +00:00
Acquisition and configuration functions
2002-01-21 15:17:12 +00:00
</title>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<para>
This Section gives an overview of all &comedi; functions with which
2003-07-07 22:34:18 +00:00
application programmers can implement their data acquisition. (With
<quote>acquisition</quote> we mean all possible kinds of interfacing
2003-07-07 22:34:18 +00:00
with the cards: input, output, configuration, streaming, etc.)
<xref linkend="comedireference"/> explains the function calls in full
2003-07-07 22:34:18 +00:00
detail.
</para>
<section id="singleacquisition">
<title>
Functions for single acquisition
</title>
<para>
The simplest form of using &comedi; is to get one single sample to or
from an interface card. This sections explains how to do such simple
<link linkend="dio">digital</link> and
<link linkend="singleanalog">analog</link> acquisitions.
</para>
<section id="dio">
<title>
Single digital acquisition
</title>
<para>
Many boards supported by &comedi; have digital input and output
channels; i.e., channels that can only produce a <literal>0</literal>
or a <literal>1</literal>.
Some boards allow the <emphasis>direction</emphasis> (input or output)
of each channel to be specified independently in software.
</para>
<para>
&comedi; groups digital channels into a
<emphasis>subdevice</emphasis>, 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.
</para>
<para>
Individual bits on a digital I/O device can be read and written using
the functions <function><link linkend="func-ref-comedi-dio-read">comedi_dio_read</link></function>
and <function><link linkend="func-ref-comedi-dio-write">comedi_dio_write</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_dio_read</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
<paramdef>unsigned int *<parameter>bit</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_dio_write</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
<paramdef>unsigned int <parameter>bit</parameter></paramdef>
</funcprototype></funcsynopsis>
The <parameter class="function">device</parameter> parameter is a
2003-07-07 22:34:18 +00:00
<link linkend="ref-type-comedi-t">pointer</link>
to a successfully opened &comedi; device.
The <parameter class="function">subdevice</parameter> and
<parameter class="function">channel</parameter> parameters are positive
2003-07-07 22:34:18 +00:00
integers that indicate which subdevice and channel is used in the
acquisition. The integer <parameter class="function">bit</parameter>
2003-07-07 22:34:18 +00:00
contains the value of the acquired bit.
</para>
2003-07-07 22:34:18 +00:00
<para>
The direction of bidirectional lines can be configured using the function
<function><link linkend="func-ref-comedi-dio-config">comedi_dio_config</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_dio_config</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
<paramdef>unsigned int <parameter>dir</parameter></paramdef>
</funcprototype></funcsynopsis>
The parameter <parameter class="function">dir</parameter> should be
either <constant>COMEDI_INPUT</constant> or
<constant>COMEDI_OUTPUT</constant>.
2003-07-07 22:34:18 +00:00
Many digital I/O subdevices group channels into blocks for
configuring direction. Changing one channel in a block changes
the entire block.
</para>
<para>
Multiple channels can be read and written simultaneously using the
function <function><link linkend="func-ref-comedi-dio-bitfield2">comedi_dio_bitfield2</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_dio_bitfield2</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>write_mask</parameter></paramdef>
<paramdef>unsigned int *<parameter>bits</parameter></paramdef>
<paramdef>unsigned int <parameter>base_channel</parameter></paramdef>
</funcprototype></funcsynopsis>
Each channel from <parameter class="function">base_channel</parameter>
to <parameter class="function">base_channel</parameter> &plus;
<literal>31</literal> is assigned to a bit in the
<parameter class="function">write_mask</parameter> and
<parameter class="function">bits</parameter>
bitfield with bit 0 assigned to channel
<parameter class="function">base_channel</parameter>, bit 1 assigned to channel
<parameter class="function">base_channel</parameter> &plus;
<literal>1</literal>, etc. If a bit in
<parameter class="function">write_mask</parameter> is set, the
corresponding bit in <parameter class="function">*bits</parameter> will
be written to the digital output line corresponding to the channel given by
<parameter class="function">base_channel</parameter> plus the bit number.
Each digital line is then read and placed into
<parameter class="function">*bits</parameter>. The value
of bits in <parameter class="function">*bits</parameter> corresponding
2003-07-07 22:34:18 +00:00
to digital output lines is undefined and device-specific. Channel
<parameter class="function">base_channel</parameter> &plus;
<literal>0</literal> is the least significant bit in the bitfield. No
more than 32 channels at once can be accessed using this method.
<emphasis role="strong">Warning!</emphasis> Older versions of &comedi;
may ignore <parameter class="function">base_channel</parameter> and treat
it as <literal>0</literal> unless the subdevice has more than 32 channels.
2003-07-07 22:34:18 +00:00
</para>
<para>
The digital acquisition functions seem to be very simple, but, behind
the implementation screens of the &comedi; kernel module, they are
executed as special cases of the general
<link linkend="instructions">instruction</link> command.
</para>
</section>
<section id="singleanalog">
<title>
Single analog acquisition
</title>
<para>
Analog &comedi; channels can produce data values that are
<emphasis>samples</emphasis> from continuous analog signals.
These samples are integers with a significant content in
the range of, typically, 8, 10, 12, or 16 bits.
2003-07-07 22:34:18 +00:00
</para>
<para>
Single samples can be read from an analog channel using the function
<function><link linkend="func-ref-comedi-data-read">comedi_data_read</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_data_read</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
<paramdef>unsigned int <parameter>range</parameter></paramdef>
<paramdef>unsigned int <parameter>aref</parameter></paramdef>
<paramdef>lsampl_t *<parameter>data</parameter></paramdef>
</funcprototype></funcsynopsis>
This reads one such data value from a &comedi; channel, and puts it in
the user-specified <parameter class="function">data</parameter> buffer.
</para>
<para>
The <parameter class="function">range</parameter> parameter is the zero-based
index of one of the gain ranges supported by the channel. This is a number
from 0 to N-1 where N is the number of ranges supported by the channel.
Use the function
<function><link linkend="func-ref-comedi-get-n-ranges">comedi_get_n_ranges</link></function>
to get the number of ranges supported by the channel, the function
<function><link linkend="func-ref-comedi-find-range">comedi_find_range</link></function>
to search for a suitable range, or the function
<function><link linkend="func-ref-comedi-get-range">comedi_get_range</link></function>
to get the details of a supported range.
</para>
<para>
The <parameter class="function">aref</parameter> parameter specifies an
analog reference to use:
<constant><link linkend="aref-ground">AREF_GROUND</link></constant>,
<constant><link linkend="aref-common">AREF_COMMON</link></constant>,
<constant><link linkend="aref-diff">AREF_DIFF</link></constant>, or
<constant><link linkend="aref-other">AREF_OTHER</link></constant>.
Use the function
<function><link linkend="func-ref-comedi-get-subdevice-flags">comedi_get_subdevice_flags</link></function>
to see which analog references are supported by the subdevice.
</para>
<para>
In the opposite direction, single samples can be written to an analog output
channel using the function
<function><link linkend="func-ref-comedi-data-write">comedi_data_write</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_data_write</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
<paramdef>unsigned int <parameter>range</parameter></paramdef>
<paramdef>unsigned int <parameter>aref</parameter></paramdef>
<paramdef>lsampl_t <parameter>data</parameter></paramdef>
</funcprototype></funcsynopsis>
</para>
<para>
Raw data values read or written by the above functions
2003-07-07 22:34:18 +00:00
are unsigned integers less than, or equal to, the maximum sample value
of the channel, which can be determined using the function
<function><link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link></function>:
<funcsynopsis><funcprototype>
<funcdef>lsampl_t <function>comedi_get_maxdata</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
</funcprototype></funcsynopsis>
Conversion between raw data values and uncalibrated physical units can
be performed by the functions
<function><link linkend="func-ref-comedi-to-phys">comedi_to_phys</link></function>
and <function><link linkend="func-ref-comedi-from-phys">comedi_from_phys</link></function>:
<funcsynopsis><funcprototype>
<funcdef>double <function>comedi_to_phys</function></funcdef>
<paramdef>lsampl_t <parameter>data</parameter></paramdef>
<paramdef>comedi_range *<parameter>range</parameter></paramdef>
<paramdef>lsampl_t <parameter>maxdata</parameter></paramdef>
</funcprototype></funcsynopsis>
<funcsynopsis><funcprototype>
<funcdef>lsampl_t <function>comedi_from_phys</function></funcdef>
<paramdef>double <parameter>data</parameter></paramdef>
<paramdef>comedi_range *<parameter>range</parameter></paramdef>
<paramdef>lsampl_t <parameter>maxdata</parameter></paramdef>
</funcprototype></funcsynopsis>
</para>
<para>
There are some data structures in these commands that are not fully
2003-07-07 22:34:18 +00:00
self-explanatory:
<itemizedlist>
<listitem>
<para>
<type><link linkend="ref-type-comedi-t">comedi_t</link></type>: this data structure
2003-07-07 22:34:18 +00:00
contains all information that a user program has to know about an
<emphasis>open</emphasis> &comedi; device. The programmer doesn't have
to fill in this data structure manually: it gets filled in by opening
the device.
</para>
</listitem>
<listitem>
<para>
<type><link linkend="ref-type-lsampl-t">lsampl_t</link></type>: this
<quote>data structure</quote> represents one single sample. On most
2003-07-07 22:34:18 +00:00
architectures, it's nothing more than a 32 bits value. Internally,
&comedi; does some conversion from raw sample data to
<quote>correct</quote> integers. This is called <quote>data
munging</quote>.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<type><link linkend="ref-type-comedi-range">comedi_range</link></type>:
this holds the minimum and maximum physical values for a gain range supported
by a channel of a subdevice, and specifies the units. This can be used in
combination with the channel's <quote>maxdata</quote> value to convert between
unsigned integer sample values (of type
<type><link linkend="ref-type-lsampl-t">lsampl_t</link></type> or
<type><link linkend="ref-type-sampl-t">sampl_t</link></type>) and physical
units in a nominal (uncalibrated) way using the
<function><link linkend="func-ref-comedi-to-phys">comedi_to_phys</link></function>
and
<function><link linkend="func-ref-comedi-from-phys">comedi_from_phys</link></function>
functions. Use the
<function><link linkend="func-ref-comedi-get-maxdata">comedi_get_maxdata</link></function>
function to get the <quote>maxdata</quote> value for the channel.
</para>
<para>
Most functions specify the range to be used for a channel by a zero-based
index into the list of ranges supported by the channel. Depending on the
device and subdevice, different channels on the subdevice may or may not
share the same list of ranges, that is, ranges may or may not be
channel-specific. (The <constant>SDF_RANGETYPE</constant> subdevice flag
indicates whether ranges are channel-specific.)
</para>
2003-07-07 22:34:18 +00:00
</listitem>
</itemizedlist>
</para>
<para>
Each single acquisition by, for example,
<function><link linkend="func-ref-comedi-data-read">comedi_data_read</link></function>
2003-07-07 22:34:18 +00:00
requires quite some overhead, because all the arguments of the
function call are checked. If multiple acquisitions must be done on
the same channel, this overhead can be avoided by using a function
that can read more than one sample,
<function><link linkend="func-ref-comedi-data-read-n">comedi_data_read_n</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_data_read_n</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
<paramdef>unsigned int <parameter>range</parameter></paramdef>
<paramdef>unsigned int <parameter>aref</parameter></paramdef>
<paramdef>lsampl_t *<parameter>data</parameter></paramdef>
<paramdef>unsigned int <parameter>n</parameter></paramdef>
</funcprototype></funcsynopsis>
The number of samples, <parameter class="function">n</parameter>, is
2003-07-07 22:34:18 +00:00
limited by the &comedi; implementation (to a maximum of 100 samples),
because the call is blocking.
</para>
<para>
The start of the a single data acquisition can also be delayed by a specified
number of nano-seconds using the function
<function><link linkend="func-ref-comedi-data-read-delayed">comedi_data_read_delayed</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_data_read_delayed</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
<paramdef>unsigned int <parameter>range</parameter></paramdef>
<paramdef>unsigned int <parameter>aref</parameter></paramdef>
<paramdef>lsampl_t *<parameter>data</parameter></paramdef>
<paramdef>unsigned int <parameter>nano_sec</parameter></paramdef>
</funcprototype></funcsynopsis>
</para>
<para>
2003-07-07 22:34:18 +00:00
All these read and write acquisition functions are implemented on top
of the generic <link linkend="instructions">instruction</link>
command.
</para>
</section>
</section>
<section id="instructions">
<title>
Instructions for multiple acquisitions
2003-07-07 22:34:18 +00:00
</title>
<para>
The <emphasis>instruction</emphasis> is one of the most generic,
overloaden and flexible functions in the &comedi; API. It is used to
execute a multiple of identical acquisitions on the same channel, but
also to perform a
<link linkend="instructionsconfiguration">configuration</link> of a
channel.
<anchor id="anchor.instruction.list"/>
2003-07-07 22:34:18 +00:00
An <emphasis>instruction list</emphasis> is a list of instructions,
possibly on different channels. Both instructions and instructions
lists are executed <emphasis>synchronously</emphasis>, i.e., while
<emphasis role="strong">blocking</emphasis> the calling process.
This is one of the limitations of instructions; the other one is that
they cannot code an acquisition involving timers or external events.
These limits are eliminated by the
<link linkend="commandsstreaming">command</link> acquisition
primitive.
</para>
<section id="comediinsnstructure">
<title>
The instruction data structure
</title>
<para>
All the information needed to execute an instruction is stored in the
<type><link linkend="ref-type-comedi-insn">comedi_insn</link></type>
2003-07-07 22:34:18 +00:00
data structure:
<programlisting>
typedef struct <anchor id="insn-data-structure"/>comedi_insn_struct {
<anchor id="insn-data-structure-insn"/>unsigned int insn; // integer encoding the type of acquisition
2003-07-07 22:34:18 +00:00
// (or configuration)
unsigned int n; // number of elements in data array
<link linkend="ref-type-lsampl-t">lsampl_t</link> <anchor id="insn-data-structure-data"/>*data; // pointer to data buffer
2003-07-07 22:34:18 +00:00
unsigned int subdev; // subdevice
unsigned int <anchor id="insn-data-structure-chanspec"/><link linkend="ref-macro-CR-PACK">chanspec</link>; // encoded channel specification
2003-07-07 22:34:18 +00:00
unsigned int unused[3];
} comedi_insn;
</programlisting>
Because of the large flexibility of the instruction function, many
types of instruction do not need to fill in all fields, or attach
different meanings to the same field. But the current implementation
of &comedi; requires the
<structfield><link linkend="insn-data-structure-data">data</link></structfield>
field to be at least one byte long.
2003-07-07 22:34:18 +00:00
</para>
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> member of the
<link linkend="insn-data-structure">instruction data structure</link>
2003-07-07 22:34:18 +00:00
determines the type of acquisition executed in the corresponding
instruction:
<itemizedlist>
<listitem>
<para>
<constant>INSN_READ</constant>: the instruction executes a read on an
analog channel.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<constant>INSN_WRITE</constant>: the instruction executes a write on an
analog channel.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
2003-07-07 22:34:18 +00:00
<listitem>
<para>
<constant>INSN_BITS</constant>: indicates that the instruction must
2003-07-07 22:34:18 +00:00
read or write values on multiple digital I/O channels.
</para>
</listitem>
<listitem>
<para>
<constant>INSN_GTOD</constant>: the instruction performs a
<quote>Get Time Of Day</quote> acquisition.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<constant>INSN_WAIT</constant>: the instruction blocks for a specified
number of nanoseconds.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section id="instructionexecution">
<title>
Instruction execution
</title>
<para>
Once an instruction data structure has been filled in, the
corresponding instruction is executed with the function
<function><link linkend="func-ref-comedi-do-insn">comedi_do_insn</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_do_insn</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>comedi_insn *<parameter>instruction</parameter></paramdef>
</funcprototype></funcsynopsis>
2003-07-07 22:34:18 +00:00
Many &comedi; instructions are shortcuts that relieve the programmer
from explicitly filling in the data structure and calling the
<function><link linkend="func-ref-comedi-do-insn">comedi_do_insn</link></function>
2003-07-07 22:34:18 +00:00
function.
</para>
<para>
A list of instructions can be executed in one function call using the function
<function><link linkend="func-ref-comedi-do-insnlist">comedi_do_insnlist</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_do_insnlist</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>comedi_insnlist *<parameter>list</parameter></paramdef>
</funcprototype></funcsynopsis>
The parameter <parameter class="function">list</parameter> is a pointer to a
<type><link linkend="insnlist-data-structure">comedi_insnlist</link></type>
data structure holding a pointer to an array of <type>comedi_insn</type>
and the number of instructions in the list:
<programlisting>
typedef struct <anchor id="insnlist-data-structure"/>comedi_insnlist_struct {
unsigned int n_insns;
comedi_insn *insns;
} comedi_insnlist;
</programlisting>
</para>
<para>
The number of instructions in the list is limited in the
2003-07-07 22:34:18 +00:00
implementation, because instructions are executed
<emphasis>synchronously</emphasis>, i.e., the call blocks until the
whole instruction (list) has finished.
</para>
</section>
2003-07-07 22:34:18 +00:00
</section>
<section id="instructionsconfiguration">
<title>
Instructions for configuration
</title>
<para>
<xref linkend="instructions"/> explains how instructions are used to do
2003-07-07 22:34:18 +00:00
<emphasis>acquisition</emphasis> on channels. This section explains
how they are used to <emphasis>configure</emphasis> a subdevice.
2003-07-07 22:34:18 +00:00
There are various sorts of configurations, and the
specific information for each different configuration possibility is
to be specified via the
<structfield><link linkend="insn-data-structure-data">data</link></structfield>
buffer of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>.
(So, the pointer to a
<type><link linkend="ref-type-lsampl-t">lsampl_t</link></type>
2003-07-07 22:34:18 +00:00
is misused as a pointer to an array with board-specific information.)
</para>
<para>
Using <constant>INSN_CONFIG</constant> as the
<structfield><link linkend="insn-data-structure-insn">insn</link></structfield>
member in an
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
indicates that the instruction will
<emphasis>not perform acquisition</emphasis> on a
channel, but will <emphasis>configure</emphasis> that channel.
The
<structfield><link linkend="ref-macro-CR-PACK">chanspec</link></structfield>
member in the
<type><link linkend="insn-data-structure-chanspec">comedi_insn</link></type>
data structure, contains the channel to be configured.
The zeroth element of the data array
is always an id that specifies
what type of configuration instruction is being performed. The
meaning of rest of the elements in the data array
depend on the configuration instruction id.
Some of the
possible ids are summarised in the table below, along with the
meanings of the data array elements for
each type of configuration instruction.
2003-07-07 22:34:18 +00:00
</para>
<informaltable>
<tgroup cols='4' align='left'>
<colspec colwidth='4*' />
<colspec colwidth='4*' />
<colspec colwidth='1*' />
<colspec colwidth='4*' />
<thead>
<row>
<entry>data[0]</entry>
<entry>Description</entry>
<entry>n (number of elements in data array)</entry>
<entry>Meanings of data[1], ..., data[n-1]</entry>
</row>
</thead>
<tbody>
<row>
<entry><constant>INSN_CONFIG_DIO_INPUT</constant></entry>
<entry>
Configure a DIO line as input. It is easier to use
<function><link linkend="func-ref-comedi-dio-config">comedi_dio_config</link></function>
than to use this configuration instruction directly.
</entry>
<entry>1</entry>
<entry>
n/a
</entry>
</row>
<row>
<entry><constant>INSN_CONFIG_DIO_OUTPUT</constant></entry>
<entry>
Configure a DIO line as output. It is easier to use
<function><link linkend="func-ref-comedi-dio-config">comedi_dio_config</link></function>
than to use this configuration instruction directly.
</entry>
<entry>1</entry>
<entry>
n/a
</entry>
</row>
<row>
<entry><constant>INSN_CONFIG_ALT_SOURCE</constant></entry>
<entry>
Select an alternate input source. This instruction is used by calibration
programs to configure analog input channels
which can be redirected to read internal calibration
references. You need to set the <constant>CR_ALT_SOURCE</constant> flag in the chanspec
when reading to actually read from the configured alternate input source.
If you are using <function>comedi_data_read</function>, then the channel parameter can be
bitwise or'd with the <constant>CR_ALT_SOURCE</constant> flag.
</entry>
<entry>2</entry>
<entry>
data[1]: alternate input source.
</entry>
</row>
<row>
<entry><constant>INSN_CONFIG_BLOCK_SIZE</constant></entry>
<entry>
Specify block size for asynchonous command data.
When performing streaming input, many boards accumulate
samples in internal fifos and transfer them to the host
computer in chunks. Some drivers let you suggest a size in bytes for how big a
the chunks should be. This lets you tune how often the host computer is
interrupted with a new chunk of data.
</entry>
<entry>2</entry>
<entry>
data[1]: The desired block size in bytes. The actual configured block size is
writen back to data[1] after the instruction completes. This instruction
acts purely as a query if the block size is set to zero.
</entry>
</row>
<row>
<entry><constant>INSN_CONFIG_DIO_QUERY</constant></entry>
<entry>
Queries the configuration of a DIO line to see if it is an input or output.
It is probably easier to use the comedilib function
<function><link linkend="func-ref-comedi-dio-get-config">comedi_dio_get_config</link></function>
than to use this instruction directly.
</entry>
<entry>2</entry>
<entry>
data[1]: The instruction sets this element to either
<constant>COMEDI_INPUT</constant> or <constant>COMEDI_OUTPUT</constant>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
2003-07-07 22:34:18 +00:00
<para>
See the comedilib demo program <filename>demo/choose_clock.c</filename> for an example
of using a configuration instruction.
2003-07-07 22:34:18 +00:00
</para>
</section>
<section id="inttrigconfiguration">
<title>
Instruction for internal triggering
</title>
<para>
This special instruction has
<anchor id="insn-inttrig"/><constant>INSN_INTTRIG</constant> as the
<structfield><link linkend="insn-data-structure-insn">insn</link></structfield>
member in its
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>.
Its execution causes an
<link linkend="trig-int-start-src">internal triggering event</link>. This
event can, for example, cause the device driver to start a conversion,
or to stop an ongoing acquisition. The exact meaning of the triggering
depends on the card and its particular driver.
</para>
<para>
The
<structfield><link linkend="insn-data-structure-data">data</link></structfield>[0] element of the
<constant>INSN_INTTRIG</constant> instruction is reserved for future use,
and should be set to <literal>0</literal>.
2003-07-07 22:34:18 +00:00
</para>
</section>
<section id="commandsstreaming">
<title>
Commands for streaming acquisition
</title>
<para>
The most powerful &comedi; acquisition primitive is the
<emphasis>command</emphasis>. It's powerful because, with one single
command, the programmer launches:
<itemizedlist>
<listitem>
<para>
a possibly infinite <emphasis>sequence of acquisitions</emphasis>,
</para>
</listitem>
<listitem>
<para>
accompanied with various <emphasis>callback</emphasis> functionalities
(DMA, interrupts, driver-specific callback functions),
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
for <emphasis>any number of channels</emphasis>,
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
with an <emphasis>arbitrary order</emphasis> of channels in each scan
(possibly even with repeated channels per scan),
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
and with various scan <emphasis>triggering sources</emphasis>,
external (i.e., hardware pulses) as well as internal (i.e., pulses
generated on the DAQ card itself, or generated by a
2003-07-07 22:34:18 +00:00
<link linkend="inttrigconfiguration">software trigger instruction</link>).
</para>
</listitem>
</itemizedlist>
This command functionality exists in the &comedi; API, because various
data acquisition devices have the capability to perform this kind of
complex acquisition, driven by either on-board or
off-board timers and triggers.
</para>
<para>
A command specifies a particular data
2003-07-07 22:34:18 +00:00
<link linkend="fig-acq-seq">acquisition sequence</link>, which
consists of a number of <emphasis>scans</emphasis>, and each scan is
comprised of a number of <emphasis>conversions</emphasis>, which
usually corresponds to a single A/D or D/A conversion. So, for
example, a scan could consist of sampling channels 1, 2 and 3 of a
particular device, and this scan should be repeated 1000 times, at
intervals of 1 millisecond apart.
</para>
<para>
The command function is complementary to the
<link linkend="instructionsconfiguration">configuration instruction</link>
function: each channel in the command's
<structfield><link linkend="command-data-struct-chanlist">chanlist</link></structfield>
2003-07-07 22:34:18 +00:00
should first be configured by an appropriate instruction.
</para>
<section id="executingcommand">
<title>
Executing a command
</title>
<para>
A command is executed by the function
<function><link linkend="func-ref-comedi-command">comedi_command</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_command</function></funcdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>comedi_cmd *<parameter>command</parameter></paramdef>
</funcprototype></funcsynopsis>
2003-07-07 22:34:18 +00:00
The following sections explain the meaning of the
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> data structure.
2003-07-07 22:34:18 +00:00
Filling in this structure can be quite complicated, and
requires good knowledge about the exact functionalities of the DAQ
card. So, before launching a command, the application programmer is
adviced to check whether this complex command data structure can be
successfully parsed. So, the typical sequence for executing a command is
to first send the command through
<function><link linkend="func-ref-comedi-command-test">comedi_command_test</link></function>
2003-07-07 22:34:18 +00:00
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.
</para>
<para>
A &comedi; program can find out on-line what the command capabilities
of a specific device are, by means of the
<function><link linkend="func-ref-comedi-get-cmd-src-mask">comedi_get_cmd_src_mask</link></function>
2003-07-07 22:34:18 +00:00
function.
</para>
2003-07-07 22:34:18 +00:00
</section>
<section id="comedicmdstructure">
<title>
The command data structure
</title>
<para>
The command executes according to the information about the requested
acquisition, which is stored in the
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type>
<anchor id="command-data-struct"/>data structure:
2003-07-07 22:34:18 +00:00
<programlisting>
typedef struct comedi_cmd_struct comedi_cmd;
struct comedi_cmd_struct {
2003-07-07 22:34:18 +00:00
unsigned int subdev; // which subdevice to sample
unsigned int <anchor id="command-data-struct-flags"/>flags; // encode some configuration possibilities
2003-07-07 22:34:18 +00:00
// of the command execution; e.g.,
// whether a callback routine is to be
// called at the end of the command
unsigned int <anchor id="command-data-struct-start-src"/>start_src; // event to make the acquisition start
unsigned int <anchor id="command-data-struct-start-arg"/>start_arg; // parameters that influence this start
2003-07-07 22:34:18 +00:00
unsigned int <anchor id="command-data-struct-scan-begin-src"/>scan_begin_src; // event to make a particular scan start
unsigned int <anchor id="command-data-struct-scan-begin-arg"/>scan_begin_arg; // parameters that influence this start`
2003-07-07 22:34:18 +00:00
unsigned int <anchor id="command-data-struct-convert-src"/>convert_src; // event to make a particular conversion start
unsigned int <anchor id="command-data-struct-convert-arg"/>convert_arg; // parameters that influence this start
2003-07-07 22:34:18 +00:00
unsigned int <anchor id="command-data-struct-scan-end-src"/>scan_end_src; // event to make a particular scan terminate
unsigned int <anchor id="command-data-struct-scan-end-arg"/>scan_end_arg; // parameters that influence this termination
2003-07-07 22:34:18 +00:00
unsigned int <anchor id="command-data-struct-stop-src"/>stop_src; // what make the acquisition terminate
unsigned int <anchor id="command-data-struct-stop-arg"/>stop_arg; // parameters that influence this termination
2003-07-07 22:34:18 +00:00
unsigned int <anchor id="command-data-struct-chanlist"/>*chanlist; // pointer to list of channels to be sampled
unsigned int <anchor id="command-data-struct-chanlist-len"/>chanlist_len; // number of channels to be sampled
2003-07-07 22:34:18 +00:00
sampl_t *<anchor id="command-data-struct-data"/>data; // address of buffer
unsigned int <anchor id="command-data-struct-data-len"/>data_len; // number of samples to acquire
2003-07-07 22:34:18 +00:00
};
</programlisting>
The start and end of the whole command acquisition sequence, and the
start and end of each scan and of each conversion, is triggered by a
so-called <emphasis>event</emphasis>. More on these in
<xref linkend="comedicmdsources"/>.
2003-07-07 22:34:18 +00:00
</para>
<para>
The <parameter class="function">subdev</parameter> member of the
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> structure is
2003-07-07 22:34:18 +00:00
the index of the subdevice the command is intended for. The
<function><link linkend="func-ref-comedi-find-subdevice-by-type">comedi_find_subdevice_by_type</link></function>
2003-07-07 22:34:18 +00:00
function can be useful in discovering the index of your desired subdevice.
</para>
<para>
The <structfield><link linkend="command-data-struct-chanlist">chanlist</link></structfield>
2003-07-07 22:34:18 +00:00
member of the
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> data
2003-07-07 22:34:18 +00:00
structure should point to an array whose number of elements is
specified by
<structfield><link linkend="command-data-struct-chanlist-len">chanlist_len</link></structfield>
2003-07-07 22:34:18 +00:00
(this will generally be the same as the
<structfield><link linkend="command-data-struct-scan-end-arg">scan_end_arg</link></structfield>).
2003-07-07 22:34:18 +00:00
The
<structfield><link linkend="command-data-struct-chanlist">chanlist</link></structfield>
2003-07-07 22:34:18 +00:00
specifies the sequence of channels and gains (and analog references)
that should be stepped through for each scan. The elements of the
<structfield><link linkend="command-data-struct-chanlist">chanlist</link></structfield> array should be
initialized by <quote>packing</quote> the channel, range and reference
2003-07-07 22:34:18 +00:00
information together with the
<function><link linkend="ref-macro-CR-PACK">CR_PACK</link></function>
2003-07-07 22:34:18 +00:00
macro.
</para>
<para>
The <structfield><link linkend="command-data-struct-data">data</link></structfield> and
<structfield><link linkend="command-data-struct-data-len">data_len</link></structfield>
2003-07-07 22:34:18 +00:00
members can be safely ignored when issueing commands from a user-space
program. They only have meaning when a command is sent from a
<emphasis role="strong">kernel</emphasis> module using the
<systemitem>kcomedilib</systemitem> interface, in which case they specify
2003-07-07 22:34:18 +00:00
the buffer where the driver should write/read its data to/from.
</para>
<para>
The final member of the
<type><link linkend="command-data-struct">comedi_cmd</link></type> structure is the
<structfield><link linkend="command-data-struct-flags">flags</link></structfield> field,
2003-07-07 22:34:18 +00:00
i.e., bits in a word that can be bitwise-or'd together. The meaning of
these bits are explained in
<xref linkend="comedicmdflags"/>.
2003-07-07 22:34:18 +00:00
</para>
</section>
<section id="comedicmdsources">
<title>
The command trigger events
<anchor id="source.trigger.anchor"/>
2003-07-07 22:34:18 +00:00
</title>
<para>
A command is a very versatile acquisition instruction, in the sense
that it offers lots of possibilities to let different hardware and
software sources determine when acquisitions are started, performed,
and stopped. More specifically, the command
<link linkend="command-data-struct">data structure</link>
has <emphasis>five</emphasis> types of events: start the
2003-07-07 22:34:18 +00:00
<link linkend="acquisitionterminology">acquisition</link>,
start a <link linkend="scan">scan</link>, start a
2003-07-07 22:34:18 +00:00
<link linkend="conversion">conversion</link>, stop a scan, and stop
the acquisition. Each event can be given its own
<emphasis><link linkend="source.trigger.anchor">source</link></emphasis>
(the <parameter class="function">&hellip;_src</parameter> members in the
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> data
2003-07-07 22:34:18 +00:00
structure). And each event source can have a corresponding
argument (the <parameter class="function">&hellip;_arg</parameter> members of
the <type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> data
structure) whose meaning depends on the type of source trigger.
For example, to specify an external digital line <quote>3</quote> as a
2003-07-07 22:34:18 +00:00
source (in general, <emphasis>any</emphasis> of the five event
sources), you would use
<parameter>src</parameter>=<constant><link linkend="trig-ext">TRIG_EXT</link></constant>
and <parameter>arg</parameter>=<literal>3</literal>.
2003-07-07 22:34:18 +00:00
</para>
<para>
The following paragraphs discuss in somewhat more detail the trigger
event sources(<parameter class="function">&hellip;_src</parameter>), and the
corresponding arguments (<parameter class="function">&hellip;_arg</parameter>).
2003-07-07 22:34:18 +00:00
</para>
<para>
The start of an acquisition is controlled by the
<structfield><link linkend="command-data-struct-start-src">start_src</link></structfield> events.
2003-07-07 22:34:18 +00:00
The available options are:
<itemizedlist>
<listitem>
<para>
<anchor id="trig-now-start-src"/>
<constant>TRIG_NOW</constant>: the <quote>start</quote> event occurs
<structfield><link linkend="command-data-struct-start-arg">start_arg</link></structfield>
nanoseconds after the command is set up. Currently, only
<structfield><link linkend="command-data-struct-start-arg">start_arg</link></structfield>=<literal>0</literal> is
2003-07-07 22:34:18 +00:00
supported.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-follow-start-src"/>
<constant>TRIG_FOLLOW</constant>: (For an output device.) The <quote>start</quote>
2003-07-07 22:34:18 +00:00
event occurs when data is written to the buffer.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-ext-start-src"/>
<constant>TRIG_EXT</constant>: the <quote>start</quote> event occurs when an
external trigger signal occurs; e.g., a rising edge of a digital line.
<structfield><link linkend="command-data-struct-start-arg">start_arg</link></structfield>
2003-07-07 22:34:18 +00:00
chooses the particular digital line.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-int-start-src"/>
<constant>TRIG_INT</constant>: the <quote>start</quote> event occurs on a &comedi;
internal signal, which is typically caused by an
<constant><link linkend="insn-inttrig">INSN_INTTRIG</link></constant>
instruction.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
</itemizedlist>
The start of the beginning of each
<link linkend="scan">scan</link> is controlled by the
<structfield><link linkend="command-data-struct-scan-begin-src">scan_begin_src</link></structfield> events.
2003-07-07 22:34:18 +00:00
The available options are:
<itemizedlist>
<listitem>
<para>
<anchor id="trig-timer-start-scan"/>
<constant>TRIG_TIMER</constant>: <quote>scan begin</quote>
events occur periodically. The time between <quote>scan begin</quote>
2003-07-07 22:34:18 +00:00
events is
<structfield><link linkend="command-data-struct-scan-begin-arg">scan_begin_arg</link></structfield>
2003-07-07 22:34:18 +00:00
nanoseconds.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-follow-start-scan"/>
<constant>TRIG_FOLLOW</constant>: The <quote>scan begin</quote>
event occurs immediately after a <quote>scan end</quote>
2003-07-07 22:34:18 +00:00
event occurs.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-ext-start-scan"/>
<constant>TRIG_EXT</constant>: the <quote>scan begin</quote>
2003-07-07 22:34:18 +00:00
event occurs when an external trigger signal
occurs; e.g., a rising edge of a digital line.
<structfield><link linkend="command-data-struct-scan-begin-arg">scan_begin_arg</link></structfield>
2003-07-07 22:34:18 +00:00
chooses the particular digital line.
</para>
</listitem>
</itemizedlist>
The
<structfield><link linkend="command-data-struct-scan-begin-arg">scan_begin_arg</link></structfield>
2003-07-07 22:34:18 +00:00
used here may not be supported exactly by the device, but it
will be adjusted to the nearest supported value by
<function><link linkend="func-ref-comedi-command-test">comedi_command_test</link></function>.
2003-07-07 22:34:18 +00:00
</para>
<para>
The timing between each sample in a
2003-07-07 22:34:18 +00:00
<link linkend="scan">scan</link> is controlled by the
<structfield><link linkend="command-data-struct-convert-src">convert_src</link></structfield>
events.
The available options are:
2003-07-07 22:34:18 +00:00
<itemizedlist>
<listitem>
<para>
<anchor id="convert-trig-timer"/>
<anchor id="trig-timer"/>
<constant>TRIG_TIMER</constant>: the conversion events occur periodically.
The time between <quote>convert</quote> events is
<structfield><link linkend="command-data-struct-convert-arg">convert_arg</link></structfield>
2003-07-07 22:34:18 +00:00
nanoseconds.
</para>
</listitem>
<listitem>
<para>
<anchor id="convert-trig-ext"/>
<anchor id="trig-ext"/>
<constant>TRIG_EXT</constant>: the conversion events occur when an
external trigger signal occurs, e.g., a rising edge of a digital line.
<structfield><link linkend="command-data-struct-convert-arg">convert_arg</link></structfield>
2003-07-07 22:34:18 +00:00
chooses the particular digital line.
</para>
</listitem>
<listitem>
<para>
<anchor id="convert-trig-now"/>
<anchor id="trig-now"/>
<constant>TRIG_NOW</constant>: All conversion events in a
2003-07-07 22:34:18 +00:00
<link linkend="scan">scan</link> occur simultaneously.
</para>
</listitem>
</itemizedlist>
The <emphasis>end</emphasis> of each scan is almost always specified
by setting the
<structfield><link linkend="command-data-struct-scan-end-src">scan_end_src</link></structfield>
event to
<constant><link linkend="trig-count">TRIG_COUNT</link></constant>,
with the argument being the same as the number of channels in the
<structfield><link linkend="command-data-struct-chanlist">chanlist</link></structfield>. You
2003-07-07 22:34:18 +00:00
could probably find a device that allows something else, but it would
be strange.
2003-07-07 22:34:18 +00:00
</para>
<para>
The end of an
<link linkend="acquisitionterminology">acquisition</link> is
controlled by
<structfield><link linkend="command-data-struct-stop-src">stop_src</link></structfield> event.
The available options are:
2003-07-07 22:34:18 +00:00
<itemizedlist>
<listitem>
<para>
<anchor id="acquisition-end-trig-count"/>
<anchor id="trig-count"/>
<constant>TRIG_COUNT</constant>: stop the acquisition after
<structfield><link linkend="command-data-struct-stop-arg">stop_arg</link></structfield>
2003-07-07 22:34:18 +00:00
scans.
</para>
</listitem>
<listitem>
<para>
<anchor id="acquisition-end-trig-none"/>
<anchor id="trig-none"/>
<constant>TRIG_NONE</constant>: perform continuous acquisition,
until stopped using
<function><link linkend="func-ref-comedi-cancel">comedi_cancel</link></function>.
2003-07-07 22:34:18 +00:00
</para>
<para>
<structfield>stop_arg</structfield> is used to denote how many samples should be
used in the continuous acquisition. If <structfield>stop_arg</structfield> is
set to <literal>0</literal>, the entire output buffer may contribute to the
output. If <structfield>stop_arg</structfield> != <literal>0</literal>, only
the memory for <structfield>stop_arg</structfield> samples will be used. Many
drivers do not yet support
<structfield>stop_arg</structfield>!=<literal>0</literal> and should enforce
<structfield>stop_arg</structfield>=<literal>0</literal> via
comedi_command_test.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
</itemizedlist>
There are a couple of less usual or not yet implemented events:
<itemizedlist>
<listitem>
<para>
<anchor id="trig-time"/>
<constant>TRIG_TIME</constant>:
2003-07-07 22:34:18 +00:00
cause an event to occur at a particular time.
</para>
<para>
(This event source is reserved for future use.)
</para>
</listitem>
<listitem>
<para>
<anchor id="trigother-event"/>
<constant>TRIG_OTHER</constant>: driver specific event trigger.
2003-07-07 22:34:18 +00:00
</para>
<para>
This event can be useful as any of the trigger sources. Its exact
meaning is driver specific, because it implements a feature that
otherwise does not fit into the generic &comedi; command interface.
Configuration of <constant>TRIG_OTHER</constant> features are done by
<constant><link linkend="instructionsconfiguration">INSN_CONFIG</link></constant>
2003-07-07 22:34:18 +00:00
instructions.
</para>
<para>
The argument is reserved and should be set to <literal>0</literal>.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
</itemizedlist>
Not all event sources are applicable to all events. Supported
trigger sources for specific events depend significantly on your
particular device, and even more on the current state of its device
driver. The
<function><link linkend="func-ref-comedi-get-cmd-src-mask">comedi_get_cmd_src_mask</link></function>
2003-07-07 22:34:18 +00:00
function is useful for determining what trigger sources a subdevice
supports.
</para>
</section>
<section id="comedicmdflags">
<title>
The command flags
<anchor id="source.flags.anchor"/>
2003-07-07 22:34:18 +00:00
</title>
<para>
The
<structfield><link linkend="command-data-struct-flags">flags</link></structfield>
field in the
2003-07-07 22:34:18 +00:00
<link linkend="ref-type-comedi-cmd">command data structure</link>
is used to specify some <quote>behaviour</quote> of the acquisitions in
2003-07-07 22:34:18 +00:00
a command.
The meaning of the field is as follows:
<itemizedlist>
<listitem>
<para>
<anchor id="trig-rt"/>
<constant>TRIG_RT</constant>: ask the driver to use a
2003-07-07 22:34:18 +00:00
<emphasis role="strong">hard real-time</emphasis> 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 data buffer. You must have a
real-time kernel (<ulink url="http://www.rtai.org">RTAI</ulink> or
2004-12-02 07:59:00 +00:00
<ulink url="http://www.rtlinux-gpl.org/">RTLinux/GPL</ulink>)
2003-07-07 22:34:18 +00:00
and must compile &comedi; with real-time support, or this flag will do
nothing.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-wake-eos"/>
<constant>TRIG_WAKE_EOS</constant>:
where <quote>EOS</quote> stands for <quote>End of Scan</quote>. Some
2003-07-07 22:34:18 +00:00
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 hardware data buffer is
half full). This flag may degrade a driver's performance at high
frequencies, because the end of a scan is, in general, a much more
frequent event than the filling up of the data buffer.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-round-nearest"/>
<constant>TRIG_ROUND_NEAREST</constant>:
2003-07-07 22:34:18 +00:00
round to nearest supported timing period, the default.
This flag (as well as the following three), indicates how timing
arguments should be rounded if the hardware cannot achieve the exact
timing requested.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-round-down"/>
<constant>TRIG_ROUND_DOWN</constant>: round period down.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-round-up"/>
<constant>TRIG_ROUND_UP</constant>: round period up.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-round-up-next"/>
<constant>TRIG_ROUND_UP_NEXT</constant>:
2003-07-07 22:34:18 +00:00
this one doesn't do anything, and I don't know what it was intended
to do&hellip;?
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-dither"/>
<constant>TRIG_DITHER</constant>: enable dithering? Dithering is
a software technique to smooth the influence of discretization
<quote>noise</quote>.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-deglitch"/>
<constant>TRIG_DEGLITCH</constant>: enable deglitching?
Another <quote>noise</quote> smoothing technique.
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-write"/>
<constant>TRIG_WRITE</constant>:
2003-07-07 22:34:18 +00:00
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.
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-bogus"/>
<constant>TRIG_BOGUS</constant>: do the motions?
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<anchor id="trig-other"/>
<constant>TRIG_CONFIG</constant>: perform configuration, not triggering.
This is a legacy of the deprecated
<type><link linkend="ref-type-comedi-trig">comedi_trig_struct</link></type>
2003-07-07 22:34:18 +00:00
data structure, and has no function at present.
</para>
</listitem>
</itemizedlist>
</para>
</section>
<section>
<title>
Anti-aliasing
</title>
<para>
If you wish to aquire accurate waveforms, it is vital that you use an
anti-alias filter. An anti-alias filter is a low-pass filter used to
remove all frequencies higher than the Nyquist frequency (half your sampling rate)
from your analog input signal
before you convert it to digital. If you fail to filter your input signal,
any high frequency components in the original analog signal will create
artifacts in your recorded digital waveform that cannot be corrected.
</para>
<para>
For example, suppose you are sampling an analog input channel at a rate of
1000 Hz. If you were to apply a 900 Hz sine wave to the input, you
would find that your
sampling rate is not high enough to faithfully record the 900 Hz input,
since it is above your Nyquist frequency of 500 Hz. Instead, what you
will see in your recorded digital waveform is a 100 Hz sine wave! If you
don't use an anti-alias filter, it is impossible to tell whether the 100
Hz sine wave you see in your digital signal was really produced by a
100 Hz input signal, or a 900 Hz signal aliased to 100 Hz, or a 1100 Hz
signal, etc.
</para>
<para>
In practice, the cutoff frequency for the anti-alias filter is usually
set 10% to 20% below the Nyquist frequency due to fact that real filters
do not have infinitely sharp cutoffs.
</para>
</section>
2003-07-07 22:34:18 +00:00
</section>
<section id="slowlyvarying">
2002-01-21 15:17:12 +00:00
<title>
2003-07-07 22:34:18 +00:00
Slowly-varying inputs
2002-01-21 15:17:12 +00:00
</title>
2002-01-21 11:15:31 +00:00
<para>
<emphasis role="strong">Note: The functions described here use an old
feature that is no longer implemented by the &comedi;
kernel layer. THEY WILL NOT WORK!</emphasis>
</para>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
Sometimes, your input channels change slowly enough that
you are able to average many successive 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
<function>sqrt<parameter>number_of_samples</parameter></function>.
2003-07-07 22:34:18 +00:00
Obviously, there are limitations to this:
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<itemizedlist>
<listitem>
2002-01-21 15:17:12 +00:00
<para>
you are ultimately limited by <quote>Spurious Free Dynamic
Range</quote>. This SFDR is one of the popular measures to quantify how
2003-07-07 22:34:18 +00:00
much noise a signal carries. If you take a Fourier transform of your
signal, you will see several <quote>peaks</quote> in the transform: one
2003-07-07 22:34:18 +00:00
or more of the fundamental harmonics of the measured signal, and lots
of little <quote>peaks</quote> (called <quote>spurs</quote>) caused by
2003-07-07 22:34:18 +00:00
noise. The SFDR is then the difference between the amplitude of the
fundamental harmonic and of the largest spur (at frequencies below
half of the Nyquist frequency of the DAQ sampler!).
2002-01-21 15:17:12 +00:00
</para>
2003-07-07 22:34:18 +00:00
</listitem>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<listitem>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
you need to have <emphasis>some</emphasis> noise on the input channel,
otherwise you will be averaging the same number <literal>N</literal>
times. (Of course, this only holds if the noise is large enough to
cause at least a one-bit discretization.)
2002-01-21 15:17:12 +00:00
</para>
2003-07-07 22:34:18 +00:00
</listitem>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<listitem>
<para>
the more noise you have, the greater your SFDR, but it
takes many more samples to compensate for the increased
noise.
</para>
</listitem>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<listitem>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
if you feel the need to average samples for, for example, two seconds,
your signal will need to be <emphasis>very</emphasis> slowly-varying,
i.e., not varying more than your target uncertainty for the entire two
seconds.
2002-01-21 15:17:12 +00:00
</para>
2003-07-07 22:34:18 +00:00
</listitem>
</itemizedlist>
<para>
As you might have guessed, the &comedi; library has functions
to help you in your quest to accurately measure slowly varying
inputs:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_sv_init</function></funcdef>
<paramdef>comedi_sv_t *<parameter>sv</parameter></paramdef>
<paramdef>comedi_t *<parameter>device</parameter></paramdef>
<paramdef>unsigned int <parameter>subdevice</parameter></paramdef>
<paramdef>unsigned int <parameter>channel</parameter></paramdef>
</funcprototype></funcsynopsis>
The above function <function><link linkend="func-ref-comedi-sv-init">comedi_sv_init</link></function> initializes the
<type><link linkend="ref-type-comedi-sv-t">comedi_sv_t</link></type> data structure, used
2003-07-07 22:34:18 +00:00
to do the averaging acquisition:
<programlisting>
typedef struct comedi_sv_struct {
2003-07-07 22:34:18 +00:00
<link linkend="ref-type-comedi-t">comedi_t</link> *dev;
unsigned int subdevice;
unsigned int chan;
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
/* range policy */
int range;
int aref;
/* number of measurements to average (for analog inputs) */
int n;
lsampl_t maxdata;
} comedi_sv_t;
2003-07-07 22:34:18 +00:00
</programlisting>
The actual acquisition is done with the function
<function><link linkend="func-ref-comedi-sv-measure">comedi_sv_measure</link></function>:
<funcsynopsis><funcprototype>
<funcdef>int <function>comedi_sv_measure</function></funcdef>
<paramdef>comedi_sv_t *<parameter>sv</parameter></paramdef>
<paramdef>double *<parameter>data</parameter></paramdef>
</funcprototype></funcsynopsis>
The number of samples over which the function
<function>comedi_sv_measure</function> averages is limited by the
implementation (currently the limit is 100 samples).
2003-07-07 22:34:18 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
One typical use for this function is the measurement of thermocouple
voltages.
And 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 a part-per-thousand.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
</section>
<section id="experimentalfunctionality">
<title>
Experimental functionality
</title>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
The following subsections document functionality that has not yet
matured. Most of this functionality has even not been implemented yet
in any single device driver. This information is included here, in
order to stimulate discussion about their API, and to encourage
pioneering implementations.
2002-01-21 15:17:12 +00:00
</para>
2003-07-07 22:34:18 +00:00
<section id="digitalinputcombining">
<title>
Digital input combining machines
</title>
<para>
(<emphasis role="strong">Status: experimental (i.e., no driver implements
this yet)</emphasis>)
</para>
<para>
When one or several digital inputs are used to modify an output
value, either an accumulator or a single digital line or bit,
a bitfield structure is typically used in the &comedi; interface.
The digital inputs have two properties, <quote>sensitive</quote> inputs
and <quote>modifier</quote> inputs. Edge transitions on sensitive
2003-07-07 22:34:18 +00:00
inputs cause changes in the output signal, whereas modifier inputs
change the effect of edge transitions on sensitive inputs. Note that
inputs can be both modifier inputs and sensitive inputs.
</para>
<para>
For simplification purposes, it is assumed that multiple digital
inputs do not change simultaneously.
</para>
<para>
The combined state of the modifier inputs determine a modifier
state. For each combination of modifier state and sensitive
input, there is a set of bits that determine the effect on the
output value due to positive or negative transitions of the
sensitive input. For each transition direction, there are two
bits defined as follows:
<variablelist spacing="compact">
<varlistentry>
<term>00</term>
<listitem>transition is ignored.</listitem>
</varlistentry>
<varlistentry>
<term>01</term>
<listitem>accumulator is incremented, or output is set.</listitem>
</varlistentry>
<varlistentry>
<term>10</term>
<listitem>accumulator is decremented, or output is cleared.</listitem>
</varlistentry>
<varlistentry>
<term>11</term>
<listitem>reserved.</listitem>
</varlistentry>
</variablelist>
2003-07-07 22:34:18 +00:00
For example, a simple digital follower is specified by the bit
pattern 01 10, because it sets the output on positive transitions
of the input, and clears the output on negative transitions. A
digital inverter is similarily 10 01. These systems have only
one sensitive input.
</para>
<para>
As another example, a simple up counter, which increments on
positive transitions of one input, is specified by 01 00. This
system has only one sensitive input.
</para>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
When multiple digital inputs are used, the inputs are divided
into two types, inputs which cause changes in the accumulator, and
those that only modify the meaning of transitions on other inputs.
Modifier inputs do not require bitfields, but there needs to be
a bitfield of length 4*(2^(N-1)) for each edge sensitive input,
where N is the total number of inputs. Since N is usually 2 or
3, with only one edge sensitive input, the scaling issues are
not significant.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
</section>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<section id="analogconversion">
2002-01-21 15:17:12 +00:00
<title>
2003-07-07 22:34:18 +00:00
Analog filtering configuration
2002-01-21 15:17:12 +00:00
</title>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
<emphasis role="strong">(Status: design (i.e., no driver implements
this yet).)</emphasis>
</para>
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield>
field of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
has not been assigned yet.
</para>
<para>
The <structfield><link linkend="insn-data-structure-chanspec">chanspec</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is ignored.
</para>
<para>
Some devices have the capability to add white noise (dithering) to
analog input measurement. This additional noise can then be averaged
out, to get a more accurate measurement of the input signal. It
should not be assumed that channels can be separately configured.
A simple design can use 1 bit to turn this feature on/off.
</para>
<para>
Some devices have the capability of changing the glitch characteristics
of analog output subsytems. The default (off) case should be where
the average settling time is lowest. A simple design can use 1 bit
to turn this feature on/off.
</para>
<para>
Some devices have a configurable analog filters as part of the analog
input stage. A simple design can use 1 bit to enable/disable the
filter. Default is disabled, i.e., the filter being bypassed, or if
the choice is between two filters, the filter with the largest
bandwidth.
</para>
</section>
<section id="waveformgeneration">
<title>
Analog Output Waveform Generation
</title>
<para>
<emphasis role="strong">(Status: design (i.e., no driver implements
this yet).)</emphasis>
</para>
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> field of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
has not been assigned yet.
</para>
<para>
The <structfield><link linkend="insn-data-structure-chanspec">chanspec</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is ignored.
</para>
<para>
Some devices have the ability to cyclicly loop through samples kept in
an on-board analog output FIFO. This config should allow the user to
enable/disable this mode.
</para>
<para>
This config should allow the user to configure the number of samples
to loop through. It may be necessary to configure the channels used.
</para>
</section>
<section id="extendedtriggering">
<title>
Extended Triggering
</title>
<para>
<emphasis role="strong">(Status: alpha.)</emphasis>
</para>
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> field of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
has not been assigned yet.
</para>
<para>
The <structfield><link linkend="insn-data-structure-chanspec">chanspec</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is ignored.
</para>
<para>
This section covers common information for all extended
triggering configuration, and doesn't describe a particular
type of extended trigger.
</para>
<para>
Extended triggering is used to configure triggering engines that
do not fit into commands. In a typical programming sequence, the
application will use
<link linkend="instructionsconfiguration">configuration instructions</link>
to configure an extended trigger, and a
<link linkend="commandsstreaming">command</link>,
specifying
<constant><link linkend="trig-other">TRIG_OTHER</link></constant>
as one of the trigger sources.
2003-07-07 22:34:18 +00:00
</para>
<para>
Extended trigger configuration should be designed in such a way
that the user can probe for valid parameters, similar to how
command testing works. An extended trigger configuration instruction
should not configure the hardware directly, rather, the configuration
should be saved until the subsequent command is issued. This
allows more flexibility for future interface changes.
</para>
<para>
It has not been decided whether the configuration stage should return a
token that is then used as the trigger argument in the command.
Using tokens is one method to satisfy the problem that extended
trigger configurations may have subtle compatiblity issues with
other trigger sources/arguments that can only be determined at
command test time. Passing all stages of a command test should
only be allowed with a properly configured extended trigger.
</para>
<para>
Extended triggers must use
<structfield><link linkend="insn-data-structure-data">data</link></structfield>[1] as flags. The
2003-07-07 22:34:18 +00:00
upper 16 bits are reserved and used only for flags that are common to
all extended triggers. The lower 16 bits may be defined by the
particular type of extended trigger.
</para>
<para>
Various types of extended triggers must use
<structfield><link linkend="insn-data-structure-data">data</link></structfield>[1] to know which
2003-07-07 22:34:18 +00:00
event the extended trigger will be assigned to in the command
structure. The possible values are an OR'd mask of the following:
</para>
<itemizedlist>
<listitem>
<para>
<constant>COMEDI_EV_START</constant>
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<constant>COMEDI_EV_SCAN_BEGIN</constant>
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<constant>COMEDI_EV_CONVERT</constant>
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<constant>COMEDI_EV_SCAN_END</constant>
2003-07-07 22:34:18 +00:00
</para>
</listitem>
<listitem>
<para>
<constant>COMEDI_EV_STOP</constant>
2003-07-07 22:34:18 +00:00
</para>
</listitem>
</itemizedlist>
</section>
<section id="analogtriggering">
<title>
Analog Triggering
</title>
<para>
<emphasis role="strong">
(Status: alpha. The <filename>ni_mio_common.c</filename> driver
2003-07-07 22:34:18 +00:00
implements this feature.)
</emphasis>
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> field of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
has not been assigned yet.
</para>
<para>
The <structfield><link linkend="insn-data-structure-chanspec">chanspec</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is ignored.
</para>
<para>
The <structfield><link linkend="insn-data-structure-data">data</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is used as follows:
<variablelist spacing="compact">
<varlistentry>
<term>data[1]</term>
<listitem>trigger and combining machine configuration.</listitem>
</varlistentry>
<varlistentry>
<term>data[2]</term>
<listitem>analog triggering signal chanspec.</listitem>
</varlistentry>
<varlistentry>
<term>data[3]</term>
<listitem>primary analog level.</listitem>
</varlistentry>
<varlistentry>
<term>data[4]</term>
<listitem>secondary analog level.</listitem>
</varlistentry>
</variablelist>
</para>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
Analog triggering is described by a digital combining machine that
has two sensitive digital inputs. The sensitive digital inputs are
generated by configurable analog comparators. The analog comparators
generate a digital 1 when the analog triggering signal is greater
than the comparator level. The digital inputs are not modifier
inputs. Note, however, there is an effective modifier due to the
restriction that the primary analog comparator level must be less
than the secondary analog comparator level.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
If only one analog comparator signal is used, the combining machine
for the secondary input should be set to ignored, and the secondary
analog level should be set to <literal>0</literal>.
2003-07-07 22:34:18 +00:00
</para>
<para>
The interpretation of the chanspec and voltage levels is device
dependent, but should correspond to similar values of the analog
input subdevice, if possible.
</para>
<para>
Notes: Reading range information is not addressed. This makes it
difficult to convert comparator voltages to data values.
</para>
<para>
Possible extensions: A parameter that specifies the necessary time
that the set condition has to be true before the trigger is generated.
A parameter that specifies the necessary time that the reset condition
has to be true before the state machine is reset.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
</section>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
<section id="bitfieldmatching">
2002-01-21 15:17:12 +00:00
<title>
2003-07-07 22:34:18 +00:00
Bitfield Pattern Matching Extended Trigger
2002-01-21 15:17:12 +00:00
</title>
2003-07-07 22:34:18 +00:00
<para>
<emphasis role="strong">
(Status: design. No driver implements this feature yet.)
</emphasis>
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> field of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
has not been assigned yet.
</para>
<para>
The <structfield><link linkend="insn-data-structure-chanspec">chanspec</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is ignored.
</para>
2002-01-21 15:17:12 +00:00
<para>
The <structfield><link linkend="insn-data-structure-data">data</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is used as follows:
2002-01-21 15:17:12 +00:00
</para>
<variablelist spacing="compact">
<varlistentry>
<term>data[1]</term>
<listitem>trigger flags.</listitem>
</varlistentry>
<varlistentry>
<term>data[2]</term>
<listitem>mask.</listitem>
</varlistentry>
<varlistentry>
<term>data[3]</term>
<listitem>pattern.</listitem>
</varlistentry>
</variablelist>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
The pattern matching trigger issues a trigger when all of a specifed
2003-07-07 22:34:18 +00:00
set of input lines match a specified pattern. If the device allows,
the input lines should correspond to the input lines of a digital input
subdevice, however, this will necessarily be device dependent. Each
possible digital line that can be matched is assigned a bit in the
mask and pattern. A bit set in the mask indicates that the
input line must match the corresponding bit in the pattern.
A bit cleared in the mask indicates that the input line is ignored.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
Notes: This only allows 32 bits in the pattern/mask, which may be
too few. Devices may support selecting different sets of lines from
which to match a pattern.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
Discovery: The number of bits can be discovered by setting the mask
to all 1's. The driver must modify this value and return
<constant>-EAGAIN</constant>.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2003-07-07 22:34:18 +00:00
</section>
<section id="countertimer">
<title>
Counter configuration
</title>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
<emphasis role="strong">
(Status: design. No driver implements this feature yet.)
</emphasis>
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> field of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
has not been assigned yet.
</para>
<para>
The <structfield><link linkend="insn-data-structure-chanspec">chanspec</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is used to specify which counter to use. (I.e., the
counter is a &comedi; channel.)
2002-01-21 15:17:12 +00:00
</para>
<para>
The <structfield><link linkend="insn-data-structure-data">data</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is used as follows:
</para>
<variablelist spacing="compact">
<varlistentry>
<term>data[1]</term>
<listitem>trigger configuration.</listitem>
</varlistentry>
<varlistentry>
<term>data[2]</term>
<listitem>primary input chanspec.</listitem>
</varlistentry>
<varlistentry>
<term>data[3]</term>
<listitem>primary combining machine configuration.</listitem>
</varlistentry>
<varlistentry>
<term>data[4]</term>
<listitem>secondary input chanspec.</listitem>
</varlistentry>
<varlistentry>
<term>data[5]</term>
<listitem>secondary combining machine configuration.</listitem>
</varlistentry>
<varlistentry>
<term>data[6]</term>
<listitem>latch configuration.</listitem>
</varlistentry>
</variablelist>
2003-07-07 22:34:18 +00:00
<para>
Note that this configuration is only useful if the counting has to be
done in <emphasis>software</emphasis>. Many cards offer configurable
counters in hardware; e.g., general purpose timer cards can be
configured to act as pulse generators, frequency counters, timers,
encoders, etc.
</para>
<para>
Counters can be operated either in synchronous mode (using
<constant><link linkend="insn-read">INSN_READ</link></constant>)
or asynchronous mode (using
2003-07-07 22:34:18 +00:00
<link linkend="commandsstreaming">commands</link>), similar to analog
input subdevices.
2003-07-07 22:34:18 +00:00
The input signal for both modes is the accumulator.
Commands on counter subdevices are almost always specified using
<structfield><link linkend="command-data-struct-scan-begin-src">scan_begin_src</link></structfield>
= <constant><link linkend="trigother-event">TRIG_OTHER</link></constant>,
with the counter configuration also serving as the extended configuration for
the <quote>scan begin</quote> source.
2003-07-07 22:34:18 +00:00
</para>
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
Counters are made up of an accumulator and a combining machine that
determines when the accumulator should be incremented or decremented
based on the values of the input signals. The combining machine
optionally determines when the accumulator should be latched and
put into a buffer. This feature is used in asynchronous mode.
2002-01-21 15:17:12 +00:00
</para>
2002-01-21 11:15:31 +00:00
2002-01-21 15:17:12 +00:00
<para>
2003-07-07 22:34:18 +00:00
Note: How to access multiple pieces of data acquired at each event?
2002-01-21 15:17:12 +00:00
</para>
</section>
2003-07-07 22:34:18 +00:00
<section id="auxcounter">
<title>
2003-07-07 22:34:18 +00:00
One source plus auxiliary counter configuration
</title>
2003-07-07 22:34:18 +00:00
<para>
<emphasis role="strong">
(Status: design. No driver implements this feature yet.)
</emphasis>
</para>
<para>
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> field of the
2003-07-07 22:34:18 +00:00
<link linkend="insn-data-structure">instruction data structure</link>
has not been assigned yet.
</para>
<para>
The <structfield><link linkend="insn-data-structure-chanspec">chanspec</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is used to &hellip;
</para>
<para>
The <structfield><link linkend="insn-data-structure-data">data</link></structfield> field
2003-07-07 22:34:18 +00:00
of the <link linkend="insn-data-structure">instruction data
structure</link> is used as follows:
</para>
<para>
<variablelist spacing="compact">
<varlistentry>
<term>data[1]</term>
<listitem>
is flags, including the flags for the command triggering
2003-07-07 22:34:18 +00:00
configuration. If a command is not subsequently issued on the
subdevice, the command triggering portion of the flags are ignored.
</listitem>
</varlistentry>
<varlistentry>
<term>data[2]</term>
<listitem>
determines the mode of operation. The mode of operation
2003-07-07 22:34:18 +00:00
is actually a bitfield that encodes what to do for various
transitions of the source signals.
</listitem>
</varlistentry>
<varlistentry>
<term>data[3]</term>
<term>data[4]</term>
<listitem>
determine the primary source for the counter, similar to the
<structfield><link linkend="command-data-struct-scan-begin-src">&hellip;_src</link></structfield> and the
<structfield><link linkend="command-data-struct-scan-begin-arg">&hellip;_arg</link></structfield> fields
2003-07-07 22:34:18 +00:00
used in the
<link linkend="command-data-struct">command data structure</link>.
</listitem>
</varlistentry>
</variablelist>
</para>
<para>
2003-07-07 22:34:18 +00:00
Notes: How to specify which events cause a latch and push, and what
should get latched?
</para>
</section>
<section id="GPCT">
<title>
National Instruments General Purpose Counters/Timers (GPCT)
</title>
Counters/timers and pulse generators are fairly different in terms of
functionality, but they correspond to similar devices seen either as input
or output. When generalising, these devices are both referred to as
"counters". The NI boards provide a couple of such counters, under the name of
GPCT.
A counter is made of the following basic elements:
<variablelist spacing="compact">
<varlistentry>
<term>Input source</term>
<listitem>the signal measured or the clock of the pulse generation.</listitem>
</varlistentry>
<varlistentry>
<term>Gate</term>
<listitem>controls when the counting (or sampling) occurs.</listitem>
</varlistentry>
<varlistentry>
<term>Register</term>
<listitem>holds the current count.</listitem>
</varlistentry>
<varlistentry>
<term>Out</term>
<listitem>for the output counters (pulse generators), the output signal.</listitem>
</varlistentry>
</variablelist>
<para>
There are many different ways to count, time or generate pulses. All the modes
rely on the counter and some particular configuration. For example, in a typical
buffered counting mode, the source is the (digital) signal that is measured, the
counter is increased at every rising edge of the signal, the gate is the
(digital) signal indicating when to save the counter to memory. It is preferable
you get first familiarized with these various modes by reading your NI board
documentation before reading the following description on the mapping to the
comedi interface.
</para>
<para>
Each counter of the board is represented in comedi as a subdevice of type
<constant>COMEDI_SUBD_COUNTER</constant>. Each subdevice has a device file
associated (eg, <filename>/dev/comedi0_subd11</filename>) in order to read or
write buffered data from or to the counter.
Note that the comedi subdevice has three "channels". In most case, only channel
0 is to be used. Reading or writing on channel 0 corresponds to reading/writing
the counter value. The GPCT also has two registers named A and B, they can be
accessed respectively via channels 1 and 2.
</para>
<para>
To configure the behaviour of the counter with comedi, the
function <function>comedi_set_counter_mode</function> is used.
The possible mode values are to be found in the <type>ni_gpct_mode_bits</type>
enum constants. For instance, by default the counter is cumulative, even in
buffered counting. To reinitialise it after each sampling (ie, after an edge on
the gate signal), one can add the <constant>NI_GPCT_LOADING_ON_GATE_BIT</constant>
to the mode. In that case, the counter will be reset to the value of the A
register after each sampling.
</para>
<para>
To configure the signal to be used as the "source", one uses the <function>
comedi_set_clock_source</function> with one constant from the
<type>ni_gpct_clock_source_bits</type> enum. When the period of the signal is
fixed and known, it should be specified as the last parameter of the method, otherwise
<literal>0</literal> should be passed. Note that in comedi this is called "clock"
because in timer and pulse generator, this signal is used as the clock.
</para>
<para>
To configure the signal to be used as the "gate", one uses the <function>
comedi_set_gate_source</function> with one constant from the <type>
ni_gpct_gate_select</type> enum. When the gate signal is not be used,
<constant>NI_GPCT_DISABLED_GATE_SELECT</constant> should be specified. Some
NI boards have two gates, but the behaviour associated with the second gate is
usually unknown so it is recommended to disable it. Note that this is called
"gate" because in some modes, this signal is used to block/unblock the counter.
</para>
<para>
The function <function>comedi_reset</function> will stop and reset a counter.
After being configured, to start a counter, it should be "armed", which can be
done either with the <function>comedi_arm</function> function (for simple counting
mode), or with the <structfield>start_src</structfield> member of the command
(for buffered counting).
</para>
<para>
One side thing to mention is the signal routing of the NI card, which is done
via the PFIs (Programmable Function Inputs).
NI's naming is confusing because they use the same name for the
terminal (ie, physical input/output pins) and for the signal
(ie, the logical information that controls/indicates a specific event).
The routing allows to configure which signal goes to a PFI terminal.
This is done via <function>comedi_set_routing</function>, with subdevice being
the special DIO comedi subdevice (eg, 7 on M-series), the PFI terminal
number as channel, the signal that should be routed to it encoded as source with
one of the constants from the <type>ni_pfi_routing</type> enum.
The direction of the pin must also be correctly configured (ie, whether it is
used as input or output). This is done via <function>comedi_dio_config</function>
with the same subdevice and channel, and either <constant>COMEDI_INPUT</constant>
or <constant>COMEDI_OUTPUT</constant>.
</para>
</section>
<section id="RTSI">
<title>
National Instruments RTSI trigger bus
</title>
<para>
A number of NI boards support the RTSI (Real Time System Integration) bus.
It's primary use is to synchronize multiple DAQ cards.
On PXI boards, the RTSI lines correspond to the PXI trigger lines 0 to 7. PCI
boards use cables to connect to their RTSI ports.
The RTSI bus consists of 8 digital signal lines numbered 0 to 7 that are bi-directional.
Each of these signal lines
can be configured as an input or output, and the signal appearing on the output
of each line can be configured to one of several internal board timing signals
(although on older boards RTSI line 7 can only be used for the clock signal).
The <systemitem>ni_pcimio</systemitem>, <systemitem>ni_atmio</systemitem>, and
<systemitem>ni_mio_cs</systemitem> drivers expose the RTSI bus
as a digital I/O subdevice (subdevice number 10).
</para>
<para>
The functions <function>comedi_dio_config</function> and
<function>comedi_dio_get_config</function> can be used on
the RTSI subdevice to
set/query the direction (input or output) of each of the RTSI lines individually.
</para>
<para>
The subdevice also supports the
<constant>INSN_CONFIG_SET_CLOCK_SRC</constant> and
<constant>INSN_CONFIG_GET_CLOCK_SRC</constant> configuration
instructions, which can be
used to configure/query what source the board uses to synchronize its
master clock to. The various possibilities are defined in the <filename>comedi.h</filename>
header file:
</para>
<informaltable>
<tgroup cols='2' align='left'>
<thead>
<row>
<entry>Clock Source</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><constant>NI_MIO_INTERNAL_CLOCK</constant></entry>
<entry>
Use the board's internal oscillator.
</entry>
</row>
<row>
<entry><constant>NI_MIO_RTSI_CLOCK</constant></entry>
<entry>
Use the RTSI line 7 as the master clock. This source is
only supported on pre-m-series boards. The newer m-series boards
use <function>NI_MIO_PLL_RTSI_CLOCK</function> instead.
</entry>
</row>
<row>
<entry><constant>NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK</constant></entry>
<entry>
Only available for newer m-series PXI boards. Synchronizes the board's
phased-locked loop (which runs at 80MHz) to the PXI star trigger
line.
</entry>
</row>
<row>
<entry><constant>NI_MIO_PLL_PXI10_CLOCK</constant></entry>
<entry>
Only available for newer m-series PXI boards.
Synchronizes the board's
phased-locked loop (which runs at 80MHz) to the 10 MHz PXI backplane
clock.
</entry>
</row>
<row>
<entry>
<function>NI_MIO_PLL_RTSI_CLOCK<parameter>n</parameter></function>
</entry>
<entry>
Only available for newer m-series boards.
The function returns a clock source which will cause the board's
phased-locked loop (which runs at 80MHz) to syncronize to the RTSI
line specified in the function argument.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
For all clock sources except <constant>NI_MIO_INTERNAL_CLOCK</constant>
and <constant>NI_MIO_PLL_PXI10_CLOCK</constant>,
you should pass the period of the clock your are feeding to the board when
using <constant>INSN_CONFIG_SET_CLOCK_SRC</constant>.
</para>
<para>
Finally, the configuration instructions
<constant>INSN_CONFIG_SET_ROUTING</constant> and
<constant>INSN_CONFIG_GET_ROUTING</constant>
can be used to select/query which internal signal
will appear on a given RTSI output line. The header file <filename>comedi.h</filename> defines
the following signal sources which can be routed to an RTSI line:
</para>
<informaltable>
<tgroup cols='2' align='left'>
<thead>
<row>
<entry>Signal Source</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><constant>NI_RTSI_OUTPUT_ADR_START1</constant></entry>
<entry>
ADR_START1, an analog input start signal. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_ADR_START2</constant></entry>
<entry>
ADR_START2, an analog input stop signal. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_SCLKG</constant></entry>
<entry>
SCLKG, a sample clock signal. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_DACUPDN</constant></entry>
<entry>
DACUPDN, a dac update signal. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_DA_START1</constant></entry>
<entry>
DA_START1, an analog output start signal. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_G_SRC0</constant></entry>
<entry>
G_SRC0, the source signal to general purpose counter 0. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_G_GATE0</constant></entry>
<entry>
G_GATE0, the gate signal to general purpose counter 0. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_RGOUT0</constant></entry>
<entry>
RGOUT0, the output signal of general purpose counter 0. See the NI's
DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry>
<function>NI_RTSI_OUTPUT_RTSI_BRD<parameter>n</parameter></function>
</entry>
<entry>
RTSI_BRD0 though RTSI_BRD3 are four internal signals which can
have various other signals routed to them in turn. Currently, comedi
provides no way to configure the signals routed to the RTSI_BRD lines.
See the NI's DAQ-STC Technical Reference Manual for more information.
</entry>
</row>
<row>
<entry><constant>NI_RTSI_OUTPUT_RTSI_OSC</constant></entry>
<entry>
The RTSI clock signal. On pre-m-series boards, this signal is always
routed to RTSI line 7, and cannot be routed to lines 0 through 6. On
m-series boards, any RTSI line can be configured to output the clock
signal.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>
The RTSI bus pins may be used as trigger inputs for many of the
&comedi; trigger functions. To use the RTSI bus pins, set the source to be
<constant>TRIG_EXT</constant> and the source argument using the return values
from the <function>NI_EXT_RTSI<parameter>n</parameter></function> function (or similarly the
<function>NI_EXT_PFI<parameter>n</parameter></function> function if you want
to trigger from a PFI line). The <constant>CR_EDGE</constant> and
<constant>CR_INVERT</constant> flags may
also be set on the trigger source argument to specify edge and
falling edge/low level triggering.
</para>
<para>
An example to set up a device as a master is given below.
</para>
<programlisting><![CDATA[
void comediEnableMaster(comedi_t *dev){
comedi_insn configCmd;
lsampl_t configData[2];
int ret;
unsigned int d = 0;
static const unsigned rtsi_subdev = 10;
static const unsigned rtsi_clock_line = 7;
/* Route RTSI clock to line 7 (not needed on pre-m-series boards since their
clock is always on line 7). */
memset(&configCmd, 0, sizeof(configCmd));
memset(&configData, 0, sizeof(configData));
configCmd.insn = INSN_CONFIG;
configCmd.subdev = rtsi_subdev;
configCmd.chanspec = rtsi_clock_line;
configCmd.n = 2;
configCmd.data = configData;
configCmd.data[0] = INSN_CONFIG_SET_ROUTING;
configCmd.data[1] = NI_RTSI_OUTPUT_RTSI_OSC;
ret = comedi_do_insn(dev, &configCmd);
if(ret < 0){
comedi_perror("comedi_do_insn: INSN_CONFIG");
exit(1);
}
// Set clock RTSI line as output
ret = comedi_dio_config(dev, rtsi_subdev, rtsi_clock_line, INSN_CONFIG_DIO_OUTPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
/* Set routing of the 3 main AI RTSI signals and their direction to output.
We're reusing the already initialized configCmd instruction here since
it's mostly the same. */
configCmd.chanspec = 0;
configCmd.data[1] = NI_RTSI_OUTPUT_ADR_START1;
ret = comedi_do_insn(dev, &configCmd);
if(ret < 0){
comedi_perror("comedi_do_insn: INSN_CONFIG");
exit(1);
}
ret = comedi_dio_config(dev, rtsi_subdev, 0, INSN_CONFIG_DIO_OUTPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
configCmd.chanspec = 1;
configCmd.data[1] = NI_RTSI_OUTPUT_ADR_START2;
ret = comedi_do_insn(dev, &configCmd);
if(ret < 0){
comedi_perror("comedi_do_insn: INSN_CONFIG");
exit(1);
}
ret = comedi_dio_config(dev, rtsi_subdev, 1, INSN_CONFIG_DIO_OUTPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
configCmd.chanspec = 2;
configCmd.data[1] = NI_RTSI_OUTPUT_SCLKG;
ret = comedi_do_insn(dev, &configCmd);
if(ret < 0){
comedi_perror("comedi_do_insn: INSN_CONFIG");
exit(1);
}
ret = comedi_dio_config(dev, rtsi_subdev, 2, INSN_CONFIG_DIO_OUTPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
}
]]></programlisting>
<para>
An example to slave a m-series device from this master follows. A pre-m-series
device would need to use <constant>NI_MIO_RTSI_CLOCK</constant> for
the clock source instead. In
your code, you may also wish to configure the master device to use the
external clock source instead of using its internal clock directly (for
best syncronization).
</para>
<programlisting><![CDATA[
void comediEnableSlave(comedi_t *dev){
comedi_insn configCmd;
lsampl_t configData[3];
int ret;
unsigned int d = 0;;
static const unsigned rtsi_subdev = 10;
static const unsigned rtsi_clock_line = 7;
memset(&configCmd, 0, sizeof(configCmd));
memset(&configData, 0, sizeof(configData));
configCmd.insn = INSN_CONFIG;
configCmd.subdev = rtsi_subdev;
configCmd.chanspec = 0;
configCmd.n = 3;
configCmd.data = configData;
configCmd.data[0] = INSN_CONFIG_SET_CLOCK_SRC;
configCmd.data[1] = NI_MIO_PLL_RTSI_CLOCK(rtsi_clock_line);
configCmd.data[2] = 100; /* need to give it correct external clock period */
ret = comedi_do_insn(dev, &configCmd);
if(ret < 0){
comedi_perror("comedi_do_insn: INSN_CONFIG");
exit(1);
}
/* configure RTSI clock line as input */
ret = comedi_dio_config(dev, rtsi_subdev, rtsi_clock_line, INSN_CONFIG_DIO_INPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
/* Configure RTSI lines we are using for AI signals as inputs. */
ret = comedi_dio_config(dev, rtsi_subdev, 0, INSN_CONFIG_DIO_INPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
ret = comedi_dio_config(dev, rtsi_subdev, 1, INSN_CONFIG_DIO_INPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
ret = comedi_dio_config(dev, rtsi_subdev, 2, INSN_CONFIG_DIO_INPUT);
if(ret < 0){
comedi_perror("comedi_dio_config");
exit(1);
}
}
int comediSlaveStart(comedi_t *dev){
comedi_cmd cmd;
unsigned int nChannels = 8;
double sampleRate = 50000;
unsigned int chanList[8];
int i;
// Setup chan list
for(i = 0; i < nChannels; i++){
chanList[i] = CR_PACK(i, 0, AREF_GROUND);
}
// Set up command
memset(&cmd, 0, sizeof(cmd));
ret = comedi_get_cmd_generic_timed(dev, subdevice, &cmd,
(int)(1e9/(nChannels * sampleRate)));
if(ret<0){
printf("comedi_get_cmd_generic_timed failed\n");
return ret;
}
cmd.chanlist = chanList;
cmd.chanlist_len = nChannels;
cmd.scan_end_arg = nChannels;
cmd.start_src = TRIG_EXT;
cmd.start_arg = CR_EDGE | NI_EXT_RTSI(0);
cmd.convert_src = TRIG_EXT;
cmd.convert_arg = CR_INVERT | CR_EDGE | NI_EXT_RTSI(2);
cmd.stop_src = TRIG_NONE;
ret = comedi_command(dev0, &cmd0);
if(ret<0){
printf("comedi_command failed\n");
return ret;
}
return 0;
}
]]></programlisting>
2002-01-21 15:17:12 +00:00
</section>
</section>
2003-07-07 22:34:18 +00:00
</section>
2002-01-21 11:15:31 +00:00