- From: Bob Estes <estes_at_transmeta.com>
- Date: Mon, 24 Nov 2003 19:00:03 -0800 (PST)
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