4.  Acquisition and configuration functions

4.1. Functions for single acquisition
4.2. Instructions for multiple acquisitions
4.3. Instructions for configuration
4.4. Instruction for internal triggering
4.5. Commands for streaming acquisition
4.6. Slowly-varying inputs
4.7. Experimental functionality

This Section gives an overview of all Comedi functions with which application programmers can implement their data acquisition. (With acquisition we mean all possible kinds of interfacing with the cards: input, output, configuration, streaming, etc.) Section 5 explains the function calls in full detail.

4.1.  Functions for single acquisition

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 digital and analog acquisitions.

4.1.1.  Single digital acquisition

Many boards supported by Comedi have digital input and output channels; i.e., channels that can only produce a 0 or a 1. Some boards allow the direction (input or output) of each channel to be specified independently in software.

Comedi groups digital channels into a subdevice, which is a group of digital channels that have the same characteristics. For example, digital output lines will be grouped into a digital output subdevice, bidirectional digital lines will be grouped into a digital I/O subdevice. Thus, there can be multiple digital subdevices on a particular board.

Individual bits on a digital I/O device can be read and written using the functions comedi_dio_read and comedi_dio_write:

int comedi_dio_read(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel,
 unsigned int *bit);
 

int comedi_dio_write(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel,
 unsigned int bit);
 

The device parameter is a pointer to a successfully opened Comedi device. The subdevice and channel parameters are positive integers that indicate which subdevice and channel is used in the acquisition. The integer bit contains the value of the acquired bit.

The direction of bidirectional lines can be configured using the function comedi_dio_config:

int comedi_dio_config(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel,
 unsigned int dir);
 

The parameter dir should be either COMEDI_INPUT or COMEDI_OUTPUT. Many digital I/O subdevices group channels into blocks for configuring direction. Changing one channel in a block changes the entire block.

Multiple channels can be read and written simultaneously using the function comedi_dio_bitfield2:

int comedi_dio_bitfield2(comedi_t *device,
 unsigned int subdevice,
 unsigned int write_mask,
 unsigned int *bits,
 unsigned int base_channel);
 

Each channel from base_channel to base_channel + 31 is assigned to a bit in the write_mask and bits bitfield with bit 0 assigned to channel base_channel, bit 1 assigned to channel base_channel + 1, etc. If a bit in write_mask is set, the corresponding bit in *bits will be written to the digital output line corresponding to the channel given by base_channel plus the bit number. Each digital line is then read and placed into *bits. The value of bits in *bits corresponding to digital output lines is undefined and device-specific. Channel base_channel + 0 is the least significant bit in the bitfield. No more than 32 channels at once can be accessed using this method. Warning! Older versions of Comedi may ignore base_channel and treat it as 0 unless the subdevice has more than 32 channels.

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 instruction command.

4.1.2.  Single analog acquisition

Analog Comedi channels can produce data values that are samples from continuous analog signals. These samples are integers with a significant content in the range of, typically, 8, 10, 12, or 16 bits.

Single samples can be read from an analog channel using the function comedi_data_read:

int comedi_data_read(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel,
 unsigned int range,
 unsigned int aref,
 lsampl_t *data);
 

This reads one such data value from a Comedi channel, and puts it in the user-specified data buffer.

The range 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 comedi_get_n_ranges to get the number of ranges supported by the channel, the function comedi_find_range to search for a suitable range, or the function comedi_get_range to get the details of a supported range.

The aref parameter specifies an analog reference to use: AREF_GROUND, AREF_COMMON, AREF_DIFF, or AREF_OTHER. Use the function comedi_get_subdevice_flags to see which analog references are supported by the subdevice.

In the opposite direction, single samples can be written to an analog output channel using the function comedi_data_write:

int comedi_data_write(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel,
 unsigned int range,
 unsigned int aref,
 lsampl_t data);
 

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 comedi_get_maxdata:

lsampl_t comedi_get_maxdata(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel);
 

Conversion between raw data values and uncalibrated physical units can be performed by the functions comedi_to_phys and comedi_from_phys:

double comedi_to_phys(lsampl_t data,
 comedi_range *range,
 lsampl_t maxdata);
 

lsampl_t comedi_from_phys(double data,
 comedi_range *range,
 lsampl_t maxdata);
 

There are some data structures in these commands that are not fully self-explanatory:

  • comedi_t: this data structure contains all information that a user program has to know about an open Comedi device. The programmer doesn't have to fill in this data structure manually: it gets filled in by opening the device.

  • lsampl_t: this data structure 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 correct integers. This is called data munging.

  • comedi_range: 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 maxdata value to convert between unsigned integer sample values (of type lsampl_t or sampl_t) and physical units in a nominal (uncalibrated) way using the comedi_to_phys and comedi_from_phys functions. Use the comedi_get_maxdata function to get the maxdata value for the channel.

    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 SDF_RANGETYPE subdevice flag indicates whether ranges are channel-specific.)

Each single acquisition by, for example, comedi_data_read 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, comedi_data_read_n:

int comedi_data_read_n(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel,
 unsigned int range,
 unsigned int aref,
 lsampl_t *data,
 unsigned int n);
 

The number of samples, n, is limited by the Comedi implementation (to a maximum of 100 samples), because the call is blocking.

The start of the a single data acquisition can also be delayed by a specified number of nano-seconds using the function comedi_data_read_delayed:

int comedi_data_read_delayed(comedi_t *device,
 unsigned int subdevice,
 unsigned int channel,
 unsigned int range,
 unsigned int aref,
 lsampl_t *data,
 unsigned int nano_sec);
 

All these read and write acquisition functions are implemented on top of the generic instruction command.