%comedilib_entities; ]>
Acquisition and configuration functions 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.) explains the function calls in full detail.
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.
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.
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.
Instructions for multiple acquisitions The instruction 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 configuration of a channel. An instruction list is a list of instructions, possibly on different channels. Both instructions and instructions lists are executed synchronously, i.e., while blocking 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 command acquisition primitive.
The instruction data structure All the information needed to execute an instruction is stored in the comedi_insn data structure: typedef struct comedi_insn_struct { unsigned int insn; // integer encoding the type of acquisition // (or configuration) unsigned int n; // number of elements in data array lsampl_t *data; // pointer to data buffer unsigned int subdev; // subdevice unsigned int chanspec; // encoded channel specification unsigned int unused[3]; } comedi_insn; 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 data field to be at least one byte long. The insn member of the instruction data structure determines the type of acquisition executed in the corresponding instruction: INSN_READ: the instruction executes a read on an analog channel. INSN_WRITE: the instruction executes a write on an analog channel. INSN_BITS: indicates that the instruction must read or write values on multiple digital I/O channels. INSN_GTOD: the instruction performs a Get Time Of Day acquisition. INSN_WAIT: the instruction blocks for a specified number of nanoseconds.
Instruction execution Once an instruction data structure has been filled in, the corresponding instruction is executed with the function comedi_do_insn: int comedi_do_insn comedi_t *device comedi_insn *instruction Many &comedi; instructions are shortcuts that relieve the programmer from explicitly filling in the data structure and calling the comedi_do_insn function. A list of instructions can be executed in one function call using the function comedi_do_insnlist: int comedi_do_insnlist comedi_t *device comedi_insnlist *list The parameter list is a pointer to a comedi_insnlist data structure holding a pointer to an array of comedi_insn and the number of instructions in the list: typedef struct comedi_insnlist_struct { unsigned int n_insns; comedi_insn *insns; } comedi_insnlist; The number of instructions in the list is limited in the implementation, because instructions are executed synchronously, i.e., the call blocks until the whole instruction (list) has finished.
Instructions for configuration explains how instructions are used to do acquisition on channels. This section explains how they are used to configure a subdevice. There are various sorts of configurations, and the specific information for each different configuration possibility is to be specified via the data buffer of the instruction data structure. (So, the pointer to a lsampl_t is misused as a pointer to an array with board-specific information.) Using INSN_CONFIG as the insn member in an instruction data structure indicates that the instruction will not perform acquisition on a channel, but will configure that channel. The chanspec member in the comedi_insn 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. data[0] Description n (number of elements in data array) Meanings of data[1], ..., data[n-1] INSN_CONFIG_DIO_INPUT Configure a DIO line as input. It is easier to use comedi_dio_config than to use this configuration instruction directly. 1 n/a INSN_CONFIG_DIO_OUTPUT Configure a DIO line as output. It is easier to use comedi_dio_config than to use this configuration instruction directly. 1 n/a INSN_CONFIG_ALT_SOURCE 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 CR_ALT_SOURCE flag in the chanspec when reading to actually read from the configured alternate input source. If you are using comedi_data_read, then the channel parameter can be bitwise or'd with the CR_ALT_SOURCE flag. 2 data[1]: alternate input source. INSN_CONFIG_BLOCK_SIZE 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. 2 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. INSN_CONFIG_DIO_QUERY 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 comedi_dio_get_config than to use this instruction directly. 2 data[1]: The instruction sets this element to either COMEDI_INPUT or COMEDI_OUTPUT. See the comedilib demo program demo/choose_clock.c for an example of using a configuration instruction.
Instruction for internal triggering This special instruction has INSN_INTTRIG as the insn member in its instruction data structure. Its execution causes an internal triggering event. 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. The data[0] element of the INSN_INTTRIG instruction is reserved for future use, and should be set to 0.
Commands for streaming acquisition The most powerful &comedi; acquisition primitive is the command. It's powerful because, with one single command, the programmer launches: a possibly infinite sequence of acquisitions, accompanied with various callback functionalities (DMA, interrupts, driver-specific callback functions), for any number of channels, with an arbitrary order of channels in each scan (possibly even with repeated channels per scan), and with various scan triggering sources, external (i.e., hardware pulses) as well as internal (i.e., pulses generated on the DAQ card itself, or generated by a software trigger instruction). 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. A command specifies a particular data acquisition sequence, which consists of a number of scans, and each scan is comprised of a number of conversions, 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. The command function is complementary to the configuration instruction function: each channel in the command's chanlist should first be configured by an appropriate instruction.
Executing a command A command is executed by the function comedi_command: int comedi_command comedi_t *device comedi_cmd *command The following sections explain the meaning of the comedi_cmd 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 comedi_command_test 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. A &comedi; program can find out on-line what the command capabilities of a specific device are, by means of the comedi_get_cmd_src_mask function.
The command data structure The command executes according to the information about the requested acquisition, which is stored in the comedi_cmd data structure: typedef struct comedi_cmd_struct comedi_cmd; struct comedi_cmd_struct { unsigned int subdev; // which subdevice to sample unsigned int 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 start_src; // event to make the acquisition start unsigned int start_arg; // parameters that influence this start unsigned int scan_begin_src; // event to make a particular scan start unsigned int scan_begin_arg; // parameters that influence this start` unsigned int convert_src; // event to make a particular conversion start unsigned int convert_arg; // parameters that influence this start unsigned int scan_end_src; // event to make a particular scan terminate unsigned int scan_end_arg; // parameters that influence this termination unsigned int stop_src; // what make the acquisition terminate unsigned int stop_arg; // parameters that influence this termination unsigned int *chanlist; // pointer to list of channels to be sampled unsigned int chanlist_len; // number of channels to be sampled sampl_t *data; // address of buffer unsigned int data_len; // number of samples to acquire }; 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 event. More on these in . The subdev member of the comedi_cmd structure is the index of the subdevice the command is intended for. The comedi_find_subdevice_by_type function can be useful in discovering the index of your desired subdevice. The chanlist member of the comedi_cmd data structure should point to an array whose number of elements is specified by chanlist_len (this will generally be the same as the scan_end_arg). The chanlist specifies the sequence of channels and gains (and analog references) that should be stepped through for each scan. The elements of the chanlist array should be initialized by packing the channel, range and reference information together with the CR_PACK macro. The data and data_len members can be safely ignored when issueing commands from a user-space program. They only have meaning when a command is sent from a kernel module using the kcomedilib interface, in which case they specify the buffer where the driver should write/read its data to/from. The final member of the comedi_cmd structure is the flags field, i.e., bits in a word that can be bitwise-or'd together. The meaning of these bits are explained in .
The command trigger events <anchor id="source.trigger.anchor"/> 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 data structure has five types of events: start the acquisition, start a scan, start a conversion, stop a scan, and stop the acquisition. Each event can be given its own source (the …_src members in the comedi_cmd data structure). And each event source can have a corresponding argument (the …_arg members of the comedi_cmd data structure) whose meaning depends on the type of source trigger. For example, to specify an external digital line 3 as a source (in general, any of the five event sources), you would use src=TRIG_EXT and arg=3. The following paragraphs discuss in somewhat more detail the trigger event sources(…_src), and the corresponding arguments (…_arg). The start of an acquisition is controlled by the start_src events. The available options are: TRIG_NOW: the start event occurs start_arg nanoseconds after the command is set up. Currently, only start_arg=0 is supported. TRIG_FOLLOW: (For an output device.) The start event occurs when data is written to the buffer. TRIG_EXT: the start event occurs when an external trigger signal occurs; e.g., a rising edge of a digital line. start_arg chooses the particular digital line. TRIG_INT: the start event occurs on a &comedi; internal signal, which is typically caused by an INSN_INTTRIG instruction. The start of the beginning of each scan is controlled by the scan_begin_src events. The available options are: TRIG_TIMER: scan begin events occur periodically. The time between scan begin events is scan_begin_arg nanoseconds. TRIG_FOLLOW: The scan begin event occurs immediately after a scan end event occurs. TRIG_EXT: the scan begin event occurs when an external trigger signal occurs; e.g., a rising edge of a digital line. scan_begin_arg chooses the particular digital line. The scan_begin_arg used here may not be supported exactly by the device, but it will be adjusted to the nearest supported value by comedi_command_test. The timing between each sample in a scan is controlled by the convert_src events. The available options are: TRIG_TIMER: the conversion events occur periodically. The time between convert events is convert_arg nanoseconds. TRIG_EXT: the conversion events occur when an external trigger signal occurs, e.g., a rising edge of a digital line. convert_arg chooses the particular digital line. TRIG_NOW: All conversion events in a scan occur simultaneously. The end of each scan is almost always specified by setting the scan_end_src event to TRIG_COUNT, with the argument being the same as the number of channels in the chanlist. You could probably find a device that allows something else, but it would be strange. The end of an acquisition is controlled by stop_src event. The available options are: TRIG_COUNT: stop the acquisition after stop_arg scans. TRIG_NONE: perform continuous acquisition, until stopped using comedi_cancel. stop_arg is used to denote how many samples should be used in the continuous acquisition. If stop_arg is set to 0, the entire output buffer may contribute to the output. If stop_arg != 0, only the memory for stop_arg samples will be used. Many drivers do not yet support stop_arg!=0 and should enforce stop_arg=0 via comedi_command_test. There are a couple of less usual or not yet implemented events: TRIG_TIME: cause an event to occur at a particular time. (This event source is reserved for future use.) TRIG_OTHER: driver specific event trigger. 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 TRIG_OTHER features are done by INSN_CONFIG instructions. The argument is reserved and should be set to 0. 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 comedi_get_cmd_src_mask function is useful for determining what trigger sources a subdevice supports.
The command flags <anchor id="source.flags.anchor"/> The flags field in the command data structure is used to specify some behaviour of the acquisitions in a command. The meaning of the field is as follows: TRIG_RT: ask the driver to use a hard real-time interrupt handler. This will reduce latency in handling interrupts from your data aquisition hardware. It can be useful if you are sampling at high frequency, or if your hardware has a small onboard data buffer. You must have a real-time kernel (RTAI or RTLinux/GPL) and must compile &comedi; with real-time support, or this flag will do nothing. TRIG_WAKE_EOS: where EOS stands for End of Scan. 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. TRIG_ROUND_NEAREST: 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. TRIG_ROUND_DOWN: round period down. TRIG_ROUND_UP: round period up. TRIG_ROUND_UP_NEXT: this one doesn't do anything, and I don't know what it was intended to do…? TRIG_DITHER: enable dithering? Dithering is a software technique to smooth the influence of discretization noise. TRIG_DEGLITCH: enable deglitching? Another noise smoothing technique. TRIG_WRITE: write to bidirectional devices. Could be useful, in principle, if someone wrote a driver that supported commands for a digital I/O device that could do either input or output. TRIG_BOGUS: do the motions? TRIG_CONFIG: perform configuration, not triggering. This is a legacy of the deprecated comedi_trig_struct data structure, and has no function at present.
Anti-aliasing 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. 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. 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.
Slowly-varying inputs Note: The functions described here use an old feature that is no longer implemented by the &comedi; kernel layer. THEY WILL NOT WORK! 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 sqrtnumber_of_samples. Obviously, there are limitations to this: you are ultimately limited by Spurious Free Dynamic Range. 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 peaks in the transform: one or more of the fundamental harmonics of the measured signal, and lots of little peaks (called spurs) 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!). you need to have some noise on the input channel, otherwise you will be averaging the same number N times. (Of course, this only holds if the noise is large enough to cause at least a one-bit discretization.) the more noise you have, the greater your SFDR, but it takes many more samples to compensate for the increased noise. if you feel the need to average samples for, for example, two seconds, your signal will need to be very slowly-varying, i.e., not varying more than your target uncertainty for the entire two seconds. As you might have guessed, the &comedi; library has functions to help you in your quest to accurately measure slowly varying inputs: int comedi_sv_init comedi_sv_t *sv comedi_t *device unsigned int subdevice unsigned int channel The above function comedi_sv_init initializes the comedi_sv_t data structure, used to do the averaging acquisition: typedef struct comedi_sv_struct { comedi_t *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; The actual acquisition is done with the function comedi_sv_measure: int comedi_sv_measure comedi_sv_t *sv double *data The number of samples over which the function comedi_sv_measure averages is limited by the implementation (currently the limit is 100 samples). 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.
Experimental functionality 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.
Digital input combining machines (Status: experimental (i.e., no driver implements this yet)) 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, sensitive inputs and modifier 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. For simplification purposes, it is assumed that multiple digital inputs do not change simultaneously. 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: 00 transition is ignored. 01 accumulator is incremented, or output is set. 10 accumulator is decremented, or output is cleared. 11 reserved. 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. 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. 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.
Analog filtering configuration (Status: design (i.e., no driver implements this yet).) The insn field of the instruction data structure has not been assigned yet. The chanspec field of the instruction data structure is ignored. 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. 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. 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.
Analog Output Waveform Generation (Status: design (i.e., no driver implements this yet).) The insn field of the instruction data structure has not been assigned yet. The chanspec field of the instruction data structure is ignored. 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. This config should allow the user to configure the number of samples to loop through. It may be necessary to configure the channels used.
Extended Triggering (Status: alpha.) The insn field of the instruction data structure has not been assigned yet. The chanspec field of the instruction data structure is ignored. This section covers common information for all extended triggering configuration, and doesn't describe a particular type of extended trigger. Extended triggering is used to configure triggering engines that do not fit into commands. In a typical programming sequence, the application will use configuration instructions to configure an extended trigger, and a command, specifying TRIG_OTHER as one of the trigger sources. 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. 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. Extended triggers must use data[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. Various types of extended triggers must use data[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: COMEDI_EV_START COMEDI_EV_SCAN_BEGIN COMEDI_EV_CONVERT COMEDI_EV_SCAN_END COMEDI_EV_STOP
Analog Triggering (Status: alpha. The ni_mio_common.c driver implements this feature.) The insn field of the instruction data structure has not been assigned yet. The chanspec field of the instruction data structure is ignored. The data field of the instruction data structure is used as follows: data[1] trigger and combining machine configuration. data[2] analog triggering signal chanspec. data[3] primary analog level. data[4] secondary analog level. 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. 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 0. The interpretation of the chanspec and voltage levels is device dependent, but should correspond to similar values of the analog input subdevice, if possible. Notes: Reading range information is not addressed. This makes it difficult to convert comparator voltages to data values. 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.
Bitfield Pattern Matching Extended Trigger (Status: design. No driver implements this feature yet.) The insn field of the instruction data structure has not been assigned yet. The chanspec field of the instruction data structure is ignored. The data field of the instruction data structure is used as follows: data[1] trigger flags. data[2] mask. data[3] pattern. 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. 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. Discovery: The number of bits can be discovered by setting the mask to all 1's. The driver must modify this value and return -EAGAIN.
Counter configuration (Status: design. No driver implements this feature yet.) The insn field of the instruction data structure has not been assigned yet. The chanspec field of the instruction data structure is used to specify which counter to use. (I.e., the counter is a &comedi; channel.) The data field of the instruction data structure is used as follows: data[1] trigger configuration. data[2] primary input chanspec. data[3] primary combining machine configuration. data[4] secondary input chanspec. data[5] secondary combining machine configuration. data[6] latch configuration. Note that this configuration is only useful if the counting has to be done in software. 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. Counters can be operated either in synchronous mode (using INSN_READ) or asynchronous mode (using commands), similar to analog input subdevices. The input signal for both modes is the accumulator. Commands on counter subdevices are almost always specified using scan_begin_src = TRIG_OTHER, with the counter configuration also serving as the extended configuration for the scan begin source. 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. Note: How to access multiple pieces of data acquired at each event?
One source plus auxiliary counter configuration (Status: design. No driver implements this feature yet.) The insn field of the instruction data structure has not been assigned yet. The chanspec field of the instruction data structure is used to … The data field of the instruction data structure is used as follows: data[1] 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. data[2] 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. data[3] data[4] determine the primary source for the counter, similar to the …_src and the …_arg fields used in the command data structure. Notes: How to specify which events cause a latch and push, and what should get latched?
National Instruments General Purpose Counters/Timers (GPCT) 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: Input source the signal measured or the clock of the pulse generation. Gate controls when the counting (or sampling) occurs. Register holds the current count. Out for the output counters (pulse generators), the output signal. 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. Each counter of the board is represented in comedi as a subdevice of type COMEDI_SUBD_COUNTER. Each subdevice has a device file associated (eg, /dev/comedi0_subd11) 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. To configure the behaviour of the counter with comedi, the function comedi_set_counter_mode is used. The possible mode values are to be found in the ni_gpct_mode_bits 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 NI_GPCT_LOADING_ON_GATE_BIT to the mode. In that case, the counter will be reset to the value of the A register after each sampling. To configure the signal to be used as the "source", one uses the comedi_set_clock_source with one constant from the ni_gpct_clock_source_bits enum. When the period of the signal is fixed and known, it should be specified as the last parameter of the method, otherwise 0 should be passed. Note that in comedi this is called "clock" because in timer and pulse generator, this signal is used as the clock. To configure the signal to be used as the "gate", one uses the comedi_set_gate_source with one constant from the ni_gpct_gate_select enum. When the gate signal is not be used, NI_GPCT_DISABLED_GATE_SELECT 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. The function comedi_reset will stop and reset a counter. After being configured, to start a counter, it should be "armed", which can be done either with the comedi_arm function (for simple counting mode), or with the start_src member of the command (for buffered counting). 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 comedi_set_routing, 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 ni_pfi_routing enum. The direction of the pin must also be correctly configured (ie, whether it is used as input or output). This is done via comedi_dio_config with the same subdevice and channel, and either COMEDI_INPUT or COMEDI_OUTPUT.
National Instruments RTSI trigger bus 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 ni_pcimio, ni_atmio, and ni_mio_cs drivers expose the RTSI bus as a digital I/O subdevice (subdevice number 10). The functions comedi_dio_config and comedi_dio_get_config can be used on the RTSI subdevice to set/query the direction (input or output) of each of the RTSI lines individually. The subdevice also supports the INSN_CONFIG_SET_CLOCK_SRC and INSN_CONFIG_GET_CLOCK_SRC 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 comedi.h header file: Clock Source Description NI_MIO_INTERNAL_CLOCK Use the board's internal oscillator. NI_MIO_RTSI_CLOCK 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 NI_MIO_PLL_RTSI_CLOCK instead. NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK 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. NI_MIO_PLL_PXI10_CLOCK 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. NI_MIO_PLL_RTSI_CLOCKn 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. For all clock sources except NI_MIO_INTERNAL_CLOCK and NI_MIO_PLL_PXI10_CLOCK, you should pass the period of the clock your are feeding to the board when using INSN_CONFIG_SET_CLOCK_SRC. Finally, the configuration instructions INSN_CONFIG_SET_ROUTING and INSN_CONFIG_GET_ROUTING can be used to select/query which internal signal will appear on a given RTSI output line. The header file comedi.h defines the following signal sources which can be routed to an RTSI line: Signal Source Description NI_RTSI_OUTPUT_ADR_START1 ADR_START1, an analog input start signal. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_ADR_START2 ADR_START2, an analog input stop signal. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_SCLKG SCLKG, a sample clock signal. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_DACUPDN DACUPDN, a dac update signal. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_DA_START1 DA_START1, an analog output start signal. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_G_SRC0 G_SRC0, the source signal to general purpose counter 0. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_G_GATE0 G_GATE0, the gate signal to general purpose counter 0. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_RGOUT0 RGOUT0, the output signal of general purpose counter 0. See the NI's DAQ-STC Technical Reference Manual for more information. NI_RTSI_OUTPUT_RTSI_BRDn 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. NI_RTSI_OUTPUT_RTSI_OSC 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. 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 TRIG_EXT and the source argument using the return values from the NI_EXT_RTSIn function (or similarly the NI_EXT_PFIn function if you want to trigger from a PFI line). The CR_EDGE and CR_INVERT flags may also be set on the trigger source argument to specify edge and falling edge/low level triggering. An example to set up a device as a master is given below. An example to slave a m-series device from this master follows. A pre-m-series device would need to use NI_MIO_RTSI_CLOCK 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).