Re: NI PCI-6221 encoder (Was: JR3 force sensor driver)

Frank Mori Hess wrote:
> I'd prefer you add a different insn_config id, since the a/b/z inputs 
> aren't really gates.  I'd go with a generic configure source, like 
> INSN_CONFIG_SET_SOURCE that is otherwise similar to 
> INSN_CONFIG_SET_GATE_SRC, that can be used as a catch-all for configuring 
> sources for things other than gates (or clocks).  
Done: INSN_CONFIG_SET_OTHER_SRC

> Also, you should define 
> a new enum + inline functions for the possible a/b/z sources, even if they 
> are mostly the same as the gate sources, especially since other than the 
> PFI pins they are unknown (right?).
Done

> Your demo should use the same command line options as the other demos, as 
> far as possible, and not conflict with them (the -a option).  
getopt(..., "f:s:A:B:Z:I:")

> Probably the 
> easiest way to handle the generic options would be to split 
> a "parse_option" function you could use out of the inside of the while 
> loop in "parse_options" in demo/common.c.  
I'll pass that to someone else :-)
> It would be nice if your demo explicitly set the index phase bits to 
> something, just so it's clear to the reader that its something they might 
> need to think about.
Done

Patches attached.

Regards

Anders Blomdell

-- 
Anders Blomdell                  Email: anders.blomdell_at_control.lth.se
Department of Automatic Control
Lund University                  Phone:    +46 46 222 4625
P.O. Box 118                     Fax:      +46 46 138118
SE-221 00 Lund, Sweden
/*
 * NI quadrature encoder example.
 * Part of Comedilib
 *
 * Copyright (c) 2007 Anders Blomdell <anders.blomdell_at_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: comedi/comedi_fops.c
===================================================================
RCS file: /cvs/comedi/comedi/comedi/comedi_fops.c,v
retrieving revision 1.186
diff -u -b -r1.186 comedi_fops.c
--- comedi/comedi_fops.c	1 May 2007 21:16:15 -0000	1.186
+++ comedi/comedi_fops.c	27 Jun 2007 10:13:37 -0000
_at__at_ -638,6 +638,7 _at__at_
 	case INSN_CONFIG_GET_GATE_SRC:
 	case INSN_CONFIG_SET_CLOCK_SRC:
 	case INSN_CONFIG_GET_CLOCK_SRC:
+	case INSN_CONFIG_SET_OTHER_SRC:
 	case INSN_CONFIG_GET_COUNTER_STATUS:
 		if(insn->n == 3) return 0;
 		break;
Index: comedi/drivers/ni_mio_common.c
===================================================================
RCS file: /cvs/comedi/comedi/comedi/drivers/ni_mio_common.c,v
retrieving revision 1.299
diff -u -b -r1.299 ni_mio_common.c
--- comedi/drivers/ni_mio_common.c	8 May 2007 14:28:21 -0000	1.299
+++ comedi/drivers/ni_mio_common.c	27 Jun 2007 10:13:38 -0000
_at__at_ -3313,6 +3313,13 _at__at_
 	case NITIO_G1_Second_Gate_Reg:
 		ni_writew(bits, M_Offset_G1_Second_Gate);
 		break;
+	case NITIO_G0_ABZ_Reg:
+		ni_writew(bits, M_Offset_G0_MSeries_ABZ);
+		break;
+	case NITIO_G1_ABZ_Reg:
+		ni_writew(bits, M_Offset_G1_MSeries_ABZ);
+		break;
+	  
 	/* 32 bit registers */
 	case NITIO_G0_LoadA_Reg:
 	case NITIO_G1_LoadA_Reg:
Index: comedi/drivers/ni_tio.c
===================================================================
RCS file: /cvs/comedi/comedi/comedi/drivers/ni_tio.c,v
retrieving revision 1.14
diff -u -b -r1.14 ni_tio.c
--- comedi/drivers/ni_tio.c	26 Apr 2007 17:43:44 -0000	1.14
+++ comedi/drivers/ni_tio.c	27 Jun 2007 10:13:39 -0000
_at__at_ -322,6 +322,23 _at__at_
 	return 0;
 }
 
+static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index)
+{
+	switch(counter_index)
+	{
+	case 0:
+		return NITIO_G0_ABZ_Reg;
+		break;
+	case 1:
+		return NITIO_G1_ABZ_Reg;
+		break;
+	default:
+		BUG();
+		break;
+	}
+	return 0;
+}
+
 enum Gi_Auto_Increment_Reg_Bits
 {
 	Gi_Auto_Increment_Mask = 0xff
_at__at_ -1607,6 +1624,41 _at__at_
 	return 0;
 }
 
+static int ni_tio_set_other_src(struct ni_gpct *counter, 
+				unsigned index, lsampl_t source)
+{
+  	if (counter->variant == ni_gpct_variant_m_series && 
+	    (index == NI_GPCT_SOURCE_ENCODER_A ||
+	     index == NI_GPCT_SOURCE_ENCODER_B ||
+	     index == NI_GPCT_SOURCE_ENCODER_Z)) {
+	      	unsigned int abz_reg, shift, mask;
+		abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index);
+
+		switch(index) {
+		case NI_GPCT_SOURCE_ENCODER_A:
+		  	shift = 10;
+			break;
+		case NI_GPCT_SOURCE_ENCODER_B:
+		  	shift = 5;
+			break;
+		case NI_GPCT_SOURCE_ENCODER_Z:
+		  	shift = 0;
+			break;
+		}
+		mask = 0x1f << shift;
+		if (source > 0x1f) {
+		  /* Disable gate */
+		  source = 0x1f;
+		}
+		counter->regs[abz_reg] &= ~mask;
+		counter->regs[abz_reg] |= source << shift;
+		counter->write_register(counter, counter->regs[abz_reg], abz_reg);
+		printk("%s %x %d %d\n", __FUNCTION__, counter->regs[abz_reg], index, source);
+		return 0;
+	}
+	return -EINVAL;
+}
+
 static unsigned ni_660x_first_gate_to_generic_gate_source(unsigned ni_660x_gate_select)
 {
 	unsigned i;
_at__at_ -1875,6 +1927,9 _at__at_
 	case INSN_CONFIG_GET_GATE_SRC:
 		return ni_tio_get_gate_src(counter, data[1], &data[2]);
 		break;
+	case INSN_CONFIG_SET_OTHER_SRC:
+		return ni_tio_set_other_src(counter, data[1], data[2]);
+		break;
 	case INSN_CONFIG_RESET:
 		ni_tio_reset_count_and_disarm(counter);
 		return 0;
Index: comedi/drivers/ni_tio.h
===================================================================
RCS file: /cvs/comedi/comedi/comedi/drivers/ni_tio.h,v
retrieving revision 1.6
diff -u -b -r1.6 ni_tio.h
--- comedi/drivers/ni_tio.h	26 Apr 2007 17:43:44 -0000	1.6
+++ comedi/drivers/ni_tio.h	27 Jun 2007 10:13:39 -0000
_at__at_ -86,6 +86,8 _at__at_
 	NITIO_G1_DMA_Status_Reg,
 	NITIO_G2_DMA_Status_Reg,
 	NITIO_G3_DMA_Status_Reg,
+	NITIO_G0_ABZ_Reg,
+	NITIO_G1_ABZ_Reg,
 	NITIO_Num_Registers,
 };
 
Index: include/linux/comedi.h
===================================================================
RCS file: /cvs/comedi/comedi/include/linux/comedi.h,v
retrieving revision 1.69
diff -u -b -r1.69 comedi.h
--- include/linux/comedi.h	26 Feb 2007 17:23:50 -0000	1.69
+++ include/linux/comedi.h	27 Jun 2007 10:13:39 -0000
_at__at_ -250,6 +250,8 _at__at_
 	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,
_at__at_ -643,6 +645,32 _at__at_
 	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
Index: demo/Makefile.am
===================================================================
RCS file: /cvs/comedi/comedilib/demo/Makefile.am,v
retrieving revision 1.7
diff -u -r1.7 Makefile.am
--- demo/Makefile.am	8 Jan 2007 21:53:59 -0000	1.7
+++ demo/Makefile.am	27 Jun 2007 10:11:55 -0000
_at__at_ -1,7 +1,7 _at__at_
 
 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
_at__at_ -48,6 +48,10 _at__at_
 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)
Index: include/comedi.h
===================================================================
RCS file: /cvs/comedi/comedilib/include/comedi.h,v
retrieving revision 1.38
diff -u -r1.38 comedi.h
--- include/comedi.h	26 Feb 2007 17:24:24 -0000	1.38
+++ include/comedi.h	27 Jun 2007 10:11:55 -0000
_at__at_ -250,6 +250,8 _at__at_
 	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,
_at__at_ -643,6 +645,32 _at__at_
 	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

Received on 2007-06-27Z09:15:52