Electronics and Software
Engineering Innovation

National Instruments PCI-6143 COMEDI Driver


Date 2006-02-07
Author Dr Terry Barnaby, BEAM Ltd

Introduction

This document lists information on the COMEDI driver for the National instruments PCI-6143 DAQ board.
The PCI-6143 is a DAQ card that contains 8 x 16bit Analogue to Digital converters that can simultaneously sample 8 differential analogue signals at up to 256K Samples per sec. It also has two counter/timer modules and 8 bits of digital I/O. No Digital to Analogue converters are provided.
This driver was developed for an internal project that required 3 of these boards synchronised to sample, simultaneously 24 channels of analogue data at 50KHz.
National Instruments support this card via the NIDAQmx-base system. Unfortunately this system is closed source and only supported in binary form on a limited number of Linux distributions. It is also a large lump of software and is not ideal for near real-time systems. National Instruments also produce a DDK kit which is a low level software interface to some of their boards. This uses a generic driver to communicate with boards. Unfortunatately the driver component and associated libraries (the VESA system) is closed source and not compatible with many Linux versions.
For our project, which is a real-time project, we wanted to use the Linux COMEDI system. This is open source and relatively simple. It is not tied to any particular vendors DAQ cards and offers a real-time kernel API. Unfortunately the NI PCI-6143 was not supported, but after some email conversaions with people at NI they agreed to produce and publish the register level documentation for the board.
Thanks are due to Malcolm Borgendale and Alan Armstead of National Instruments for producing the documentation for this board and providing assistance in getting this driver to work.

Overview

The PCI-6143 is a NI S-Series card. It is functionally similar to the NI M-Series and to previous NI cards. All of the main hardware is implemented in a FPGA on board and this emulates much of the original NI discrete chip hardware. In common with other NI boards its main functionality is provided by the STC "System Timing Controller" module. This module, implemented in the FPGA, implements the standard NI STC controller functions with a few minor changes. The PCI-6143's bus interface is provided by a "Mite" compatible interface, again implemented within the FPGA. The PCI-6143 has some additional board registers that provides control of the data FIFO and Calibration configuration.
Due to the usage of the STC and Mite API's a lot of the standard Comedi NI driver code will operate the PCI-6143 without change. The main differences are with the FIFO handling and Calibration system.
We choose to add support to the Comedi "ni_pcimio" for this card as it best matched the board. COMEDI Support for the PCI-6143 is fairly complete but some of the functionality has not been fully tested. The board works with interrupts and DMA for data transfer and has low CPU overhead for continuous data acquisitions (around 1% CPU on our system for 8 channels at 50KHz).
As we also needed to synchronise the boards using the NI RTSI bus we have added basic support for the NI RTSI bus to COMEDI for this board and probably all the other NI boards supported by the "ni_pcimio" driver.
The source code for this driver and RTSI additions should be in the COMEDI CVS tree soon.

Notes

  • The PCI-6143 has a 32bit FIFO that stores two samples per location. Trying to capture sets of data that is not a multiple of two samples may cause issues.
  • The Calibration system of the PCI-6143 is different from other cards, so the COMEDI calibration programs will probably not work.
  • The Digital I/O system has not been tested, but should work.
  • The Counter/timer system has not been tested but should work.
  • The setting of the PWM calibration source has not been tested.

SubDevices

The PCI-6143 "ni_pcimio" driver supports the following sub devices:
Number
Type
Description
0
Analogue Input
8 differential Analogue inputs with a range of +-5Volts simultaineously sampled with 16 bits at up to 250K samples per second. Uses main connector for signal lines.
2
Digital I/O
8 bits of bi-directional digital I/O on main connector. Untested
4
Counter/Timers
2 Counter timers. Untested.
5
Calibration
Calibration devices. Sets up calibration source including PWM signal. PWM signal setting is untested.
6
Memory
EEPROM containing configuration parameters. Untested.
7
Digital I/O
PFI trigger lines on main connector. These lines can be set for input or output and can be used as triggers for capture events.
9
Serial
Serial device interface. Calibration DAC's have not been tested. Untested.
10
Digital I/O
RTSI bus on secondary connector. This bus provides bi-directional digital lines for synchronsing boards together.

Source Code

Patch for comedi
comedi-beam-1.patch
comedi-beam-2.patch
Patch for comedilib
comedilib-beam-1.patch
comedilib-beam-2.patch

Development Information

The following link gives information on the PCI-6143 driver development including manuals etc.

Testing

We have only done major testing of the driver for our particular usage. We use the following setup:
3 * PCI-6143 boards set to continuously and simultaneously sample 24 channels of analogue data at 50KHz.
One of the boards is set as a master and the other two are slaved over the RTSI bus.

Example programs

There are some example programs I used for testing the driver during development.

Calibration

The PCI-6143 has a single calibration source that can be connected with relays to all of the input channels simultaneously.
The calibration source can be set to one of a number of settings. These are defined as:
Value
Definition
Usage
0
Calibration_Channel_Gnd_Gnd
Offset Calibration
2
Calibration_Channel_2v5_Gnd
 2.5V Reference
5
Calibration_Channel_Pwm_Gnd
+/- 5V Self Cal
10
Calibration_Channel_2v5_Pwm
PWM Calibration
11
Calibration_Channel_Pwm_Pwm
CMRR
14
Calibration_Channel_Gnd_Pwm
PWM Calibration
The PCI-6143 Calibration subdevice, number 5, is used to configure calibration.
The INSN_CONFIG_ALT_SOURCE sets the calibration source from one of the above settings.
The INSN_CONFIG_PWM_OUTPUT command sets up the PWM signal generator.
The first channel of the data acquisition should have the "CR_ALT_SOURCE" bit set. this enables the calibration input for all of the channels.

RTSI Bus

The RTSI Bus consists of an 48 pin IDC connector on the PCI-6143 and special bus signal lines on PXI boards.
There are 8 digital signal lines that are bi-directional.
Each of these signal lines can be configured as an input or output also the signal appearing on the output can be configured to one of many internal board timing signals.
We have added basic RSTI support to enable a board to be set as a master and other boards to be set as slaves.
To simplify the API and code we have hard-coded the actual set of internal timing signals that appear on the RTSI lines and just provide the ability to set the I/O direction of the lines. It would be good to add a new configure command to set up this routing to a different setup.
The COMEDI API is provided as a Digital I/O subdevice number 10 with an extra config command to set up the master clock mode.
This provides a number of configure commands through the COMEDI config API which can be accessed using the comedi_do_insn(), comedi_dio_config() and comedi_dio_get_config() functions.
The config API calls are:
API Command
Description
INSN_CONFIG_SET_RTSI_CLOCK_MODE
This sets the boards main clock mode. The argument defines the setting as one of:
COMEDI_RTSI_CLOCK_MODE_INTERNAL - Internal Clock
COMEDI_RTSI_CLOCK_MODE_OUTPUT - Run from internal clock and output this on the RTSI bus bit as RTSI_7
COMEDI_RTSI_CLOCK_MODE_SLAVE - Run from the clock on the RTSI bus bit RTSI_7
COMEDI_RTSI_CLOCK_MODE_MASTER - Output the clock on the RTSI bus bit as RTSI_7 and run from this external clock
INSN_CONFIG_DIO_OUTPUT
Configure the "channel" bit as an output. Channel is one of NI_RTSI_[0-6]
INSN_CONFIG_DIO_INPUT
Configure the "channel" bit as an input. Channel is one of NI_RTSI_[0-6].
INSN_CONFIG_DIO_QUERY
Find the direction of one of the RTSI "channels". Channel is one of NI_RTSI_[0-6].

The RTSI bus pins and default output routing is:
Name
Standard Routing
Pin
RTSI_0
NI_RTSI_STD_AI_START1
20
RTSI_1 NI_RTSI_STD_AI_START2
22
RTSI_2 NI_RTSI_STD_AI_CONV
24
RTSI_3 NI_RTSI_STD_CT1_SRC
26
RTSI_4 NI_RTSI_STD_CT1_GATE
28
RTSI_5 NI_RTSI_STD_AO_SAMP_CLOCK
30
RTSI_6 NI_RTSI_STD_AO_START_TRIG
32
RTSI_7 or RTSI_CLK
Master Clock
34

The RTSI bus pins are available to 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 to be a value between 10 and 16 corresponding to RTSI_0 through RTSI_6. We have provided the defines NI_EXT_PFI_[0-9] and NI_EXT_RTSI_[0-6] to define all the available external trigger sources.

A simple 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;
   
    // Configure the PFI bus device
    memset(&configCmd, 0, sizeof(configCmd));
    memset(&configData, 0, sizeof(configData));
    configCmd.insn = INSN_CONFIG;
    configCmd.subdev = 10;
    configCmd.chanspec = 0;
    configCmd.n = 2;
    configCmd.data = configData;
    configCmd.data[0] = INSN_CONFIG_SET_RTSI_CLOCK_MODE;
    configCmd.data[1] = COMEDI_RTSI_CLOCK_MODE_MASTER;

    ret = comedi_do_insn(dev, &configCmd);
    if(ret < 0){
        comedi_perror("comedi_command: INSN_CONFIG");
        exit(1);
    }

    // Set direction of the 3 main AI RTSI signals to output
    ret = comedi_dio_config(dev, 10, NI_RTSI_0, INSN_CONFIG_DIO_OUTPUT);
    ret = comedi_dio_config(dev, 10, NI_RTSI_1, INSN_CONFIG_DIO_OUTPUT);
    ret = comedi_dio_config(dev, 10, NI_RTSI_2, INSN_CONFIG_DIO_OUTPUT);
}

An example to slave a device from this master follows:
void comediEnableSlave(comedi_t* dev){
    comedi_insn   configCmd;
    lsampl_t          configData[2];
    int                   ret;
    unsigned int    d = 0;;
   
    // Configure the PFI bus device
    memset(&configCmd, 0, sizeof(configCmd));
    memset(&configData, 0, sizeof(configData));
    configCmd.insn = INSN_CONFIG;
    configCmd.subdev = 10;
    configCmd.chanspec = 0;
    configCmd.n = 2;
    configCmd.data = configData;
    configCmd.data[0] = INSN_CONFIG_SET_RTSI_CLOCK_MODE;
    configCmd.data[1] = COMEDI_RTSI_CLOCK_MODE_SLAVE;

    ret = comedi_do_insn(dev, &configCmd);
    if(ret < 0){
        comedi_perror("comedi_command: INSN_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;
}