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

Anders Blomdell wrote:
> Anders Blomdell wrote:
>> Anders Blomdell wrote:
>>> Frank Mori Hess wrote:
>>>> On Thursday 21 June 2007 13:36, you wrote:
>>>>> I know (I'll get to it as soon as I have figured out how to use the NI
>>>>> pci-6221 with quadrature encoders).
>>>> See the enums in comedi.h, in particular enum ni_gpct_mode_bits.  You'll 
>>>> need to use one of the NI_GPCT_COUNTING_MODE_QUADRATURE_XN_BITS bitfields, 
>>>> instead of the NI_GPCT_COUNTING_MODE_NORMAL_BITS that the simple counting 
>>>> demo uses.  And maybe some of the NI_GPCT_INDEX_* bits.  It might actually 
>>>> be useful to look at the ni 6601/6602 register level programming manual.
>>> That only partially works, what happens is that whatever
>>> NI_GPCT_COUNTING_MODE_QUADRATURE_XN_BITS is selected, the counter starts to
>>> count down on each edge on CTR{0/1}A (PFI 8/PFI 3) but remains stationary
>>> regardless of activity on CTR{0/1}B (PFI 10/PFI 11). To me this indicates that
>>> the counter is not in encoder mode, because a failure in the routing of the B
>>> signal should result in the counter changing one value only (X0 -> X1 -> X0
>>> transitions should gige one up and one down event). Direction is changed if
>>> NI_GPCT_COUNTING_DIRECTION_UP_BITS is set.
>>>
>>> Where can I find the documentation where M_Offset_G0_Counting_Mode, etc are
>>> found (the only document I have found on NI's site is "NI M Series Register Map
>>> (Preliminay)"
>> The following hack (gleaned after getting a working example in the NI
>> nimhddk_linux26/nimseries register level programming), makes it work:
>>
>>   case NITIO_G0_Counting_Mode_Reg:
>>     ni_writew(bits, M_Offset_G0_Counting_Mode);
>>     bits = 0x26a0;
>>     ni_writew(bits, M_Offset_G0_MSeries_ABZ);
>>     break;
>>
>> Seems like we (I?) need to add functionality to do the equivalent of (see
>> attached NI/RLP example for context):
>>
>>   board->G0_MSeries_ABZ.setG0_A_Select(9);
>>   board->G0_MSeries_ABZ.setG0_B_Select(21);
>>   board->G0_MSeries_ABZ.flush();
>>
>> any comments on what it should look like (or is it already there, but hidden by
>> my ignorance)?
> I have looked a little more on the comedi code. The functionality seems to be
> lacking (or I'm totally blind). Which of the following implementations is preferred:
> 
> 1. Adding INSN_CONFIG_SET_ABZ_SRC, which accepts two arguments:
>      index [0=A, 1=B, 2=Z]
>      source [1-10=PFI0-PFI9, 21-26=PFI10-PFI15, 31=DISABLED, ...]
> 
> 2. Adding INSN_CONFIG_SET_A_SRC, INSN_CONFIG_SET_B_SRC, INSN_CONFIG_SET_Z_SRC,
> which accepts 1 argument:
>     source [1-10=PFI0-PFI9, 21-26=PFI10-PFI15, 31=DISABLED, ...]
> 
> 3. Modify INSN_CONFIG_SET_GATE_SRC to accept
>      index [2=A, 3=B, 4=Z]
>      source [1-10=PFI0-PFI9, 21-26=PFI10-PFI15, 31=DISABLED, ...]
> 
> 4. None of the above, please fill in a rough sketch on dotted line below:
> 
>       ...........................................
Selected #3 above, patches to comedi & comedilib are included. Have not got Z
signal to work, but at least A/B works (will get back if I find what is missing)...


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
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	26 Jun 2007 10:43:57 -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	26 Jun 2007 10:43:57 -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_ -1600,6 +1617,25 _at__at_
 			break;
 		}
 		break;
+	case 2:
+	case 3:
+	case 4:
+	  	if (counter->variant != ni_gpct_variant_m_series) {
+		  	return -EINVAL;
+		}
+		{	
+		  	const unsigned abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index);
+		  	int shift = (4 - gate_index) * 5;
+			int mask = 0x1f << shift;
+			if (gate_source > 0x1f) {
+			  /* Disable gate */
+			  gate_source = 0x1f;
+			}
+			counter->regs[abz_reg] &= ~mask;
+			counter->regs[abz_reg] |= gate_source << shift;
+			counter->write_register(counter, counter->regs[abz_reg], abz_reg);
+		}
+		break;
 	default:
 		return -EINVAL;
 		break;
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	26 Jun 2007 10:43:57 -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,
 };
 
diff -urbN comedilib.save/demo/gpct_encoder.c comedilib/demo/gpct_encoder.c
--- comedilib.save/demo/gpct_encoder.c	1970-01-01 01:00:00.000000000 +0100
+++ comedilib/demo/gpct_encoder.c	2007-06-26 12:04:32.000000000 +0200
_at__at_ -0,0 +1,110 _at__at_
+/*
+ * 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 ni_gpct_start_encoder(comedi_t *device, unsigned subdevice, 
+			  int a, int b, int z)
+{
+	int retval;
+	lsampl_t counter_mode;
+
+	retval = reset_counter(device, subdevice);
+
+	set_gate_source(device, subdevice, 0, NI_GPCT_DISABLED_GATE_SELECT);
+	set_gate_source(device, subdevice, 1, NI_GPCT_DISABLED_GATE_SELECT);
+	set_gate_source(device, subdevice, 2, a);
+	set_gate_source(device, subdevice, 3, b);
+	set_gate_source(device, subdevice, 4, 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;
+	}
+	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_GATE_SELECT;
+  int b = NI_GPCT_DISABLED_GATE_SELECT;
+  int z = NI_GPCT_DISABLED_GATE_SELECT;
+  int retval;
+
+  struct parsed_options options;
+  {
+    int c;
+    while (-1 != (c = getopt(argc, argv, "f:s:a:b:z:"))) {
+      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_GATE_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_GATE_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_GATE_SELECT(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, a, b, z);
+  
+  if(retval < 0) return retval;
+  
+  return 0;
+}

diff -urbN comedilib.save/demo/Makefile.am comedilib/demo/Makefile.am
--- comedilib.save/demo/Makefile.am	2007-01-08 22:53:59.000000000 +0100
+++ comedilib/demo/Makefile.am	2007-06-21 17:14:32.000000000 +0200
_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)

Received on 2007-06-26Z10:00:57