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.
(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:
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.
(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.
(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.
(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
(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:
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.
(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:
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
.
(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:
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?
(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:
…_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?
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_CLOCK (n )
| 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_BRD (n )
| 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_RTSI
(n
) function (or similarly the
NI_EXT_PFI
(n
) 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.
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); } }
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).
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; }