Jump to content
  • 0

PCI-QUAD04


Nathan Kumar

Question

Hi,

I am using PCI-QUAD04 encoder board and I am able to read the value of the encoder using the windows library provided with the board.

But when I try to read the encoder data using a real time OS called INtime, I running into problems. Under INtime when I try to get the base address of this PCI-QUAD04 board, I get 2 different base addresses:

1) When windows driver is installed and running, I get one set of address( Mcc Quad04 base1 = 56961, base2 = 57137 with Mcc driver active)

2) When windows driver is completely uninstalled, I get these address: base1 = = 53249, base2 = 53569

 

I am not able read the encoder data under INtime. 

 

Can you please help? I have attached both Windows side code and INtime side code for your perusal.

 

Nathan

The is the code on Windows side:

////////Windows example code that works correctly/////////////////////////////////

/* Include files */
#include "..\cbw.h"
#include "Utilities.h"
#include <time.h>

int Delta( const SYSTEMTIME st1, const SYSTEMTIME st2 ) {
    union timeunion {
        FILETIME fileTime;
        ULARGE_INTEGER ul;
    };

    timeunion ft1;
    timeunion ft2;

    SystemTimeToFileTime( &st1, &ft1.fileTime );
    SystemTimeToFileTime( &st2, &ft2.fileTime );

    return max(1, (ft2.ul.QuadPart - ft1.ul.QuadPart) );
}
DWORD GetTimeDifference( SYSTEMTIME &st1, SYSTEMTIME &st2 )
{
    FILETIME        ft1, ft2;
    LARGE_INTEGER   li1, li2, liDiff;
    DWORD dwDiff;

    SystemTimeToFileTime( &st1, &ft1 );
    SystemTimeToFileTime( &st2, &ft2 );

    li1.LowPart = ft1.dwLowDateTime;
    li1.HighPart = ft1.dwHighDateTime;
    li2.LowPart = ft2.dwLowDateTime;
    li2.HighPart = ft2.dwHighDateTime;

    //if ( CompareFileTime( &ft1, &ft2 ) < 0 ) 
    {
        liDiff.LowPart = li2.LowPart - li1.LowPart;
        liDiff.HighPart = li2.HighPart - li1.HighPart;
    }
    //else {
    //    liDiff.LowPart = li1.LowPart - li2.LowPart;
    //    liDiff.HighPart = li1.HighPart - li2.HighPart;
    //}

    dwDiff = ( (__int64)liDiff.HighPart << 32 ) + liDiff.LowPart;
    dwDiff /= ( (__int64)10 * 1000 * 1000 ); // Convert from n x 100ns intervals into seconds

    return max(1, dwDiff);
}
int main( void )
{
    /* Variable Declarations */
    int        Row, Col;
    int        ULStat = NOERRORS;
    int        BoardNum = 0;
    int        CounterNum, Quadrature, CountingMode, DataEncoding, IndexMode;
    int        numCounters, defaultCtr;
    int        InvertIndex, FlagPins, GateEnable;
    long    LoadValue;
    ULONG   Count[4], StatusBits[4];
    ULONG    BackwardBadCount[4], PreviousCount[4];
    ULONG   DiffCount[4], PrevForwardCount[4], ForwardCount[4];
    int        RegName;
    float    RevLevel = (float)CURRENTREVNUM;
    const char*    DirectionStr;
    int        ctrType = CTR7266;
    char    BoardName[BOARDNAMELEN];
    int        dummy;
    int        MoreThan2inches = 0;
    bool    bBadEncoderData = false;

    double inchesTravelled = 0.0;
    double inchesTravelledInMinute = 0.0;
    double booksPerMinute = 10.0;

    /* Declare UL Revision Level */
    ULStat = cbDeclareRevision( &RevLevel );

    InitUL();    // Set up error handling

    // get the name of the board
    if ( !GetNameOfBoard( BoardNum, BoardName ) ) {
        DisplayMessage( NOERRORS );
        return 0;
    }

    ClearScreen();
    printf( "Demonstration of 7266 Counter Functions using %s\n\n", BoardName );

    // Determine if device is compatible with this example
    numCounters = FindCountersOfType( BoardNum, ctrType, &defaultCtr );
    if ( numCounters == 0 ) {
        printf( "%s (board %u) does not have 7266 counters.\n", BoardName, BoardNum );
        DisplayMessage( NOERRORS );
        return 0;
    }

    printf( "Press any key to stop reading counter.\n\n" );

    /* set the configurable operations of the counter
        Parameters:
            BoardNum       :the number used by CB.CFG to describe this board
            CounterNum     :the counter to be configured (0-5)
            Quadrature     :Select type of counter input
            CountingMode   :Slects how counter will operate
            IndexMode      :Selects what index signal will control
            InvertIndex    :Set to ENABLED id index signal is inverted
            FlagPins       :Select which signals will drive Flag pins
            GateEnable     :Set to ENABLED to use external gating signal
    */
    double pinSpacing = 14.0;//inches

    for(int ctrIdx = 0; ctrIdx < numCounters; ++ctrIdx )
    {
    CounterNum = defaultCtr + ctrIdx;
    Quadrature = X1_QUAD;//DONE
    CountingMode = NORMAL_MODE;//DONE
    DataEncoding = BINARY_ENCODING;//DONE
    IndexMode = LOAD_CTR;//INDEX_DISABLED;
    InvertIndex = DISABLED;
    FlagPins = CARRY_BORROW;//DONE
    GateEnable = DISABLED;//DONE
    /*
    int EXTCCONV cbC7266Config (int BoardNum, int CounterNum, int Quadrature,
                                int CountingMode, int DataEncoding, int IndexMode,
                                int InvertIndex, int FlagPins, int GateEnable);
    */
    ULStat = cbC7266Config( BoardNum, CounterNum, Quadrature, CountingMode,
        DataEncoding, IndexMode, InvertIndex, FlagPins, GateEnable );

    /* send a starting value to the counter with cbCLoad()
        Parameters:
            BoardNum    :the number used by CB.CFG to describe this board
            RegName     :the counter to be loading with the starting value
            LoadValue   :the starting value to place in the counter
    */

    LoadValue = 0x000000;//FFFFFF;
    RegName = COUNT1 + CounterNum - 1;
    printf( "Loading counter #%u with an initial count of %u using cbCLoad()\n", CounterNum, LoadValue );
    ULStat = cbCLoad32( BoardNum, RegName, LoadValue );

    LoadValue = 0xFFFFFF;
    RegName = PRESET1 + CounterNum - 1;
    printf( "Setting counter #%u maximum count to %u by loading PRESET register", CounterNum, LoadValue );
    ULStat = cbCLoad32( BoardNum, RegName, LoadValue );

    ForwardCount[ctrIdx] = 0l;
    PrevForwardCount[ctrIdx] = 0l;
    DiffCount[ctrIdx] = 0l;
    PreviousCount[ctrIdx] = 0l;
    BackwardBadCount[ctrIdx] = 0l;
    }
    /* use a loop to keep checking the counter value with cbCIn() */
    SYSTEMTIME dateTime1;
    ::GetLocalTime( &dateTime1 );
    
    GetTextCursor( &Col, &Row );
    time_t startTime;
    double seconds;

    time( &startTime );
    while ( !_kbhit() ) {
        for ( int ctrIdx = 0; ctrIdx < 1;/*numCounters*/ ++ctrIdx )
        {
            CounterNum = defaultCtr + ctrIdx;
        /* Parameters:
            BoardNum    :the number used by CB.CFG to describe this board
            CounterNum  :the counter to be setup
            Count       :the count value in the counter
        */
        ULStat = cbCIn32( BoardNum, CounterNum, &Count[ctrIdx] );

        /* Parameters:
            BoardNum    :the number used by CB.CFG to describe this board
            CounterNum  :the counter to be setup
            StatusBits  :counter's status returned here
        */
        ULStat = cbCStatus( BoardNum, CounterNum, &StatusBits[ctrIdx] );
        bool bDiretionUp = !( StatusBits[ctrIdx] & C_UP_DOWN );
        if ( StatusBits[ctrIdx] & C_UP_DOWN )
            DirectionStr = "UP  ";
        else
            DirectionStr = "DOWN";
        SYSTEMTIME dateTime2;
        ::GetLocalTime( &dateTime2 );
        int pulsesPerInch = 399;
        ForwardCount[ctrIdx] = 0x00FFFFFF - ( Count[ctrIdx] & 0x00FFFFFF );
        if(PrevForwardCount[ctrIdx] != 0L && ForwardCount[ctrIdx] != PrevForwardCount[ctrIdx] && bDiretionUp )
        {
            if( ForwardCount[ctrIdx] >= PrevForwardCount[ctrIdx] )
            {
                DiffCount[ctrIdx] = (unsigned short)( ForwardCount[ctrIdx] - PrevForwardCount[ctrIdx] );
            }
            else 
            {
                ULONG DiffCount1 = (unsigned short)(0x00FFFFFF - PrevForwardCount[ctrIdx]) + (unsigned short)ForwardCount[ctrIdx];
                if( DiffCount1 < pulsesPerInch )
                {
                    DiffCount[ctrIdx] = DiffCount1;
                    ++BackwardBadCount[ctrIdx];
                }
            }
        }

        double inches = DiffCount[ctrIdx] / double( pulsesPerInch );
        inchesTravelled += inches;
        inchesTravelledInMinute += inches;
        time_t currentTime;
        time( &currentTime );
        int numberOfSeconds = difftime( currentTime, startTime );
        
        booksPerMinute = inchesTravelledInMinute / pinSpacing / numberOfSeconds * 60;
        MoveCursor( Col, Row + 2 + ctrIdx );
        printf( "\nCounter %1u is %10d, Diff is %3u, inches = %4.3f <RCOUNT %6d>%s BPMinute = %3.0f Inches Travelled  = %6.2f in %d seconds\n\n", 
            CounterNum, ForwardCount[ctrIdx], DiffCount[ctrIdx], inches, BackwardBadCount[ctrIdx], bBadEncoderData ? "<BAD>":"<GOOD>", 
            booksPerMinute, inchesTravelledInMinute, numberOfSeconds );

        if ( inches > 2.0 )
        {
            bBadEncoderData = true;
            ++MoreThan2inches;
        }
        if( numberOfSeconds > 30 && booksPerMinute > 350.0)
        {
            bBadEncoderData = true;
        }
        // /* Parameters:
        //     BoardNum    :the number used by CB.CFG to describe this board
        //     CounterNum  :the counter to be setup
        //     Count       :the count value in the counter
        // */
        // ULStat = cbCIn32( BoardNum, CounterNum, &Count );
        // 
        // /* Parameters:
        //     BoardNum    :the number used by CB.CFG to describe this board
        //     CounterNum  :the counter to be setup
        //     StatusBits  :counter's status returned here
        // */
        // ULStat = cbCStatus( BoardNum, CounterNum, &StatusBits );
        // if ( StatusBits & C_UP_DOWN )
        //     DirectionStr = "UP  ";
        // else
        //     DirectionStr = "DOWN";
        // 
        // MoveCursor( Col, Row + 1 + ctrIdx );
        // printf( "\nThe value of Counter %u is %u     \n", CounterNum, Count );
        // //printf( "The counter is now counting %s", DirectionStr );

        
        PrevForwardCount[ctrIdx] = ForwardCount[ctrIdx];
        PreviousCount[ctrIdx] = Count[ctrIdx];
        }
    }
    dummy = _getch();
    printf( "\n" );
    DisplayMessage( NOERRORS );
    return 0;
}

/////////////////////////////////////////

 

////This is the code on INtime side///////////////////

//base address retrieval code

//    process MCC-QUAD04 encoder d board
//    ------------------------------------------

                                        // check for PCI9200 vendor and device ID
                                        // if not, go process pci8010 boards
                if (  ( PciData->VendorID == PCI_VENDOR_ID_CBOARDS )
                   && ( PciData->DeviceID == PCI_DEVICE_ID_CBOARDS_QUAD04 ) )
                {

                                        // check for previous board found
                                        // if so, initialize to first board
                    if ( dNumPciMccQuad04Found == 0 )
                        dNumPciMccQuad04Found = PCI_MCCQUAD04_1_NUM;

                                        // else, advance to next board
                    else
                        dNumPciMccQuad04Found++;

                                        // install PCI application data
                    gapciapp[dNumPciMccQuad04Found].lEnable = TRUE;
                    gapciapp[dNumPciMccQuad04Found].dBaseAdr0 = PciData->u.type0.BaseAddresses[1];// & 0xFFFFFFFE;
                    gapciapp[dNumPciMccQuad04Found].dBaseAdr1 = PciData->u.type0.BaseAddresses[2];// & 0xFFFFFFFE;//NULL;

                    BoardData[0].base1 = gapciapp[dNumPciMccQuad04Found].dBaseAdr0;
                    BoardData[0].base2 = gapciapp[dNumPciMccQuad04Found].dBaseAdr1;
                    BoardData[0].irq = PciData->u.type0.InterruptLine;
                    quad04_init_one( 0 );
                    unsigned int encoderData = 0;
                    {
                        byte counter_data[3];
                        int ret = quad04_read( 0, 0, counter_data, 3 );
                        encoderData = counter_data[2] << 16 | counter_data[1] << 8 | counter_data[0];
                        encoderData = 0x00FFFFFF - ( encoderData & 0x00FFFFFF );
                    }
/////////////////////////////////////////////////////////////////////////////////////////////

void quad04_init_one( int NumBoards )
{
    int i;
    //int minor;
    dword base1;
    dword base2;
    byte data[3];
    unsigned int pci9052_intreg;
    unsigned long counterValue = 0;
    if ( NumBoards >= MAX_BOARDS )
    {
        //printk( "quad04_init_one: NumBoards = %d. Can't exceed MAX_BOARDS.  edit quad04.h.\n", NumBoards );
        return;// -ENODEV;
    }

    /*GETTING BASE ADDRESS 1 */
    base1 = BoardData[NumBoards].base1;

    /*GETTING BASE ADDRESS 2 */
    base2 = BoardData[NumBoards].base2;

    ///* Turn off interrupts */
    pci9052_intreg = _inpd( INTCSR_REG );
    pci9052_intreg &= ~( INTE | PCINT );
    _outpd( INTCSR_REG, pci9052_intreg );
    pci9052_intreg = _inpd( INTCSR_REG );

    _outpd( INTCSR_REG, pci9052_intreg | INTCLR );

    /* Initialize the LS7266R1 chip */
    BoardData[NumBoards].mode = CONFIG_0;  // (4) 24-bit counters (1/2/3/4) (default)
    BoardData[NumBoards].pic_A = 0x0;
    BoardData[NumBoards].pic_B = 0x0;
    _outp( PIC_A_REG, BoardData[NumBoards].pic_A );
    _outp( PIC_B_REG, BoardData[NumBoards].pic_B );

    BoardData[NumBoards].iscr = CONFIG_0; // default to 4 24 bit counters
    _outp( ISCR_REG, BoardData[NumBoards].iscr );
    BoardData[NumBoards].ircr = 0x0F;      // IDxSEL for all counters
    _outp( IRCR_REG, BoardData[NumBoards].ircr );

    for ( i = 0; i < NCOUNTERS; i++ )
    {
        Counter[NumBoards][i].open = TRUE;
        Counter[NumBoards][i].data_port = DATA1_REG + 2 * i;
        Counter[NumBoards][i].cmd_port = CMD1_REG + 2 * i;
        Counter[NumBoards][i].counter = i;

         //   /* Reset/Load Register */
         _outp( Counter[NumBoards][i].cmd_port, RESET_CNTR );
         _outp( Counter[NumBoards][i].cmd_port, RESET_FLAGS );
         _outp( Counter[NumBoards][i].cmd_port, RESET_E );
         _outp( Counter[NumBoards][i].cmd_port, RESET_BP );
         //   
         //   /* Be sure the prescaler is setup */
         _outp( Counter[NumBoards][i].data_port, 1 );
         _outp( Counter[NumBoards][i].cmd_port, TRAN_PR_PSC );
         _outp( Counter[NumBoards][i].cmd_port, RESET_BP );
         //   
         /* Set Counter Mode to Normal, Binary, QuadX1 */
         Counter[NumBoards][i].cmr = ( CMR1 | BIN | X1 | NORMAL );
         _outp( Counter[NumBoards][i].cmd_port, Counter[NumBoards][i].cmr );
         
         /* Enable Counter Inputs */
         Counter[NumBoards][i].ior = ( IOR1 | ENABLE_AB | LOL | RCNTR );//| FLG_CB );
         _outp( Counter[NumBoards][i].cmd_port, Counter[NumBoards][i].ior );
         
         /* Disable Index */
         Counter[NumBoards][i].idr = ( IDR1 | DISABLE_INDEX | LCNTRL_INDEX );//LOAD_CTR );//| 
         _outp( Counter[NumBoards][i].cmd_port, Counter[NumBoards][i].idr );
         //   
         ///* Load Counter Preset */
         _outp( Counter[NumBoards][i].cmd_port, RESET_BP );
         _outp( Counter[NumBoards][i].data_port, 0xFF );
         _outp( Counter[NumBoards][i].data_port, 0xFF );
         _outp( Counter[NumBoards][i].data_port, 0xFF );
        
        /* Transfer the loaded value to the counter */
        _outp( Counter[NumBoards][i].cmd_port, TRAN_PR_CNTR );
        
         /* Transfer counter to latch */
        _outp( Counter[NumBoards][i].cmd_port, ( TRAN_CNTR_OL | RESET_BP ) );
        //Init_7266( Counter[NumBoards][i].data_port );
        //Write_7266_PR( Counter[NumBoards][i].data_port, 0x00FFFFFF );
        //counterValue = Read_7266_OL( Counter[NumBoards][i].data_port );

        /* Now read back the data from the output latch */
        data[0] = _inp( Counter[NumBoards][i].data_port );
        data[1] = _inp( Counter[NumBoards][i].data_port );
        data[2] = _inp( Counter[NumBoards][i].data_port );
        
        ////* Clear the preset */
        _outp( Counter[NumBoards][i].cmd_port, RESET_BP );
        _outp( Counter[NumBoards][i].data_port, 0x0 );
        _outp( Counter[NumBoards][i].data_port, 0x0 );
        _outp( Counter[NumBoards][i].data_port, 0x0 );

        /* Reset all fags */
        _outp( Counter[NumBoards][i].cmd_port, RESET_CNTR );
        _outp( Counter[NumBoards][i].cmd_port, RESET_FLAGS );
        _outp( Counter[NumBoards][i].cmd_port, RESET_E );
        _outp( Counter[NumBoards][i].cmd_port, RESET_BP );
    }

    NumBoards++;
    return;

}
////////////////////////////////////////////////////////////////////////////////

size_t quad04_read( int board, int chan, unsigned char *buf, size_t count )
{
    int i;
    dword base1;
    dword base2;
    byte data[12];    // counter could be 24 bit to 96 bits depending upon mode

    base1 = BoardData[board].base1;
    base2 = BoardData[board].base2;

    switch ( BoardData[board].mode ) 
    {

    case CONFIG_0:   // (4) 24-Bit counters  1/2/3/4
    {
        _outp( Counter[board][chan].cmd_port, ( TRAN_CNTR_OL | RESET_BP ) );  // transfer counter to output latch
        for ( i = 0; i < 3; i++ ) 
        {
            data[i] = _inp( Counter[board][chan].data_port );
            buf[i] = data[i];
        }
        return 3;
    }
    break;

    case CONFIG_1:  // (2) 48-Bit counters  1-2/3-4
    {
        if ( chan == 0 || chan == 1 ) 
        {
            _outp( CMD1_REG, ( TRAN_CNTR_OL | RESET_BP ) );
            for ( i = 0; i < 3; i++ ) 
            {
                data[i] = _inp( DATA1_REG );
                buf[i] = data[i];
            }
            _outp( CMD2_REG, ( TRAN_CNTR_OL | RESET_BP )  );
            for ( i = 3; i < 6; i++ ) 
            {
                data[i] = _inp( DATA2_REG );
                buf[i] = data[i];
            }
        }
        else 
        {
            _outp( CMD3_REG, ( TRAN_CNTR_OL | RESET_BP ) );
            for ( i = 0; i < 3; i++ ) 
            {
                data[i] = _inp( DATA3_REG );
                buf[i] = data[i];
            }
            _outp( CMD4_REG, ( TRAN_CNTR_OL | RESET_BP ) );
            for ( i = 3; i < 6; i++ ) 
            {
                data[i] = _inp( DATA4_REG );
                buf[i] = data[i];
            }
        }
        return 6;
    }
    break;

    case CONFIG_2: // (1) 24-bit counter,  (1) 72-bit counter  1/2-3-4
    {
        if ( chan == 0 ) 
        {
            _outp( CMD1_REG, ( TRAN_CNTR_OL | RESET_BP ) );
            for ( i = 0; i < 3; i++ ) 
            {
                data[i] = _inp( DATA1_REG );
                buf[i] = data[i];
            }
            return 3;
        }
        else {
            _outp( CMD2_REG, ( TRAN_CNTR_OL | RESET_BP ) );
            for ( i = 0; i < 3; i++ ) 
            {
                data[i] = _inp( DATA2_REG );
                buf[i] = data[i];
            }
            _outp( CMD3_REG, RESET_BP );
            for ( i = 3; i < 6; i++ ) 
            {
                data[i] = _inp( DATA3_REG );
                buf[i] = data[i];
            }
            _outp( CMD4_REG, RESET_BP );
            for ( i = 6; i < 8; i++ ) 
            {
                data[i] = _inp( DATA4_REG );
                buf[i] = data[i];
            }
            return 9;
        }
    }
    break;

    case CONFIG_3: // (1) 96-bit counter   1-2-3-4
        _outp( CMD1_REG, ( TRAN_CNTR_OL | RESET_BP ) );
        for ( i = 0; i < 3; i++ ) 
        {
            data[i] = _inp( DATA1_REG );
            buf[i] = data[i];
        }
        _outp( CMD2_REG, ( TRAN_CNTR_OL | RESET_BP ) );
        for ( i = 3; i < 6; i++ ) 
        {
            data[i] = _inp( DATA2_REG );
            buf[i] = data[i];
        }
        _outp( CMD3_REG, ( TRAN_CNTR_OL | RESET_BP ) );
        for ( i = 6; i < 9; i++ ) 
        {
            data[i] = _inp( DATA3_REG );
            buf[i] = data[i];
        }
        _outp( CMD4_REG, ( TRAN_CNTR_OL | RESET_BP ) );
        for ( i = 9; i < 12; i++ ) 
        {
            data[i] = _inp( DATA4_REG );
            buf[i] = data[i];
        }
        return 12;
        break;
    }
    return 0;
}
 

////////////////////////////////////////////

Link to comment
Share on other sites

1 answer to this question

Recommended Posts

  • 0

Hello @Nathan Kumar

Unfortunately, Measurement Computing only provides support for the PCI-QUAD04 when used on Windows OS.

We do not provide drivers nor support for INtime.

You are welcome to use the 3rd party drivers provided by Warren Jasper on Github:  https://github.com/wjasper/Linux_Drivers

if you have any issues using his driver please contact him directly, his contact information is listed on the above gibhub.com page.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...