![]() |
![]() |
Software & Electronic System Development |
|
National Instruments PCI-6143 COMEDI Driver
IntroductionThis 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. OverviewThe 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
SubDevicesThe PCI-6143 "ni_pcimio" driver supports the following sub devices:
Source Code
Development InformationThe following link gives information on the PCI-6143 driver development including manuals etc.TestingWe 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 programsThere are some example programs I used for testing the driver during development.CalibrationThe 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:
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 BusThe 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:
The RTSI bus pins and default output routing is:
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; } |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||