Demo program for quadrature encoder counting with NI GPCT, from
authorFrank Mori Hess <fmhess@speakeasy.net>
Thu, 28 Jun 2007 01:22:38 +0000 (01:22 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Thu, 28 Jun 2007 01:22:38 +0000 (01:22 +0000)
Anders Blomdell <anders.blomdell@control.lth.se>

demo/Makefile.am
demo/gpct_encoder.c [new file with mode: 0644]
include/comedi.h

index 5f7e151d5b6bc0e7f0b2c568e2af6a65c9e09b3b..9e61feebed47e18038fd941f2c3f33b1829dc470 100644 (file)
@@ -1,7 +1,7 @@
 
 noinst_PROGRAMS = \
        antialias ao_waveform ao_mmap apply_cal board_info choose_clock \
-       choose_routing cmd dio eeprom_dump gpct_pulse_generator \
+       choose_routing cmd dio eeprom_dump gpct_encoder gpct_pulse_generator \
        gpct_simple_counting inp inpn insn ledclock \
        mmap outp poll receiver select \
        sender sigio sv tut1 tut2
@@ -48,6 +48,10 @@ eeprom_dump_SOURCES = eeprom_dump.c common.c
 eeprom_dump_CFLAGS = $(COMEDILIB_CFLAGS)
 eeprom_dump_LDADD = $(COMEDILIB_LIBS)
 
+gpct_encoder_SOURCES = gpct_encoder.c common.c
+gpct_encoder_CFLAGS = $(COMEDILIB_CFLAGS)
+gpct_encoder_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)
diff --git a/demo/gpct_encoder.c b/demo/gpct_encoder.c
new file mode 100644 (file)
index 0000000..ad55784
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * NI quadrature encoder example.
+ * Part of Comedilib
+ *
+ * Copyright (c) 2007 Anders Blomdell <anders.blomdell@control.lth.se>
+ *
+ * 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"
+
+int set_source(comedi_t *device, unsigned subdevice, 
+              lsampl_t index, lsampl_t 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_OTHER_SRC;
+  data[1] = index;
+  data[2] = 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_encoder(comedi_t *device, unsigned subdevice, 
+                         unsigned int initial_value,
+                         int a, int b, int z)
+{
+       int retval;
+       lsampl_t counter_mode;
+       
+
+       retval = reset_counter(device, subdevice);
+        /* set initial counter value by writing to channel 0 */
+        retval = comedi_data_write(device, subdevice, 0, 0, 0, initial_value);
+        /* set "load a" register to initial_value by writing to channel 1 */
+        retval = comedi_data_write(device, subdevice, 1, 0, 0, initial_value);
+        /* set "load b" register to initial_value by writing to channel 2 */
+        retval = comedi_data_write(device, subdevice, 2, 0, 0, initial_value);
+
+       set_gate_source(device, subdevice, 0, NI_GPCT_DISABLED_GATE_SELECT);
+       set_gate_source(device, subdevice, 1, NI_GPCT_DISABLED_GATE_SELECT);
+       set_source(device, subdevice, NI_GPCT_SOURCE_ENCODER_A, a);
+       set_source(device, subdevice, NI_GPCT_SOURCE_ENCODER_B, b);
+       set_source(device, subdevice, NI_GPCT_SOURCE_ENCODER_Z, z);
+
+       counter_mode = (NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS |
+                       NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS);
+       if (z != NI_GPCT_DISABLED_GATE_SELECT) {
+         counter_mode |= (NI_GPCT_INDEX_ENABLE_BIT |
+                          NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS);
+       }
+       retval = set_counter_mode(device, subdevice, counter_mode);
+       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 = NULL;
+  int subdevice = -1;
+  int a = NI_GPCT_DISABLED_OTHER_SELECT;
+  int b = NI_GPCT_DISABLED_OTHER_SELECT;
+  int z = NI_GPCT_DISABLED_OTHER_SELECT;
+  unsigned int initial_value = 0;
+  int retval;
+
+  struct parsed_options options;
+  {
+    int c;
+    while (-1 != (c = getopt(argc, argv, "f:s:A:B:Z:I:"))) {
+      switch (c) {
+       case 'f':
+         device = comedi_open(optarg);
+         if(!device) {
+           comedi_perror(optarg);
+           exit(-1);
+         }
+         break;
+       case 's':
+         subdevice = strtoul(optarg, NULL, 0);
+         break;
+       case 'A':
+         /* TODO: Should we pass the value directly, i.e. could anybody
+          *       be interested in values besides PFIx/DISABLED */
+         a = NI_GPCT_PFI_OTHER_SELECT(strtoul(optarg, NULL, 0));
+         break;
+       case 'B':
+         /* TODO: Should we pass the value directly, i.e. could anybody
+          *       be interested in values besides PFIx/DISABLED */
+         b = NI_GPCT_PFI_OTHER_SELECT(strtoul(optarg, NULL, 0));
+         break;
+       case 'Z':
+         /* TODO: Should we pass the value directly, i.e. could anybody
+          *       be interested in values besides PFIx/DISABLED */
+         z = NI_GPCT_PFI_OTHER_SELECT(strtoul(optarg, NULL, 0));
+         break;
+       case 'I':
+         initial_value = strtoul(optarg, NULL, 0);
+      break;
+      }
+    }
+  }
+
+  /*FIXME: check that device is counter */
+  printf("Initiating encoder on subdevice %d.\n", subdevice);
+  
+  retval = ni_gpct_start_encoder(device, subdevice, initial_value, a, b, z);
+  
+  if(retval < 0) return retval;
+  
+  return 0;
+}
index c4b31c18370c643edbd61b7ac061a0050c0a4293..7014fc46401207e0a9c7ef2678a341035dec4a21 100644 (file)
@@ -250,6 +250,8 @@ enum configuration_ids
        INSN_CONFIG_GET_GATE_SRC = 2002,        // Get gate source
        INSN_CONFIG_SET_CLOCK_SRC = 2003,       // Set master clock source
        INSN_CONFIG_GET_CLOCK_SRC = 2004,       // Get master clock source
+       INSN_CONFIG_SET_OTHER_SRC = 2005,       // Set other source
+//     INSN_CONFIG_GET_OTHER_SRC = 2006,       // Get other source
        INSN_CONFIG_SET_COUNTER_MODE = 4097,
        INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE,       /* deprecated */
        INSN_CONFIG_8254_READ_STATUS = 4098,
@@ -643,6 +645,32 @@ static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n)
        return 0x202 + n;
 }
 
+/* Possibilities for setting a source with
+INSN_CONFIG_SET_OTHER_SRC when using NI general-purpose counters. */
+enum ni_gpct_other_index {
+  NI_GPCT_SOURCE_ENCODER_A,
+  NI_GPCT_SOURCE_ENCODER_B,
+  NI_GPCT_SOURCE_ENCODER_Z
+};
+enum ni_gpct_other_select
+{
+       /* m-series gates */
+        // Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT 
+       NI_GPCT_DISABLED_OTHER_SELECT = 0x8000,
+};
+static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n)
+{
+       if (n < 10) {
+               return 0x1 + n;
+       } else if (n < 16) {
+               return 0xb + n;
+       } else {
+               // Really should report this error somehow
+               return NI_GPCT_DISABLED_OTHER_SELECT;
+       }
+}
+
+
 /* start sources for ni general-purpose counters for use with
 INSN_CONFIG_ARM */
 enum ni_gpct_arm_source