Added gpct_pulse_generator demo.
This commit is contained in:
parent
98b683b85d
commit
daf810a110
3 changed files with 277 additions and 5 deletions
|
@ -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)
|
||||
|
|
10
demo/README
10
demo/README
|
@ -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
258
demo/gpct_pulse_generator.c
Normal 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;
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue