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

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)?


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
//
//  gpctex2.cpp --
//
//      Simple Event Counting --  hardware controlled up/down
//
//  $DateTime: 2006/07/27 23:51:45 $
//
//  Count pulses from an external source using an external signal to control
//  the count direction.
//
//  Connect an external source to pin 37 (PFI 8), and connect an external up/down
//  signal to pin 38 (PFI 9)
//

////////////////////////////////////////////////////////////////////////////////
//  Possible Gi_Source_Select values:
//  0: TB1(20 MHz)
//  1-10: PFI<0..9>
//  11-17: RTSI<0..6>
//  18: TB2(100 kHz)
//  19: The G_TC signal from the other general-purpose counter
//  20: The G_GATE signal from the other counter, when G0_Src_SubSelect = 0;
//      Star_Trig when G0_Src_SubSelect = 1
//  21-26: PFI<10..15>
//  27: RTSI7
//  28: TB1(20 MHz)
//  29: PXIClk10
//  30: The internal signal TB3(80 MHz), when G0_Src_SubSelect = 0;
//      The output of the Analog Trigger module when G0_Src_SubSelect = 1
//  31: Logic low
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//  Possible Gi_Gate_Select values
//  0: The output of the TimeStamping Mux.
//     This signal is selected with the G0_TimeStamp_Select bitfield
//  1-10: PFI<0..9>
//  11-17: RTSI<0..6>
//  18: The internal analog input signal AI_START2
//  19: Star_Trig
//  20: The G_OUT signal from the other general-purpose counter
//  21-26: PFI<10..15>
//  27: RTSI7
//  28: The internal analog input signal AI_START1
//  29: The G_SOURCE signal from the other general-purpose counter
//  30: The output of the Analog Trigger Module
//  31: Logic low
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
//
//  Possible up/down signal values (Gi_B_Select)
//  
//  0: P0(6) (DIO line on port 0 line 6)
//  1-10: PFI<0..9>
//  11-17: RTSI<0..6>
//  18: Reserved
//  19: Reserved
//  20: Star_Trig
//  21-26: PFI<10..15>
//  27: RTSI7
//  28: Reserved
//  29: Reserved
//  30: ANALOG_TRIGGER_OUT, the analog trigger circuitry output signal
//  31: Logic low
////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <unistd.h>

#ifndef ___tMSeries_h___
    #include "tMSeries.h"
#endif

#ifndef ___tTIO_h___
    #include "tTIO.h"
#endif

#ifndef ___common_h___
    #include "common.h"
#endif

#define GPCT0_INITIAL_COUNT 0x0100

void resetGPCT0(tTIO *board);
void armGPCT0(tTIO *board);
void disarmGPCT0(tTIO *board);
void simpleEventCountConfigGPCT0(tTIO *board, tMSeries *boardM);
u32 readSaveRegGPCT0(tTIO *board);

void test(iBus *bus)
{

    // create register map

    tAddressSpace  bar1;
    tMSeries *boardM;
    tTIO *board;

    bar1 = bus->createAddressSpace(kPCI_BAR1);
    boardM = new tMSeries(bar1);
    board = new tTIO(bar1);
    //TIO chip on MSeries boards is at offset 0x100
    board->setAddressOffset(0x100);

    configureTimebase(boardM);

    resetGPCT0(board);

    simpleEventCountConfigGPCT0(board, boardM);

    //Set PFI pins to be input
    boardM->IO_Bidirection_Pin.writeRegister (0x00);

    armGPCT0(board);

    {
      int i;
      for (i = 0 ; i < 10 ; i++) {
	sleep(1);
	printf("GPCT0 value is now 0x%08lx\n",readSaveRegGPCT0(board));

	
      }
    }
    disarmGPCT0(board);

    printf("GPCT0 value is now 0x%08lx\n",readSaveRegGPCT0(board));

    //cleanup
    delete boardM;
    delete board;
    bus->destroyAddressSpace(bar1);
}

void resetGPCT0(tTIO *board)
{
    // Reset GPCT0

    board->G01_Joint_Reset.writeG0_Reset(1);
    board->G0_Mode.writeRegister(0);
    board->G0_Command.writeRegister(0);
    board->G0_Input_Select.writeRegister(0);
    board->G0_AutoIncrement.writeRegister(0);
    board->Interrupt_G0_Enable.setG0_TC_Interrupt_Enable(0);
    board->Interrupt_G0_Enable.setG0_Gate_Interrupt_Enable(0);
    board->Interrupt_G0_Enable.flush();
    board->G0_Command.writeG0_Synchronized_Gate(tTIO::tG0_Command::kG0_Synchronized_GateEnabled);
    board->Interrupt_G0_Ack.setG0_Gate_Error_Confirm(1);
    board->Interrupt_G0_Ack.setG0_TC_Error_Confirm(1);
    board->Interrupt_G0_Ack.setG0_TC_Interrupt_Ack(1);
    board->Interrupt_G0_Ack.setG0_Gate_Interrupt_Ack(1);
    board->Interrupt_G0_Ack.flush();
    board->G0_AutoIncrement.write(0);
    board->G0_MSeries_Counting_Mode.setG0_MSeries_Alternate_Synchronization(0);
    board->G0_MSeries_Counting_Mode.setG0_MSeries_Index_Enable(0);
    board->G0_MSeries_Counting_Mode.flush();
    board->G0_Second_Gate.setG0_Second_Gate_Select(0);
    board->G0_Second_Gate.setG0_Second_Gate_Polarity(0);
    board->G0_Second_Gate.flush();
}

void armGPCT0(tTIO *board)
{
    //Arm CPCT0

    board->G0_Command.writeG0_Arm(1);
}

void disarmGPCT0(tTIO *board)
{
    //Disarm CPCT0

    board->G0_Command.writeG0_Disarm(1);
}

#define DD(x) printf("# %s\n", #x); x

void simpleEventCountConfigGPCT0(tTIO *board, tMSeries *boardM)
{
    //Set up GPCT0 for Simple Event Counting

  DD(board->G0_Mode.writeG0_Load_Source_Select(tTIO::tG0_Mode::kG0_Load_Source_SelectLoad_A););
  DD(board->G0_Load_A.writeRegister(GPCT0_INITIAL_COUNT););
  DD(board->G0_Command.writeG0_Load(1););
  DD(board->G0_Load_B.writeRegister(0););
  DD(board->G0_Load_A.writeRegister(0););
  DD(board->G0_Input_Select.setG0_Source_Select(9);); //see above for choices, PFI8=9, 100 kHZ=18
  DD(board->G0_Input_Select.setG0_Source_Polarity(0);); //rising=0  
  DD(board->G0_MSeries_Counting_Mode.setG0_MSeries_Alternate_Synchronization(1););
  DD(board->G0_MSeries_Counting_Mode.setG0_MSeries_Encoder_Counting_Mode(3););
  DD(board->G0_MSeries_Counting_Mode.flush(););

  //Enable Input Pins
  DD(board->G0_MSeries_ABZ.setG0_A_Select(9);); //PFI8=9,
  DD(board->G0_MSeries_ABZ.setG0_B_Select(21);); //PFI10=21
  DD(board->G0_MSeries_ABZ.flush(););

  // Set counter to use HW signal for up/down selection
  DD(board->G0_Command.writeG0_Up_Down(tTIO::tG0_Command::kG0_Up_DownHardware);); // Software_Down=0, Software_Up=1, Hardware=2, Hardware_Gate= 3
  DD(board->G0_Input_Select.setG0_Source_Select(20);); //PFI8=9, 0=20 MHz
  DD(return;);
}

u32 readSaveRegGPCT0(tTIO *board)
{
    //Read save register twice and compare.
    //If not equal, then read third time and return.

    u32 value1, value2;

    board->G0_Command.writeG0_Save_Trace(0);
    board->G0_Command.writeG0_Save_Trace(1);

    value1 = board->G0_Save.readG0_Save_Value();
    value2 = board->G0_Save.readG0_Save_Value();

    if(value1 != value2)
    {
        value1 = board->G0_Save.readG0_Save_Value();
    }

    return value1;
}

Received on 2007-06-25Z15:15:41