DAQ calibration ...

Hi,

I've been studying the comedi code and examples and have odified the mmap
example to do approximately what I want, but I don't think I have the
calibration right.  I've run comedi_calibrate fromt he command line and
have a loop that runs comedi_apply_calibration for each configured channel
in my program, yet, there is a DC offset to my data.  I'm capturing a 200
mV peak-to-peak sine wave with an offset of zero, but am recording an
offset of about 7 or 8 mV when I run

  ./read_ai -t -f 10000 0g2

This should sample channel 0 using ground as a reference and range 2:
[-500,500] mV.

Any ideas? suggestions?

Thanks!

-B

*** The out of demo/info is ***

overall info:
  version code: 0x000743
  driver name: ni_pcimio
  board name: pci-6036e
  number of subdevices: 8
subdevice 0:
  type: 1 (analog input)
  number of channels: 16
  max data value: 65535
  ranges:
    all chans: [-10,10] [-5,5] [-0.5,0.5] [-0.05,0.05]
  command:
    start: now|ext|int
    scan_begin: timer|ext
    convert: timer|ext
    scan_end: count
    stop: none|count
  command fast 1chan:
    start: now 0
    scan_begin: timer 5000
    convert: timer 5000
    scan_end: count 1
    stop: count 2
subdevice 1:
  type: 2 (analog output)
  number of channels: 2
  max data value: 65535
  ranges:
    all chans: [-10,10]
  command:
    not supported
subdevice 2:
  type: 5 (digital I/O)
  number of channels: 8
  max data value: 1
  ranges:
    all chans: [0,5]
  command:
    not supported
subdevice 3:
  type: 0 (unused)
subdevice 4:
  type: 6 (counter)
  number of channels: 2
  max data value: 1
  ranges:
    all chans: [0,1]
  command:
    not supported
subdevice 5:
  type: 9 (calibration)
  number of channels: 16
  max data value: 255
  ranges:
    all chans: [0,1]
  command:
    not supported
subdevice 6:
  type: 8 (memory)
  number of channels: 512
  max data value: 255
  ranges:
    all chans: [0,1]
  command:
    not supported
subdevice 7:
  type: 5 (digital I/O)
  number of channels: 10
  max data value: 1
  ranges:
    all chans: [0,1]
  command:
    not supported

*** My program in listed below ***

#include <stdio.h>
#include <comedilib.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#include <getopt.h>
#include <ctype.h>
#include <malloc.h>
#include <math.h>

void parse_options(int argc, char *argv[]);
char *cmd_src(int src,char *buf);
void dump_cmd(FILE *file,comedi_cmd *cmd);
int prepare_cmd(comedi_t *dev, int subdevice, comedi_cmd *cmd);
double convert(lsampl_t x, int channel);
void calibrate_channels();

char *progName = "read_ai";
char *deviceName = "/dev/comedi0";
comedi_t *device;
int subdevice = 0;

int print_time = 0;
int verbose;
int n_chan = 0;
double freq = 1000.0;
unsigned int dt;

unsigned int chanlist[16];
double maxdatalist[16];
double range_to_maxdata[] = { 10.0, 5.0, 0.5, 0.05 };

int main(int argc, char *argv[])
	{
	void *map;
	comedi_cmd c, *cmd = &c;
	int size;
	int front, back;
	int ret;
	int i;
	unsigned int sample = 0;

	parse_options(argc, argv);

	if (!(device = comedi_open(deviceName))) { comedi_perror(deviceName); exit(1); }

	calibrate_channels();

	size = comedi_get_buffer_size(device, subdevice);
	if ((map = mmap(NULL, size, PROT_READ, MAP_SHARED, comedi_fileno(device), 0))
		== MAP_FAILED) { perror("mmap"); exit(1); }
	
	// Why run comedi_command_test twice?
	prepare_cmd(device, subdevice, cmd);
	if (verbose) dump_cmd(stderr, cmd);

	ret = comedi_command_test(device,cmd);
	if ((ret = comedi_command_test(device,cmd)) != 0)
		{ fprintf(stderr,"command_test failed\n"); exit(1); }

	if ((ret = comedi_command(device,cmd)) < 0)
		{ comedi_perror("comedi_command"); exit(1); }

	front = 0;
	back = 0;
	while (1)
		{
		front += comedi_get_buffer_contents(device, subdevice);
		if (front < back) break;
		if (front == back)
			{
			usleep(10000);
			continue;
			}

		for (i = back; i < front; i += sizeof(sampl_t))
			{
			static int channel = 0;
			if (print_time) printf("%12.7f", (double)sample * dt/1e9);
			// printf("%10d ", *(sampl_t *)(map+(i%size)));
			printf("%12.8f ", convert(*(sampl_t *)(map+(i%size)), channel));
			channel++;
			if (channel == n_chan) { printf("\n"); channel = 0; sample++; }
			}

		if ((ret = comedi_mark_buffer_read(device, subdevice, front-back)) < 0)
			{ comedi_perror("comedi_mark_buffer_read"); break; }
		back = front;
		}

	return 0;
	}

#define MAX_SAMPLE 65535

double
convert(lsampl_t data, int channel)
	{
	double max = maxdatalist[channel];
	return ((double)data * 2.0 * max/MAX_SAMPLE) - max;
	}

int 
prepare_cmd(comedi_t *device, int subdevice, comedi_cmd *cmd)
	{
	memset(cmd,0,sizeof(*cmd));

	cmd->subdev = subdevice;
	cmd->flags = 0;

	cmd->start_src = TRIG_NOW;
	cmd->start_arg = 0;
	
	cmd->scan_begin_src = TRIG_TIMER;
	cmd->scan_begin_arg = dt;
	
	cmd->convert_src = TRIG_TIMER;
	cmd->convert_arg = 1;
	
	cmd->scan_end_src = TRIG_COUNT;
	cmd->scan_end_arg = n_chan;
	
	cmd->stop_src = TRIG_NONE;
	cmd->stop_arg = 0;
	
	cmd->chanlist = chanlist;
	cmd->chanlist_len = n_chan;
	
	return 0;
	}

// This is a little helper function to parse options that are common to
// most of the examples.

int
usage()
	{
	printf("%s [options] <channel> ...\n", progName);
	printf("  -f <Hz>         frequency (Hz):%f\n", freq);
	printf("  -t              print sample time (in seconds)\n");
	printf("  -v              verbose\n");
	printf("  channel         <channel>[dgc]<range>\n");
	printf("    channel in [0,15]\n");
	printf("    reference - d:differential, g:ground, c:common\n");
	printf("    range: 0:[-10,10], 1:[-5:5], 2:[-0.5,0.5], 3:[-0.05,0.05]\n");
	exit(-1);
	}

void
calibrate_channels()
	{
	int i, channel, range, aref;
	for (i = 0; i < n_chan; i++)
		{
		channel = CR_CHAN(chanlist[i]);
		range = CR_RANGE(chanlist[i]);
		aref = CR_AREF(chanlist[i]);
		if (comedi_apply_calibration(device, subdevice, channel, range, aref, NULL) < 0)
			{ comedi_perror(deviceName); exit(0); }
		}
	}

void
parse_options(int argc, char *argv[])
	{
	char buf[256]; 
	int c, i, aref;
	int channel, range;

	argv++; argc--; // Skip program name
	while (argc > 1 && *argv[0] == '-')
		{
		switch (argv[0][1])
			{
			case 'f': freq = strtod(argv[1], NULL); argv++; argc--; break;
			case 't': print_time = 1; break;
			case 'v': verbose = 1; break;
			default: usage(); break;
			}
		argv++; argc--;
		}

	n_chan = argc;
	if (n_chan > 15 || n_chan < 1)
		{ fprintf(stderr, "Error: specify between 1 and 16 channels\n"); usage(); }

	for (i = 0; i < n_chan; i++)
		{
		if ((sscanf(argv[i], "%d%[dgc]%d", &channel, &buf, &range) != 3) ||
			(channel < 0 || channel > 15 || range < 0 || range > 3 || buf[1] != '\0'))
			{
			fprintf(stderr, "Error: can't parse channel spec '%s'\n", argv[i]);
			usage();
			}

		switch(buf[0])
			{
			case 'd': aref = AREF_DIFF; break;
			case 'g': aref = AREF_GROUND; break;
			case 'c': aref = AREF_COMMON; break;
			}

		chanlist[i] = CR_PACK(channel, range, aref);
		maxdatalist[i] = range_to_maxdata[range];
		}

	dt = (unsigned int)1e9/freq;
	}

char *
cmd_src(int src, char *buf)
	{
	buf[0] = 0;

	if (src & TRIG_NONE)   strcat(buf,"none|");
	if (src & TRIG_NOW)    strcat(buf,"now|");
	if (src & TRIG_FOLLOW) strcat(buf, "follow|");
	if (src & TRIG_TIME)   strcat(buf, "time|");
	if (src & TRIG_TIMER)  strcat(buf, "timer|");
	if (src & TRIG_COUNT)  strcat(buf, "count|");
	if (src & TRIG_EXT)    strcat(buf, "ext|");
	if (src & TRIG_INT)    strcat(buf, "int|");
#ifdef TRIG_OTHER
	if (src & TRIG_OTHER)  strcat(buf, "other|");
#endif

	if (strlen(buf) == 0) sprintf(buf,"unknown(0x%08x)", src);
	else buf[strlen(buf)-1] = 0;
	
	return buf;
	}

void 
dump_cmd(FILE *out, comedi_cmd *cmd)
	{
	char buf[100];

	fprintf(out, "start:      %-8s %d\n",
		cmd_src(cmd->start_src, buf), cmd->start_arg);
	fprintf(out, "scan_begin: %-8s %d\n",
		cmd_src(cmd->scan_begin_src, buf), cmd->scan_begin_arg);
	fprintf(out, "convert:    %-8s %d\n",
		cmd_src(cmd->convert_src, buf), cmd->convert_arg);
	fprintf(out, "scan_end:   %-8s %d\n",
		cmd_src(cmd->scan_end_src, buf), cmd->scan_end_arg);
	fprintf(out, "stop:       %-8s %d\n",
		cmd_src(cmd->stop_src, buf), cmd->stop_arg);
	}

Received on 2003-11-25Z03:00:03