From 90ea57b2e964f10f5b2d9736ec86c37c07cf9e0f Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 2 May 2012 17:58:15 +0100 Subject: [PATCH 1/8] Created a PWM demo using the newly introduced defines to manipulate PWM frequency. --- demo/Makefile.am | 7 ++- demo/README | 5 ++ demo/pwm.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 demo/pwm.c diff --git a/demo/Makefile.am b/demo/Makefile.am index 523d3eb..8e87f2b 100644 --- a/demo/Makefile.am +++ b/demo/Makefile.am @@ -4,7 +4,7 @@ noinst_PROGRAMS = \ choose_routing cmd do_waveform dio eeprom_dump gpct_buffered_counting \ gpct_encoder gpct_pulse_generator \ gpct_simple_counting inp inpn insn ledclock \ - mmap outp poll receiver select \ + mmap outp poll receiver select pwm \ sender sigio sv tut1 tut2 tut3 noinst_HEADERS = examples.h @@ -101,6 +101,11 @@ poll_SOURCES = poll.c common.c poll_CFLAGS = $(COMEDILIB_CFLAGS) poll_LDADD = $(COMEDILIB_LIBS) +pwm_SOURCES = pwm.c common.c +pwm_CFLAGS = $(COMEDILIB_CFLAGS) +pwm_LDADD = $(COMEDILIB_LIBS) + + receiver_SOURCES = receiver.c common.c receiver_CFLAGS = $(COMEDILIB_CFLAGS) receiver_LDADD = $(COMEDILIB_LIBS) diff --git a/demo/README b/demo/README index 9238186..b870db0 100644 --- a/demo/README +++ b/demo/README @@ -136,6 +136,11 @@ outp : Write one to one channel of one subdevice. Requires a digital or analog output subdevice. +pwm: + controls PWM devices. Use the option -N 0 and -N 1 to switch + it on / off respectively. Call with no arguments to get + a help screen. + receiver: This demo is meant to be used in conjunction with the sender demo. Receiver requires a digital input subdevice, and sender diff --git a/demo/pwm.c b/demo/pwm.c new file mode 100644 index 0000000..ede2ec7 --- /dev/null +++ b/demo/pwm.c @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +/* + * A little pwm demo + * Part of Comedilib + * + * Copyright (c) 2012 Bernd Porr + * + * This file may be freely modified, distributed, and combined with + * other software, as long as proper attribution is given in the + * source code. + */ + +#include +#include +#include +#include +#include "examples.h" + +// the option -n is used to switch on/off the pwm + +int main(int argc, char *argv[]) +{ + int ret,i; + comedi_insn insn; + lsampl_t d[5]; + comedi_t *device; + + int freq; + + struct parsed_options options; + + init_parsed_options(&options); + options.freq = -1; + // we hijack this option to switch it on or off + options.n_scan = -1; + options.value = -1; + parse_options(&options, argc, argv); + + if ((options.value==-1)&&(options.n_scan==-1)&&(options.freq==-1)) { + fprintf(stderr, + "Usage: %s OPTIONS duty_cycle\n" + "options: \n" + " -N 0 switches PWM off\n" + " -N 1 switches PWM on\n" + " -N 2 enquires the max value for the duty cycle\n" + " -F FREQ sets the PWM frequency\n", + argv[0]); + } + + device = comedi_open(options.filename); + if(!device){ + comedi_perror(options.filename); + exit(-1); + } + + options.subdevice = comedi_find_subdevice_by_type(device,COMEDI_SUBD_PWM,0); + if (options.verbose) + printf("PWM subdevice autodetection gave subdevice number %d\n", + options.subdevice); + + if(options.n_scan==2) { + printf("%d\n",comedi_get_maxdata(device,options.subdevice,0)); + close(device); + exit(0); + } + + insn.insn=INSN_CONFIG; + insn.data=d; + insn.subdev=options.subdevice; + insn.chanspec=CR_PACK(0,0,0); + + if(options.n_scan==1) { + d[0] = INSN_CONFIG_ARM; + d[1] = 0; + insn.n=2; + ret=comedi_do_insn(device,&insn); + if(ret < 0){ + fprintf(stderr,"Could not switch on:%d\n",ret); + comedi_perror(options.filename); + exit(-1); + } + } + if(options.n_scan==0) { + d[0] = INSN_CONFIG_DISARM; + d[1] = 0; + insn.n=1; + ret=comedi_do_insn(device,&insn); + if(ret < 0){ + fprintf(stderr,"Could not switch off:%d\n",ret); + comedi_perror(options.filename); + exit(-1); + } + } + if(options.freq>0) { + freq = options.freq; + d[0] = INSN_CONFIG_PWM_SET_PERIOD; + d[1] = 1E9/freq; + insn.n=2; + ret=comedi_do_insn(device,&insn); + if(ret < 0){ + fprintf(stderr,"Could set frequ:%d\n",ret); + comedi_perror(options.filename); + exit(-1); + } + } + + d[0] = INSN_CONFIG_GET_PWM_STATUS; + insn.n=2; + ret=comedi_do_insn(device,&insn); + if(ret < 0){ + fprintf(stderr,"Could not get status:%d insn=%d\n", + ret, + d[0]); + comedi_perror(options.filename); + exit(-1); + } + if (options.verbose) { + if (d[1]) + fprintf(stderr, + "PWM is on.\n"); + else + fprintf(stderr, + "PWM is off.\n"); + } + d[0] = INSN_CONFIG_PWM_GET_PERIOD; + insn.n=2; + ret=comedi_do_insn(device,&insn); + if(ret < 0){ + fprintf(stderr,"Could get frequ:%d\n",ret); + comedi_perror(options.filename); + exit(-1); + } + freq = 1E9 / d[1]; + if (options.verbose) + fprintf(stderr,"PWM frequency is %d\n", freq); + + if (options.value>=0) + + if(comedi_data_write(device, + options.subdevice, + options.channel, + 0, + 0, + options.value)<0) + { + fprintf(stderr,"error setting the pwm duty cycle on "); + comedi_perror(options.filename); + exit(1); + } + + return 0; +} From 74a1207a29b59e2b0b38052b3333e556b537b3b7 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Wed, 2 May 2012 18:40:07 +0100 Subject: [PATCH 2/8] Added info that '-n' is used to select the waveform. --- demo/ao_waveform.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/demo/ao_waveform.c b/demo/ao_waveform.c index fef1d2c..02c8863 100644 --- a/demo/ao_waveform.c +++ b/demo/ao_waveform.c @@ -106,12 +106,13 @@ int main(int argc, char *argv[]) init_parsed_options(&options); options.subdevice = -1; - options.n_chan = 0; /* default waveform */ + options.n_chan = -1; /* waveform */ parse_options(&options, argc, argv); /* Use n_chan to select waveform (cheat!) */ fn = options.n_chan; if(fn < 0 || fn >= NUMFUNCS){ + fprintf(stderr,"Use the option '-n' to select another waveform.\n"); fn = 0; } @@ -158,7 +159,8 @@ int main(int argc, char *argv[]) dds_init(waveform_frequency, options.freq, fn); - dump_cmd(stdout,&cmd); + if (options.verbose) + dump_cmd(stdout,&cmd); err = comedi_command_test(dev, &cmd); if (err < 0) { @@ -189,7 +191,8 @@ int main(int argc, char *argv[]) "See the --write-buffer option of comedi_config\n", n); exit(1); } - printf("m=%d\n",m); + if (options.verbose) + printf("m=%d\n",m); ret = comedi_internal_trigger(dev, options.subdevice, 0); if(ret < 0){ @@ -206,7 +209,8 @@ int main(int argc, char *argv[]) perror("write"); exit(0); } - printf("m=%d\n",m); + if (options.verbose) + printf("m=%d\n",m); n-=m; } total+=BUF_LEN; From c22d498dc06f1f9bd3d3bb07ed98b1c92d789284 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 3 May 2012 00:39:04 +0100 Subject: [PATCH 3/8] Added comedi_board_info which has been inspired by the original info in the demo directory. I've made it a bit more verbose and also took into account that now the generic_timed command takes more than one channel so that a user can experiment which sampling rates are possible with different channel numbers. I've also added an option to set the sampling rate for the generic_timed command. That sould actually not be needed but I'm sure there are drivers out there which do not correct the sampling rate downwards automatically. --- Makefile.am | 2 +- comedi_board_info/Makefile.am | 7 + comedi_board_info/comedi_board_info.1 | 40 ++++ comedi_board_info/comedi_board_info.c | 316 ++++++++++++++++++++++++++ configure.ac | 1 + 5 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 comedi_board_info/Makefile.am create mode 100644 comedi_board_info/comedi_board_info.1 create mode 100644 comedi_board_info/comedi_board_info.c diff --git a/Makefile.am b/Makefile.am index 16f5207..f436177 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = lib comedi_config man testing demo doc swig \ +SUBDIRS = lib comedi_config man testing demo comedi_board_info doc swig \ include etc scxi c++ pkgconfigdir = $(libdir)/pkgconfig diff --git a/comedi_board_info/Makefile.am b/comedi_board_info/Makefile.am new file mode 100644 index 0000000..c0b8c24 --- /dev/null +++ b/comedi_board_info/Makefile.am @@ -0,0 +1,7 @@ +bin_PROGRAMS = comedi_board_info + +man_MANS = comedi_board_info.1 + +comedi_board_info_SOURCES = comedi_board_info.c +comedi_board_info_CFLAGS = $(COMEDILIB_CFLAGS) +comedi_board_info_LDADD = $(COMEDILIB_LIBS) diff --git a/comedi_board_info/comedi_board_info.1 b/comedi_board_info/comedi_board_info.1 new file mode 100644 index 0000000..99a64ec --- /dev/null +++ b/comedi_board_info/comedi_board_info.1 @@ -0,0 +1,40 @@ +.TH COMEDI_BOARD_INFO "1" "May 2012" "comedi_board_info" "User Commands" +.SH NAME +comedi_board_info \- reports useful information about COMEDI devices +.SH SYNOPSIS +.B comedi_board_info +[\fIOPTIONS\fR] COMEDI_DEVICE +.SH DESCRIPTION +This program reads information about a comedi device and +displays it in a human-readable form. It also +probes the asynchronous acquisition by calling the function +probe_cmd_generic_timed +which provides information about the maximum sampling rate of +the board +and how the card acquires multiple channels (e.g. at once or +one by one). +.TP +\-n NUMBER_OF_CHANNELS +Requests the number of channels for the asynchronous acquisition. +This might influence the maximum sampling rate and the mode how +the comedi device samples the channels. +If the number is higher than the available +channels this will be corrected downwards to the number of available +channels. +.TP +\-F SAMPLING_RATE +Requests the sampling rate for an asynchronous +acquisition. By default this is set to comedi's highest sampling rate +so that the driver is forced to reduce it and will in most cases +return the maximum possible sampling rate. +.TP +\-v +Verbose output. +.TP +\-h +Shows a brief help screen. +.SH "SEE ALSO" +More documentation can be found on +http://www.comedi.org/ +.SH AUTHOR +comedi_board_info was written by David Schleef and Bernd Porr . diff --git a/comedi_board_info/comedi_board_info.c b/comedi_board_info/comedi_board_info.c new file mode 100644 index 0000000..bbe38ee --- /dev/null +++ b/comedi_board_info/comedi_board_info.c @@ -0,0 +1,316 @@ +/* + This program reads information about a comedi device and + displays the information in a human-readable form. + */ + +#include +#include +#include +#include +#include +#include +#include + + +static char * const default_filename = "/dev/comedi0"; + +int verbose = 0; + +static const char * const subdevice_types[]={ + "unused", + "analog input", + "analog output", + "digital input", + "digital output", + "digital I/O", + "counter", + "timer", + "memory", + "calibration", + "processor", + "serial digital I/O", + "pwm" +}; + +struct subdev_flag { + const char *sdf_define; + unsigned int bitmask; + const char *description; +}; + +static struct subdev_flag subdev_flags[] = { + {"SDF_MAXDATA",0x0010,"maxdata depends on channel"}, + {"SDF_FLAGS",0x0020,"flags depend on channel"}, + {"SDF_RANGETYPE",0x0040,"range type depends on channel"}, + {"SDF_MODE0",0x0080,"can do mode 0"}, + {"SDF_MODE1",0x0100,"can do mode 1"}, + {"SDF_MODE2",0x0200,"can do mode 2"}, + {"SDF_MODE3",0x0400,"can do mode 3"}, + {"SDF_MODE4",0x0800,"can do mode 4"}, + {"SDF_SOFT_CALIBRATED",0x2000,"subdevice uses software calibration"}, + {"SDF_CMD_WRITE",0x4000,"can do output commands"}, + {"SDF_CMD_READ",0x8000,"can do input commands"}, + {"SDF_READABLE",0x00010000,"subdevice can be read (e.g. analog input)"}, + {"SDF_WRITABLE",0x00020000,"subdevice can be written (e.g. analog output)"}, + {"SDF_INTERNAL",0x00040000,"subdevice does not have externally visible lines"}, + {"SDF_GROUND",0x00100000,"can do aref=ground"}, + {"SDF_COMMON",0x00200000,"can do aref=common"}, + {"SDF_DIFF",0x00400000,"aref=diff"}, + {"SDF_OTHER",0x00800000,"can do aref=other"}, + {"SDF_DITHER",0x01000000,"can do dithering"}, + {"SDF_DEGLITCH",0x02000000,"can do deglitching"}, + {"SDF_MMAP",0x04000000,"can do mmap()"}, + {"SDF_RUNNING",0x08000000,"subdevice is acquiring data"}, + {"SDF_LSAMPL",0x10000000,"subdevice uses 32-bit samples"}, + {"SDF_PACKED",0x20000000,"subdevice can do packed DIO"}, + {0,0,0}}; + +void explain_subdevice_flags(char* padding,unsigned int sf) { + int i = 0; + while (subdev_flags[i].sdf_define) { + if (sf & subdev_flags[i].bitmask) + printf("%s%s:%s\n", + padding, + subdev_flags[i].sdf_define, + subdev_flags[i].description); + i++; + } +} + +void unit_to_desc(char *udesc,int unit) { + switch(unit) { + case UNIT_volt: strcpy(udesc," V"); break; + case UNIT_mA: strcpy(udesc," mA"); break; + case UNIT_none: strcpy(udesc,""); break; + default: sprintf(udesc," (unknown unit %d)", + unit); + } +} + + + +char *tobinary(char *s,int bits,int n) +{ + int bit=1<>=1) + *t++=(bits&bit)?'1':'0'; + *t=0; + + return s; +} + + +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 probe_cmd_generic_timed(comedi_t *it,int s,int n_channels,int freq_for_generic_timed) +{ + comedi_cmd cmd; + char buf[100]; + + printf(" command structure filled with probe_cmd_generic_timed for %d channels:\n", + n_channels); + if(comedi_get_cmd_generic_timed(it, s, &cmd, n_channels, 1E9/freq_for_generic_timed)<0){ + printf(" not supported\n"); + }else{ + printf(" start: %s %d\n", + cmd_src(cmd.start_src,buf),cmd.start_arg); + printf(" scan_begin: %s %d\n", + cmd_src(cmd.scan_begin_src,buf),cmd.scan_begin_arg); + if (verbose) { + if ((cmd.scan_begin_src == TRIG_TIMER)&&(cmd.scan_begin_arg)) { + printf(" scan_begin_src = TRIG_TIMER:\n" + " The sampling rate is defined per scan\n" + " meaning all channels are sampled at\n" + " the same time. The maximum sampling rate is f=%d Hz\n", + (int)(1E9/cmd.scan_begin_arg));} + } + printf(" convert: %s %d\n", + cmd_src(cmd.convert_src,buf),cmd.convert_arg); + if (verbose) { + if ((cmd.convert_src == TRIG_TIMER)&&(cmd.convert_arg)) { + printf(" convert_src = TRIG_TIMER\n" + " The sampling rate is defined per channel\n" + " meaning that a multiplexer is being switched from\n" + " channel to channel at a maximum rate of %d Hz.\n" + " The overall sampling rate needs to be divided\n" + " by the number of channels and results in f=%d Hz.\n", + (int)(1E9/cmd.convert_arg), + (int)(1E9/cmd.convert_arg/n_channels)); + } + } + printf(" scan_end: %s %d\n", + cmd_src(cmd.scan_end_src,buf),cmd.scan_end_arg); + printf(" stop: %s %d\n", + cmd_src(cmd.stop_src,buf),cmd.stop_arg); + } +} + + + +void get_command_stuff(comedi_t *it,int s,int n_chans_for_generic_timed,int freq_for_generic_timed) +{ + comedi_cmd cmd; + char buf[100]; + + if(comedi_get_cmd_src_mask(it,s,&cmd)<0){ + printf(" not supported\n"); + }else{ + printf(" start: %s\n",cmd_src(cmd.start_src,buf)); + if (cmd.start_src == TRIG_EXT) + printf(" cmd.start_src allows external trigger (TRIG_EXT)," + " for example from on input pin at the device.\n"); + printf(" scan_begin: %s\n",cmd_src(cmd.scan_begin_src,buf)); + printf(" convert: %s\n",cmd_src(cmd.convert_src,buf)); + printf(" scan_end: %s\n",cmd_src(cmd.scan_end_src,buf)); + printf(" stop: %s\n",cmd_src(cmd.stop_src,buf)); + + probe_cmd_generic_timed(it,s,n_chans_for_generic_timed,freq_for_generic_timed); + } +} + + + +int main(int argc,char *argv[]) +{ + int i,j; + int n_subdevices,type; + const char *type_str; + int chan,n_chans; + int n_ranges; + int subdev_flags; + comedi_range *rng; + comedi_t *it; + char *filename = default_filename; + char c; + char strtmp[16]; + int n_chans_for_generic_timed = 1; + int freq_for_generic_timed = 1E9; + + while (-1 != (c = getopt(argc, argv, "hvn:F:"))) { + switch (c) { + case 'n': + n_chans_for_generic_timed = strtoul(optarg, NULL, 0); + break; + case 'F': + freq_for_generic_timed = strtoul(optarg, NULL, 0); + break; + case 'v': + verbose++; + break; + case 'h': + default: + fprintf(stderr, + "usage: comedi_board_info [OPTIONS] COMEDI_DEVICE\n" + " -n number of channels for async command (default 1)\n" + " -F probing sampling rate for async command (default 1Ghz)\n" + " -v verbose output\n" + " -h this help screen\n"); + exit(1); + } + } + + if(optind < argc) { + filename = argv[optind]; + } + + it = comedi_open(filename); + if(!it){ + comedi_perror(filename); + exit(1); + } + + printf("overall info:\n"); + printf(" version code: 0x%06x\n", comedi_get_version_code(it)); + printf(" driver name: %s\n", comedi_get_driver_name(it)); + printf(" board name: %s\n", comedi_get_board_name(it)); + printf(" number of subdevices: %d\n", n_subdevices = comedi_get_n_subdevices(it)); + + for(i = 0; i < n_subdevices; i++){ + printf("subdevice %d:\n",i); + type = comedi_get_subdevice_type(it, i); + if(type < (int)(sizeof(subdevice_types) / sizeof(subdevice_types[0]))){ + type_str = subdevice_types[type]; + }else{ + type_str = "UNKNOWN"; + } + printf(" type: %d (%s)\n",type,type_str); + if(type==COMEDI_SUBD_UNUSED) + continue; + subdev_flags = comedi_get_subdevice_flags(it, i); + printf(" flags: 0x%08x\n",subdev_flags); + if (verbose) explain_subdevice_flags(" ",subdev_flags); + n_chans=comedi_get_n_channels(it,i); + printf(" number of channels: %d\n",n_chans); + if(!comedi_maxdata_is_chan_specific(it,i)){ + printf(" max data value: %lu\n", (unsigned long)comedi_get_maxdata(it,i,0)); + }else{ + printf(" max data value: (channel specific)\n"); + for(chan=0;chanunit); + printf(" [%g%s,%g%s]",rng->min,strtmp,rng->max,strtmp); + } + printf("\n"); + }else{ + for(chan=0;chanunit); + printf(" [%g%s,%g%s]",rng->min,strtmp,rng->max,strtmp); + } + printf("\n"); + } + } + printf(" command:\n"); + if (n_chans_for_generic_timed>n_chans) + n_chans_for_generic_timed = n_chans; + if (n_chans_for_generic_timed<1) + n_chans_for_generic_timed = 1; + if (freq_for_generic_timed > 1E9) + freq_for_generic_timed = 1E9; + if (freq_for_generic_timed < 1) + freq_for_generic_timed = 1; + get_command_stuff(it,i,n_chans_for_generic_timed,freq_for_generic_timed); + } + + return 0; +} + diff --git a/configure.ac b/configure.ac index 97c848e..ffb85a7 100644 --- a/configure.ac +++ b/configure.ac @@ -275,6 +275,7 @@ fi AC_CONFIG_FILES( Makefile comedi_config/Makefile +comedi_board_info/Makefile c++/Makefile c++/include/Makefile etc/Makefile From 33f3a2eada793de92aab3f133ccc1fe45ad37063 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 3 May 2012 00:52:13 +0100 Subject: [PATCH 4/8] Just what I said in the git log is now also actually in the man page namely that the frequency option is only there for debugging. --- comedi_board_info/comedi_board_info.1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/comedi_board_info/comedi_board_info.1 b/comedi_board_info/comedi_board_info.1 index 99a64ec..37d04de 100644 --- a/comedi_board_info/comedi_board_info.1 +++ b/comedi_board_info/comedi_board_info.1 @@ -23,10 +23,12 @@ channels this will be corrected downwards to the number of available channels. .TP \-F SAMPLING_RATE -Requests the sampling rate for an asynchronous -acquisition. By default this is set to comedi's highest sampling rate -so that the driver is forced to reduce it and will in most cases -return the maximum possible sampling rate. +Requests a sampling rate for the asynchronous +acquisition. By default this is set to comedi's highest sampling rate +(1GHz) so that the driver is forced to reduce it and will +return the maximum possible sampling rate. This option is only provided +for driver testing and for drivers which do not return the highest +sampling rate. .TP \-v Verbose output. From 47b3edd6e2845d92ad6ebd6be856ce570a9799f7 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 3 May 2012 01:03:16 +0100 Subject: [PATCH 5/8] Changed some of the descriptions for the SDF flags which were a bit misleading. --- comedi_board_info/comedi_board_info.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/comedi_board_info/comedi_board_info.c b/comedi_board_info/comedi_board_info.c index bbe38ee..35a66dd 100644 --- a/comedi_board_info/comedi_board_info.c +++ b/comedi_board_info/comedi_board_info.c @@ -48,10 +48,10 @@ static struct subdev_flag subdev_flags[] = { {"SDF_MODE3",0x0400,"can do mode 3"}, {"SDF_MODE4",0x0800,"can do mode 4"}, {"SDF_SOFT_CALIBRATED",0x2000,"subdevice uses software calibration"}, - {"SDF_CMD_WRITE",0x4000,"can do output commands"}, - {"SDF_CMD_READ",0x8000,"can do input commands"}, - {"SDF_READABLE",0x00010000,"subdevice can be read (e.g. analog input)"}, - {"SDF_WRITABLE",0x00020000,"subdevice can be written (e.g. analog output)"}, + {"SDF_CMD_WRITE",0x4000,"can do asynchronous output commands"}, + {"SDF_CMD_READ",0x8000,"can do asynchronous input commands"}, + {"SDF_READABLE",0x00010000,"subdevice can be read"}, + {"SDF_WRITABLE",0x00020000,"subdevice can be written"}, {"SDF_INTERNAL",0x00040000,"subdevice does not have externally visible lines"}, {"SDF_GROUND",0x00100000,"can do aref=ground"}, {"SDF_COMMON",0x00200000,"can do aref=common"}, @@ -61,7 +61,7 @@ static struct subdev_flag subdev_flags[] = { {"SDF_DEGLITCH",0x02000000,"can do deglitching"}, {"SDF_MMAP",0x04000000,"can do mmap()"}, {"SDF_RUNNING",0x08000000,"subdevice is acquiring data"}, - {"SDF_LSAMPL",0x10000000,"subdevice uses 32-bit samples"}, + {"SDF_LSAMPL",0x10000000,"subdevice uses 32-bit samples for commands"}, {"SDF_PACKED",0x20000000,"subdevice can do packed DIO"}, {0,0,0}}; From 2d0ed0442c7c668b0cf8aee084382cb916a3cd92 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 3 May 2012 01:24:22 +0100 Subject: [PATCH 6/8] Added a couple of sentences about async acquisition and the two modes cards do it and then mentioned our new board_info. --- doc/tutorial.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/tutorial.xml b/doc/tutorial.xml index 5ca284e..3344d2a 100644 --- a/doc/tutorial.xml +++ b/doc/tutorial.xml @@ -132,6 +132,26 @@ This technique is used in programs such as ktimetrace or comedirecord. + + There are two different ways how a sequence of channels is + measured during asynchronous acquisition (see also the Figure in + the introduction): + + + The channels are measured with the help + of a multiplexer which switches to the next channel after each measurement. + This means that the sampling rate is divided by the number + of channels. + + + The channels are all measured at the same time, for example + when every channel has its own converter. In this case the + sampling rate need not to be divided by the number of channels. + + + How your &comedi; device handles the asynchronous acquisition can be found out + with the command comedi_board_info -v. + The program tut3.c demonstrates the asynchronous acquisition. The general strategy is always From ee16e47509fb2dab2581e729f59ea880595e4b71 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 3 May 2012 02:07:30 +0100 Subject: [PATCH 7/8] Just spotted that the documentation also talks about board_info. I've updated it as well: explained the new command comedi_board_info. --- doc/install.xml | 191 +++++++++++++++++++++++++++++++----------------- 1 file changed, 122 insertions(+), 69 deletions(-) diff --git a/doc/install.xml b/doc/install.xml index 681a4e6..80418a7 100644 --- a/doc/install.xml +++ b/doc/install.xml @@ -164,86 +164,139 @@ comedi0: ni_atmio: 0x0260 at-mio-16e-10 ( irq = 3 ) So now that you have &comedi; talking to the hardware, try to - talk to &comedi;. Here's some information from comedi's proc - file, which indicates what drivers are loaded and which - boards are configured: + talk to &comedi;. + Call the command comedi_board_info, which provides information + about each subdevice on the board. + Here's part of the output of the USB-DUX sigma + board (which is on /dev/comedi0), as a result of + the command comedi_board_info -v. + +overall info: + version code: 0x00074c + driver name: usbduxsigma + board name: usbduxsigma + number of subdevices: 4 +subdevice 0: + type: 1 (analog input) + flags: 0x10119000 + SDF_CMD_READ:can do asynchronous input commands + SDF_READABLE:subdevice can be read + SDF_GROUND:can do aref=ground + SDF_LSAMPL:subdevice uses 32-bit samples for commands + number of channels: 16 + max data value: 16777215 + ranges: + all chans: [-1.325 V,1.325 V] + command: + start: now|int + scan_begin: timer + convert: now + scan_end: count + stop: none|count + command structure filled with probe_cmd_generic_timed for 16 channels: + start: now 0 + scan_begin: timer 1000000 + scan_begin_src = TRIG_TIMER: + The sampling rate is defined per scan + meaning all channels are sampled at + the same time. The maximum sampling rate is f=1000 Hz + convert: now 0 + scan_end: count 16 + stop: count 2 +subdevice 1: + type: 2 (analog output) + flags: 0x00125000 + SDF_CMD_WRITE:can do asynchronous output commands + SDF_WRITABLE:subdevice can be written + SDF_GROUND:can do aref=ground + number of channels: 4 + max data value: 255 + ranges: + all chans: [0 V,2.5 V] + command: + start: now|int + scan_begin: timer + convert: now + scan_end: count + stop: none|count + command structure filled with probe_cmd_generic_timed for 4 channels: + start: now 0 + scan_begin: timer 1000000 + scan_begin_src = TRIG_TIMER: + The sampling rate is defined per scan + meaning all channels are sampled at + the same time. The maximum sampling rate is f=1000 Hz + convert: now 0 + scan_end: count 4 + stop: count 2 +subdevice 2: + type: 5 (digital I/O) + flags: 0x00030000 + SDF_READABLE:subdevice can be read + SDF_WRITABLE:subdevice can be written + number of channels: 24 + max data value: 1 + ranges: + all chans: [0 V,5 V] + command: + not supported +subdevice 3: + type: 12 (pwm) + flags: 0x00020100 + SDF_MODE1:can do mode 1 + SDF_WRITABLE:subdevice can be written + number of channels: 8 + max data value: 512 + ranges: + all chans: [0,1] + command: + not supported + + + + This board has four subdevices. Devices are separated into + subdevices that each have a distinct purpose; e.g., analog + input, analog output, digital input/output. + + + + + Here's the information from comedi's proc + file, which indicates what drivers are loaded and which + boards are configured: + + cat /proc/comedi - - For example, on a computer with an NI pxi-6281 configured on - /dev/comedi0 and - a pxi-6602 configured on /dev/comedi1 you might - see something like: - + + For example, on a computer with an NI pxi-6281 configured on + /dev/comedi0 and + a pxi-6602 configured on /dev/comedi1 you might + see something like: + -comedi version 0.7.74 +comedi version 0.7.76 format string: "%2d: %-20s %-20s %4d",i,driver_name,board_name,n_subdevices -0: ni_pcimio pxi-6281 14 -1: ni_660x PXI-6602 10 -ni_pcimio: - ni_pcimio -8255: - 8255 -ni_660x: - ni_660x + 0: usbduxsigma usbduxsigma 4 +usbduxfast: + usbduxfast +usbduxsigma: + usbduxsigma - - This documentation feature is not well-developed yet. Basically, it - currently returns the driver name, the device name, and the number of - subdevices. Following those lines are a list of the comedi kernel - driver modules currently loaded, each followed by a list of the board - names it recognizes (names that can be used with comedi_config). - + + This documentation feature currently returns the driver name, the device name, and the number of + subdevices. Following those lines are a list of the comedi kernel + driver modules currently loaded, each followed by a list of the board + names it recognizes (names that can be used with comedi_config). + - - In the demo/ subdirectory of - Comedilib, there is a - command called board_info, which provides information - about each subdevice on the board. Its output can be rather long, - if the board has several subdevices. - Here's part of the output of the National Instruments - board (which is on /dev/comedi0), as a result of - the command demo/board_info /dev/comedi0 (run from the - top-level directory of comedilib): - - - -overall info: - version code: 0x00074a - driver name: ni_atmio - board name: at-mio-16e-10 - number of subdevices: 7 -subdevice 0: - type: 1 (analog input) - number of channels: 16 - max data value: 4095 -... - - - - The overall info gives information about the device; basically - the same information as /proc/comedi. - - - - This board has seven subdevices. Devices are separated into - subdevices that each have a distinct purpose; e.g., analog - input, analog output, digital input/output. This board also - has an EEPROM and calibration DACs that are also subdevices. - - - - &comedi; has more information about the device than what is displayed - above, but demo/board_info doesn't currently display - this. - - - + + From 048c280a9a035da3aa9c6d1e4dae1ea1fa662b52 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Thu, 3 May 2012 02:11:14 +0100 Subject: [PATCH 8/8] Removed a para from the section about proc which mentioned an NI card but that's now the dux board from above actually. --- doc/install.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/doc/install.xml b/doc/install.xml index 80418a7..69c6e26 100644 --- a/doc/install.xml +++ b/doc/install.xml @@ -272,13 +272,6 @@ subdevice 3: cat /proc/comedi - - For example, on a computer with an NI pxi-6281 configured on - /dev/comedi0 and - a pxi-6602 configured on /dev/comedi1 you might - see something like: - - comedi version 0.7.76 format string: "%2d: %-20s %-20s %4d",i,driver_name,board_name,n_subdevices