Added gpct_pulse_generator demo.

This commit is contained in:
Frank Mori Hess 2007-01-05 21:09:28 +00:00
parent 98b683b85d
commit daf810a110
3 changed files with 277 additions and 5 deletions

View file

@ -1,7 +1,7 @@
noinst_PROGRAMS = \
antialias ao_waveform ao_mmap apply_cal choose_clock \
choose_routing cmd dio eeprom_dump board_info \
antialias ao_waveform ao_mmap apply_cal board_info choose_clock \
choose_routing cmd dio eeprom_dump gpct_pulse_generator \
inp inpn insn ledclock mmap outp poll receiver select \
sender sigio sv tut1 tut2
@ -23,6 +23,10 @@ apply_cal_SOURCES = apply_cal.c common.c
apply_cal_CFLAGS = $(COMEDILIB_CFLAGS)
apply_cal_LDADD = $(COMEDILIB_LIBS)
board_info_SOURCES = info.c common.c
board_info_CFLAGS = $(COMEDILIB_CFLAGS)
board_info_LDADD = $(COMEDILIB_LIBS)
choose_clock_SOURCES = choose_clock.c common.c
choose_clock_CFLAGS = $(COMEDILIB_CFLAGS)
choose_clock_LDADD = $(COMEDILIB_LIBS)
@ -43,9 +47,9 @@ eeprom_dump_SOURCES = eeprom_dump.c common.c
eeprom_dump_CFLAGS = $(COMEDILIB_CFLAGS)
eeprom_dump_LDADD = $(COMEDILIB_LIBS)
board_info_SOURCES = info.c common.c
board_info_CFLAGS = $(COMEDILIB_CFLAGS)
board_info_LDADD = $(COMEDILIB_LIBS)
gpct_pulse_generator_SOURCES = gpct_pulse_generator.c common.c
gpct_pulse_generator_CFLAGS = $(COMEDILIB_CFLAGS)
gpct_pulse_generator_LDADD = $(COMEDILIB_LIBS)
inp_SOURCES = inp.c common.c
inp_CFLAGS = $(COMEDILIB_CFLAGS)

View file

@ -60,6 +60,16 @@ eeprom_dump:
Dumps the EEPROM of a card, if it has one. Useful for debugging
devices/drivers.
gpct_pulse_generator:
Causes an NI general-purpose counter subdevice to produce a
continuous train of pulses on its output. The -F option specifies
the pulse period (as a frequency in Hertz), and the argument specifies
the pulse width (in nanoseconds). By default, the pulse width will
be set to half the pulse period. You may need to use the "dio"
and "choose_routing" demos to route the counter's output to
an output line that you can observe (for instance one of the PFI
lines).
inp:
Simple input: Reads one sample from one channel on one subdevice.

258
demo/gpct_pulse_generator.c Normal file
View file

@ -0,0 +1,258 @@
/*
* NI general-purpose counter example. Configures the counter to
* produce a continuous pulse train. The argument specifies the
* number of nanoseconds the output pulse should remain high.
* The example assumes the board has already been configured to
* route the output signal of the counter to an appropriate
* location (you may need to route it to a PFI output line
* for example).
* Part of Comedilib
*
* Copyright (c) 2007 Frank Mori Hess <fmhess@users.sourceforge.net>
*
* This file may be freely modified, distributed, and combined with
* other software, as long as proper attribution is given in the
* source code.
*/
/*
* Requirements: A board with a National Instruments general-purpose
* counter, and comedi driver version 0.7.74 or newer.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <comedilib.h>
#include <math.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <getopt.h>
#include <ctype.h>
#include "examples.h"
/*FIXME: move helper functions to common.c so they can be used on other (mostly counter) examples*/
int arm(comedi_t *device, unsigned subdevice, lsampl_t source)
{
comedi_insn insn;
lsampl_t data[2];
int retval;
memset(&insn, 0, sizeof(comedi_insn));
insn.insn = INSN_CONFIG;
insn.subdev = subdevice;
insn.chanspec = 0;
insn.data = data;
insn.n = sizeof(data) / sizeof(data[0]);
data[0] = INSN_CONFIG_ARM;
data[1] = source;
retval = comedi_do_insn(device, &insn);
if(retval < 0)
{
fprintf(stderr, "%s: error:\n", __FUNCTION__);
comedi_perror("comedi_do_insn");
return retval;
}
return 0;
}
/* This resets the count to zero and disarms the counter. The counter output
is set low. */
int reset_counter(comedi_t *device, unsigned subdevice)
{
comedi_insn insn;
lsampl_t data[1];
int retval;
memset(&insn, 0, sizeof(comedi_insn));
insn.insn = INSN_CONFIG;
insn.subdev = subdevice;
insn.chanspec = 0;
insn.data = data;
insn.n = sizeof(data) / sizeof(data[0]);
data[0] = INSN_CONFIG_RESET;
retval = comedi_do_insn(device, &insn);
if(retval < 0)
{
fprintf(stderr, "%s: error:\n", __FUNCTION__);
comedi_perror("comedi_do_insn");
return retval;
}
return 0;
}
int set_counter_mode(comedi_t *device, unsigned subdevice, lsampl_t mode_bits)
{
comedi_insn insn;
lsampl_t data[2];
int retval;
memset(&insn, 0, sizeof(comedi_insn));
insn.insn = INSN_CONFIG;
insn.subdev = subdevice;
insn.chanspec = 0;
insn.data = data;
insn.n = sizeof(data) / sizeof(data[0]);
data[0] = INSN_CONFIG_SET_COUNTER_MODE;
data[1] = mode_bits;
retval = comedi_do_insn(device, &insn);
if(retval < 0)
{
fprintf(stderr, "%s: error:\n", __FUNCTION__);
comedi_perror("comedi_do_insn");
return retval;
}
return 0;
}
int set_clock_source(comedi_t *device, unsigned subdevice, lsampl_t clock, lsampl_t period_ns)
{
comedi_insn insn;
lsampl_t data[3];
int retval;
memset(&insn, 0, sizeof(comedi_insn));
insn.insn = INSN_CONFIG;
insn.subdev = subdevice;
insn.chanspec = 0;
insn.data = data;
insn.n = sizeof(data) / sizeof(data[0]);
data[0] = INSN_CONFIG_SET_CLOCK_SRC;
data[1] = clock;
data[2] = period_ns;
retval = comedi_do_insn(device, &insn);
if(retval < 0)
{
fprintf(stderr, "%s: error:\n", __FUNCTION__);
comedi_perror("comedi_do_insn");
return retval;
}
return 0;
}
int set_gate_source(comedi_t *device, unsigned subdevice, lsampl_t gate_index, lsampl_t gate_source)
{
comedi_insn insn;
lsampl_t data[3];
int retval;
memset(&insn, 0, sizeof(comedi_insn));
insn.insn = INSN_CONFIG;
insn.subdev = subdevice;
insn.chanspec = 0;
insn.data = data;
insn.n = sizeof(data) / sizeof(data[0]);
data[0] = INSN_CONFIG_SET_GATE_SRC;
data[1] = gate_index;
data[2] = gate_source;
retval = comedi_do_insn(device, &insn);
if(retval < 0)
{
fprintf(stderr, "%s: error:\n", __FUNCTION__);
comedi_perror("comedi_do_insn");
return retval;
}
return 0;
}
int ni_gpct_start_pulse_generator(comedi_t *device, unsigned subdevice, unsigned period_ns, unsigned up_time_ns)
{
int retval;
lsampl_t counter_mode;
const unsigned clock_period_ns = 50; /* 20MHz clock */
unsigned up_ticks, down_ticks;
/*
FIXME:
How is output initialized to known state for toggling (reset?)
*/
retval = reset_counter(device, subdevice);
if(retval < 0) return retval;
retval = set_gate_source(device, subdevice, 0, NI_GPCT_DISABLED_GATE_SELECT | CR_EDGE);
if(retval < 0) return retval;
retval = set_gate_source(device, subdevice, 1, NI_GPCT_DISABLED_GATE_SELECT | CR_EDGE);
if(retval < 0)
{
fprintf(stderr, "Failed to set second gate source. This is expected for older boards (e-series, etc.)\n"
"that don't have a second gate.\n");
}
counter_mode = NI_GPCT_COUNTING_MODE_NORMAL_BITS;
// toggle output on terminal count
counter_mode |= NI_GPCT_OUTPUT_TC_TOGGLE_BITS;
// load on terminal count
counter_mode |= NI_GPCT_LOADING_ON_TC_BIT;
// alternate the reload source between the load a and load b registers
counter_mode |= NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS;
// count down
counter_mode |= NI_GPCT_COUNTING_DIRECTION_DOWN_BITS;
// initialize load source as load b register
counter_mode |= NI_GPCT_LOAD_B_SELECT_BIT;
retval = set_counter_mode(device, subdevice, counter_mode);
if(retval < 0) return retval;
/* 20MHz clock */
retval = set_clock_source(device, subdevice, NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS, clock_period_ns);
if(retval < 0) return retval;
up_ticks = (up_time_ns + clock_period_ns / 2) / clock_period_ns;
down_ticks = (period_ns + clock_period_ns / 2) / clock_period_ns - up_ticks;
/* set initial counter value by writing to channel 0 */
retval = comedi_data_write(device, subdevice, 0, 0, 0, down_ticks);
if(retval < 0) return retval;
/* set "load a" register to the number of clock ticks the counter output should remain low
by writing to channel 1. */
comedi_data_write(device, subdevice, 1, 0, 0, down_ticks);
if(retval < 0) return retval;
/* set "load b" register to the number of clock ticks the counter output should remain high
by writing to channel 2 */
comedi_data_write(device, subdevice, 2, 0, 0, up_ticks);
if(retval < 0) return retval;
retval = arm(device, subdevice, NI_GPCT_ARM_IMMEDIATE);
if(retval < 0) return retval;
return 0;
}
int main(int argc, char *argv[])
{
comedi_t *device;
unsigned up_time;
unsigned period_ns;
int retval;
struct parsed_options options;
init_parsed_options(&options);
options.value = -1.;
parse_options(&options, argc, argv);
period_ns = lrint(1e9 / options.freq);
if(options.value < 0.)
up_time = period_ns / 2;
else
up_time = lrint(options.value);
device = comedi_open(options.filename);
if(!device)
{
comedi_perror(options.filename);
exit(-1);
}
/*FIXME: check that device is counter */
printf("Generating pulse train on subdevice %d.\n", options.subdevice);
printf("Period = %d ns.\n", period_ns);
printf("Up Time = %d ns.\n", up_time);
printf("Down Time = %d ns.\n", period_ns - up_time);
retval = ni_gpct_start_pulse_generator(device, options.subdevice, period_ns, up_time);
if(retval < 0) return retval;
return 0;
}