
This patch documents the new interpretation of stop_arg when stop_src == TRIG_NONE. In the new interpretation, if stop_src==TRIG_NONE, a user may specify that a buffer of finite length (and less than or equal to the maximum buffer size) be repeated indefinitely. For now, only the NI MIO driver implements this new interpretation. All other drivers should continue to force stop_arg==0 when stop_src==TRIG_NONE. In this case, the old behavior is maintained.
2512 lines
87 KiB
XML
2512 lines
87 KiB
XML
<?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;
|
|
]>
|
|
|
|
<section id="acquisitionfunctions">
|
|
<title>
|
|
Acquisition and configuration functions
|
|
</title>
|
|
|
|
<para>
|
|
This Section gives an overview of all &comedi; functions with which
|
|
application programmers can implement their data acquisition. (With
|
|
<quote>acquisition</quote> we mean all possible kinds of interfacing
|
|
with the cards: input, output, configuration, streaming, etc.)
|
|
<xref linkend="comedireference"/> explains the function calls in full
|
|
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
|
|
<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
|
|
integers that indicate which subdevice and channel is used in the
|
|
acquisition. The integer <parameter class="function">bit</parameter>
|
|
contains the value of the acquired bit.
|
|
</para>
|
|
<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>.
|
|
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> +
|
|
<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> +
|
|
<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
|
|
to digital output lines is undefined and device-specific. Channel
|
|
<parameter class="function">base_channel</parameter> +
|
|
<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.
|
|
</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.
|
|
</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
|
|
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
|
|
self-explanatory:
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>
|
|
<type><link linkend="ref-type-comedi-t">comedi_t</link></type>: this data structure
|
|
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
|
|
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>.
|
|
</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>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</para>
|
|
<para>
|
|
Each single acquisition by, for example,
|
|
<function><link linkend="func-ref-comedi-data-read">comedi_data_read</link></function>
|
|
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
|
|
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>
|
|
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
|
|
</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"/>
|
|
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>
|
|
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
|
|
// (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
|
|
unsigned int subdev; // subdevice
|
|
unsigned int <anchor id="insn-data-structure-chanspec"/><link linkend="ref-macro-CR-PACK">chanspec</link>; // encoded channel specification
|
|
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.
|
|
</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>
|
|
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.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<constant>INSN_WRITE</constant>: the instruction executes a write on an
|
|
analog channel.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<constant>INSN_BITS</constant>: indicates that the instruction must
|
|
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.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<constant>INSN_WAIT</constant>: the instruction blocks for a specified
|
|
number of nanoseconds.
|
|
</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>
|
|
|
|
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>
|
|
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
|
|
implementation, because instructions are executed
|
|
<emphasis>synchronously</emphasis>, i.e., the call blocks until the
|
|
whole instruction (list) has finished.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
|
|
<section id="instructionsconfiguration">
|
|
<title>
|
|
Instructions for configuration
|
|
</title>
|
|
<para>
|
|
<xref linkend="instructions"/> explains how instructions are used to do
|
|
<emphasis>acquisition</emphasis> on channels. This section explains
|
|
how they are used to <emphasis>configure</emphasis> a subdevice.
|
|
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
|
|
<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>
|
|
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
|
|
<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.
|
|
</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>
|
|
|
|
<para>
|
|
See the comedilib demo program <filename>demo/choose_clock.c</filename> for an example
|
|
of using a configuration instruction.
|
|
</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
|
|
<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>.
|
|
</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),
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
for <emphasis>any number of channels</emphasis>,
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
with an <emphasis>arbitrary order</emphasis> of channels in each scan
|
|
(possibly even with repeated channels per scan),
|
|
</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
|
|
<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
|
|
<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>
|
|
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>
|
|
|
|
The following sections explain the meaning of the
|
|
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> data structure.
|
|
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>
|
|
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>
|
|
function.
|
|
</para>
|
|
|
|
</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:
|
|
<programlisting>
|
|
typedef struct comedi_cmd_struct comedi_cmd;
|
|
|
|
struct comedi_cmd_struct {
|
|
unsigned int subdev; // which subdevice to sample
|
|
unsigned int <anchor id="command-data-struct-flags"/>flags; // encode some configuration possibilities
|
|
// 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
|
|
|
|
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`
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
};
|
|
</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"/>.
|
|
</para>
|
|
|
|
<para>
|
|
The <parameter class="function">subdev</parameter> member of the
|
|
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> structure is
|
|
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>
|
|
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>
|
|
member of the
|
|
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> data
|
|
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>
|
|
(this will generally be the same as the
|
|
<structfield><link linkend="command-data-struct-scan-end-arg">scan_end_arg</link></structfield>).
|
|
The
|
|
<structfield><link linkend="command-data-struct-chanlist">chanlist</link></structfield>
|
|
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
|
|
information together with the
|
|
<function><link linkend="ref-macro-CR-PACK">CR_PACK</link></function>
|
|
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>
|
|
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
|
|
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,
|
|
i.e., bits in a word that can be bitwise-or'd together. The meaning of
|
|
these bits are explained in
|
|
<xref linkend="comedicmdflags"/>.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
|
|
<section id="comedicmdsources">
|
|
<title>
|
|
The command trigger events
|
|
<anchor id="source.trigger.anchor"/>
|
|
</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
|
|
<link linkend="acquisitionterminology">acquisition</link>,
|
|
start a <link linkend="scan">scan</link>, start a
|
|
<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">…_src</parameter> members in the
|
|
<type><link linkend="ref-type-comedi-cmd">comedi_cmd</link></type> data
|
|
structure). And each event source can have a corresponding
|
|
argument (the <parameter class="function">…_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
|
|
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>.
|
|
</para>
|
|
<para>
|
|
The following paragraphs discuss in somewhat more detail the trigger
|
|
event sources(<parameter class="function">…_src</parameter>), and the
|
|
corresponding arguments (<parameter class="function">…_arg</parameter>).
|
|
</para>
|
|
<para>
|
|
The start of an acquisition is controlled by the
|
|
<structfield><link linkend="command-data-struct-start-src">start_src</link></structfield> events.
|
|
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
|
|
supported.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<anchor id="trig-follow-start-src"/>
|
|
<constant>TRIG_FOLLOW</constant>: (For an output device.) The <quote>start</quote>
|
|
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>
|
|
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.
|
|
</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.
|
|
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>
|
|
events is
|
|
<structfield><link linkend="command-data-struct-scan-begin-arg">scan_begin_arg</link></structfield>
|
|
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>
|
|
event occurs.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<anchor id="trig-ext-start-scan"/>
|
|
<constant>TRIG_EXT</constant>: the <quote>scan begin</quote>
|
|
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>
|
|
chooses the particular digital line.
|
|
</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
The
|
|
<structfield><link linkend="command-data-struct-scan-begin-arg">scan_begin_arg</link></structfield>
|
|
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>.
|
|
</para>
|
|
<para>
|
|
The timing between each sample in a
|
|
<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:
|
|
<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>
|
|
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>
|
|
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
|
|
<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
|
|
could probably find a device that allows something else, but it would
|
|
be strange.
|
|
</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:
|
|
<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>
|
|
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>.
|
|
</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.
|
|
</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>:
|
|
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.
|
|
</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>
|
|
instructions.
|
|
</para>
|
|
<para>
|
|
The argument is reserved and should be set to <literal>0</literal>.
|
|
</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>
|
|
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"/>
|
|
</title>
|
|
|
|
<para>
|
|
The
|
|
<structfield><link linkend="command-data-struct-flags">flags</link></structfield>
|
|
field in the
|
|
<link linkend="ref-type-comedi-cmd">command data structure</link>
|
|
is used to specify some <quote>behaviour</quote> of the acquisitions in
|
|
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
|
|
<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
|
|
<ulink url="http://www.rtlinux-gpl.org/">RTLinux/GPL</ulink>)
|
|
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
|
|
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>:
|
|
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.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<anchor id="trig-round-up"/>
|
|
<constant>TRIG_ROUND_UP</constant>: round period up.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<anchor id="trig-round-up-next"/>
|
|
<constant>TRIG_ROUND_UP_NEXT</constant>:
|
|
this one doesn't do anything, and I don't know what it was intended
|
|
to do…?
|
|
</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>.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<anchor id="trig-deglitch"/>
|
|
<constant>TRIG_DEGLITCH</constant>: enable deglitching?
|
|
Another <quote>noise</quote> smoothing technique.
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<anchor id="trig-write"/>
|
|
<constant>TRIG_WRITE</constant>:
|
|
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?
|
|
</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>
|
|
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>
|
|
</section>
|
|
|
|
|
|
<section id="slowlyvarying">
|
|
<title>
|
|
Slowly-varying inputs
|
|
</title>
|
|
|
|
<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>
|
|
|
|
<para>
|
|
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>.
|
|
Obviously, there are limitations to this:
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
|
|
<listitem>
|
|
<para>
|
|
you are ultimately limited by <quote>Spurious Free Dynamic
|
|
Range</quote>. This SFDR is one of the popular measures to quantify how
|
|
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
|
|
or more of the fundamental harmonics of the measured signal, and lots
|
|
of little <quote>peaks</quote> (called <quote>spurs</quote>) caused by
|
|
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!).
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
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.)
|
|
</para>
|
|
</listitem>
|
|
|
|
<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>
|
|
|
|
<listitem>
|
|
<para>
|
|
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.
|
|
</para>
|
|
</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
|
|
to do the averaging acquisition:
|
|
<programlisting>
|
|
typedef struct comedi_sv_struct {
|
|
<link linkend="ref-type-comedi-t">comedi_t</link> *dev;
|
|
unsigned int subdevice;
|
|
unsigned int chan;
|
|
|
|
/* range policy */
|
|
int range;
|
|
int aref;
|
|
|
|
/* number of measurements to average (for analog inputs) */
|
|
int n;
|
|
|
|
lsampl_t maxdata;
|
|
} comedi_sv_t;
|
|
</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).
|
|
</para>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section id="experimentalfunctionality">
|
|
<title>
|
|
Experimental functionality
|
|
</title>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<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
|
|
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>
|
|
|
|
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>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
|
|
<section id="analogconversion">
|
|
<title>
|
|
Analog filtering configuration
|
|
</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
|
|
<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
|
|
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
|
|
<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
|
|
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
|
|
<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
|
|
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.
|
|
</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
|
|
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
|
|
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>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<constant>COMEDI_EV_SCAN_BEGIN</constant>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<constant>COMEDI_EV_CONVERT</constant>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<constant>COMEDI_EV_SCAN_END</constant>
|
|
</para>
|
|
</listitem>
|
|
<listitem>
|
|
<para>
|
|
<constant>COMEDI_EV_STOP</constant>
|
|
</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
|
|
implements this feature.)
|
|
</emphasis>
|
|
</para>
|
|
|
|
<para>
|
|
The <structfield><link linkend="insn-data-structure-insn">insn</link></structfield> field of the
|
|
<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
|
|
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
|
|
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>
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
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>.
|
|
</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.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section id="bitfieldmatching">
|
|
<title>
|
|
Bitfield Pattern Matching Extended Trigger
|
|
</title>
|
|
<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
|
|
<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
|
|
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
|
|
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 flags.</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>data[2]</term>
|
|
<listitem>mask.</listitem>
|
|
</varlistentry>
|
|
<varlistentry>
|
|
<term>data[3]</term>
|
|
<listitem>pattern.</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
|
|
<para>
|
|
The pattern matching trigger issues a trigger when all of a specifed
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
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>.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section id="countertimer">
|
|
<title>
|
|
Counter configuration
|
|
</title>
|
|
<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
|
|
<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
|
|
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.)
|
|
</para>
|
|
|
|
<para>
|
|
The <structfield><link linkend="insn-data-structure-data">data</link></structfield> field
|
|
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>
|
|
|
|
<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
|
|
<link linkend="commandsstreaming">commands</link>), similar to analog
|
|
input subdevices.
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
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.
|
|
</para>
|
|
|
|
<para>
|
|
Note: How to access multiple pieces of data acquired at each event?
|
|
</para>
|
|
|
|
</section>
|
|
|
|
<section id="auxcounter">
|
|
<title>
|
|
One source plus auxiliary counter configuration
|
|
</title>
|
|
<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
|
|
<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
|
|
of the <link linkend="insn-data-structure">instruction data
|
|
structure</link> is used to …
|
|
</para>
|
|
|
|
<para>
|
|
The <structfield><link linkend="insn-data-structure-data">data</link></structfield> field
|
|
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
|
|
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
|
|
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">…_src</link></structfield> and the
|
|
<structfield><link linkend="command-data-struct-scan-begin-arg">…_arg</link></structfield> fields
|
|
used in the
|
|
<link linkend="command-data-struct">command data structure</link>.
|
|
</listitem>
|
|
</varlistentry>
|
|
</variablelist>
|
|
</para>
|
|
|
|
<para>
|
|
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>
|
|
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
|