Driver Development Kit (DDK)

cancel
Showing results for 
Search instead for 
Did you mean: 

I can't get aiex1 to work

I've got a NI6232 MSeries board.  I'm using the MHDDK.  My OS is On-Time RTOS-32.  I'm using the stock aiex1.cpp example.  It is getting hung up on the line:

        while ( board->Joint_Status_2.readAI_Scan_In_Progress_St())
        {
            // waiting for scan to complete
        }

I did create a custom acquireBoard and releaseBoard for my OS in the osiUserCode.cpp file.  I think it is okay, because I can do a

    u32 serialNumber;
    serialNumReadMSeries(bus, &serialNumber);
    printf ("Serial Number: 0x%08X\n", serialNumber);

And it returns the serial number posted on the box the card came in.  The serialNumReadMSeries uses the iBus board and makes calls to

    bar0 = bus->createAddressSpace(kPCI_BAR0);
    bar1 = bus->createAddressSpace(kPCI_BAR1);

So I'm pretty sure that I've got the bar0 and bar1 mapped correctly.

I don't understand why the board->Joint_Status_2.readAI_Scan_In_Progress_St() never goes low. 






0 Kudos
Message 1 of 10
(10,485 Views)

Hi Bruce-

I had a discussion here with another user that experienced a similar problem.  There's some good info about the Scan_In_Progress status bits.  My guess is that your device is not sending an AI_Stop pulse once the scan has begun, either because the convert clock is too slow or perhaps not running at all.  Can you please give some more info about how you're setting up your timing and triggering (clock divisors, any modifications to the example functions, etc)

Additionally, the 623x devices are not "officially" supported by the DDK examples, though it should be relatively easy to get them working.  I would be interested to hear about any trouble you run into with the AI front end hardware configuration.  Unfortunately I haven't created any 623x-specific examples yet, so I can't forsee any specific "gotchas" that you might experience.

Thanks-

Message Edited by Tom W [DE] on 08-08-2007 05:33 PM

Tom W
National Instruments
0 Kudos
Message 2 of 10
(10,480 Views)
Doesn't the example set up the convert clock?  I'm a little confused on what it takes to set up a clock.

Here is the sample code based in aiex1.cpp.  The only thing I did was add a Serial Number check, and changed it to use RSE instead of Differential.

void test(iBus *bus)
{
    u32 numberOfSamples = 10;   
    u32 numberOfChannels = 2; 
   
    //  read eeprom for calibration information
   
    const u32 kEepromSize = 1024;
    u8 eepromMemory[kEepromSize];
    eepromReadMSeries (bus, eepromMemory, kEepromSize);  

    // create register map
   
   tAddressSpace  bar1;
   tMSeries *board;

   bar1 = bus->createAddressSpace(kPCI_BAR1);
   board = new tMSeries(bar1);
   

    u32 serialNumber;
    serialNumReadMSeries(bus, &serialNumber);
    printf ("Serial Number: 0x%08X\n", serialNumber);

    // ---- AI Reset ----
    //

    configureTimebase (board);
    pllReset (board);
    analogTriggerReset (board);
   
    aiReset (board);
    aiPersonalize (board, tMSeries::tAI_Output_Control::kAI_CONVERT_Output_SelectActive_Low);
    aiClearFifo (board);
   
    // ADC reset only applies to 625x boards
    adcReset(board);

    // ---- End of AI Reset ----
   
    // ---- Start AI task ----
   
    aiDisarm (board);
    aiClearConfigurationMemory (board);
   
    // fill configuration FIFO
    // Note: It is not necessary for the channel numbers to be ordered
    for (u32 i = 0; i < numberOfChannels; i++)
    {       
        aiConfigureChannel (board,
                            i,  // channel number
                            1,  // gain -- check ai.h for allowed values
                            tMSeries::tAI_Config_FIFO_Data::kAI_Config_PolarityBipolar,
//                            tMSeries::tAI_Config_FIFO_Data::kAI_Config_Channel_TypeDifferential,
                            tMSeries::tAI_Config_FIFO_Data::kAI_Config_Channel_TypeRSE,
                            (i == numberOfChannels-1)?kTrue:kFalse); // last channel?
    }

    aiSetFifoRequestMode (board);   
   
    aiEnvironmentalize (board);
   
    aiHardwareGating (board);
   
    aiTrigger (board,
               tMSeries::tAI_Trigger_Select::kAI_START1_SelectPulse,
               tMSeries::tAI_Trigger_Select::kAI_START1_PolarityRising_Edge,
               tMSeries::tAI_Trigger_Select::kAI_START2_SelectPulse,
               tMSeries::tAI_Trigger_Select::kAI_START2_PolarityRising_Edge);
   
    aiSampleStop (board,
                  (numberOfChannels > 1)?kTrue:kFalse); // multi channel?
   
    aiNumberOfSamples (board,  
                       1,      // posttrigger samples
                       0,      // pretrigger samples
                       kTrue); // continuous?
   
    aiSampleStart (board,
                   0,
                   0,
                   tMSeries::tAI_START_STOP_Select::kAI_START_SelectPulse,
                   tMSeries::tAI_START_STOP_Select::kAI_START_PolarityRising_Edge);
   
    aiConvert (board,
               280,     // convert period divisor
               280,     // convert delay divisor
               kFalse); // external sample clock?
   
    aiClearFifo (board);
   
   
    tScalingCoefficients scale;
   
    // check scale.h for scaling index values
    aiGetScalingCoefficients (eepromMemory, 0, 0, 0, &scale); 
   
    aiArm (board, kFalse);
    aiStart (board);
          
 
    // ---- Read FIFO ----
   
    i32 value;
    f32 scaled;
    u32 n = 0; // number of samples counter
    u32 m = 0; // number of channels counter
  
    while (n < numberOfSamples)
    {
        // trigger a scan
        aiStartOnDemand (board);   
       
        while ( board->Joint_Status_2.readAI_Scan_In_Progress_St())
        {
            // waiting for scan to complete
        }
           
        m = 0;
        while ( m < numberOfChannels )
        {
            if(!board->AI_Status_1.readAI_FIFO_Empty_St())
            {
                value = board->AI_FIFO_Data.readRegister ();
                aiPolynomialScaler (&value, &scaled, &scale);
                printf ("%e,\n", scaled);
                m++;
            }
        }
        n++;
    }
   
    // --- Stop ----
   
    aiDisarm (board);
   
    // cleanup
    delete board;
    bus->destroyAddressSpace(bar1);

    return;
}

0 Kudos
Message 3 of 10
(10,464 Views)

Bruce-

Two things to try immediately jump out:

1. The convert clock polarity for 622x and 623x devices should be set to active low.  For other M Series devices (currently 625x and 628x) the setting should be active high.  You should change this setting in your call to aiPersonalize().

2.  The adcReset() call is only necessary for 625x devices.  You should comment or remove this line when using 622x, 623x, or 628x devices.

3.  Once you do get the AI timing working, you'll want to update your call to aiGetScalingCoefficients().  There is a bug in the example as shipped; it configures the channel for one gain level but then reads scaling coefficients for a different gain setting.  You can check which values are supported using the enums in ai.h and scale.h for the hardware gain setting and scaling coefficient settings, respectively.  The 623x devices support the same ranges as the 622x devices.

Thanks-

Tom W
National Instruments
0 Kudos
Message 4 of 10
(10,459 Views)
I tried setting the Convert to SelectActive_High and commenting out the adcReset as shown below.  But it still gets hung up on the while ( board->Joint_Status_2.readAI_Scan_In_Progress_St()).  If I step into readAI_Scan_InProgress_St(), I see where it reads the Joint_Status_2 register 0x13a from Bar1.  The Joint_Status_2 register is always 0xffff.   So this has me doubting that I have the acquireBoard correct.  How can I be absolutely sure that I have the board, bar0, and bar1 mapped correctly?

    // ---- AI Reset ----
    //

    configureTimebase (board);
    pllReset (board);
    analogTriggerReset (board);
   
    aiReset (board);
    aiPersonalize (board, tMSeries::tAI_Output_Control::kAI_CONVERT_Output_SelectActive_High);
    aiClearFifo (board);
   
    // ADC reset only applies to 625x boards
    //adcReset(board);

    // ---- End of AI Reset ----




The comments in the ai.cpp are just backward from what you said.  Here are the comments

// NI 622x --
//      tMSeries::tAI_Output_Control::kAI_CONVERT_Output_SelectActive_High
//
// NI 625x --
//      tMSeries::tAI_Output_Control::kAI_CONVERT_Output_SelectActive_Low
//
// NI 628x --
//      tMSeries::tAI_Output_Control::kAI_CONVERT_Output_SelectActive_Low
//

void aiPersonalize (tMSeries* board,
                     tMSeries::tAI_Output_Control::tAI_CONVERT_Output_Select convertOutputSelect)
{
...
}


0 Kudos
Message 5 of 10
(10,458 Views)

Bruce-

Sorry for the confusion there- you're correct about the convert polarity.  In order to check that you're mapping Bar1 correctly, you can hit a scratch pad register in the STC2.  There's an 8-bit scratchpad at offset 0x5 from Bar1 that you can write/read.  I would write a value and then check to see if you can read the same value back.

As for Bar0, if you're able to read the serial number then you have most likely mapped Bar0 correctly.

Tom W
National Instruments
0 Kudos
Message 6 of 10
(10,451 Views)
Trying the scratch pad register:

   bar1.write8(0x05, 0x11);
   u8 testread = bar1.read8(0x05);
   printf("testread = 0x%02X\n", testread);


testread always returns 0xff.



Looking at the Serial Number Read... doesn't it use both bar0 and bar1?  It looks like it reads bar1 specifically to get the serial number?

//
// Generic eeprom read
//
void readFromEeprom(iBus *bus, u32 offset, u8 *eepromBuffer, u32 bufferSize)
{
    u32 _iowcr1Initial;
    u32 _iowbsr1Initial;
    u32 _iodwbsrInitial;
    u32 _bar1Value;
   
    tAddressSpace  bar0;   
    tAddressSpace  bar1;   
   
    bar0 = bus->createAddressSpace(kPCI_BAR0);
    bar1 = bus->createAddressSpace(kPCI_BAR1);
   
    // ---- Open EEPROM
   
    _iodwbsrInitial = bar0.read32 (0xC0);
    bar0.write32 (0xC0, 0x00);

    _iowbsr1Initial = bar0.read32 (0xC4);
    _bar1Value      = bar0.read32 (0x314);

    bar0.write32 (0xC4, (0x0000008B | _bar1Value));

    _iowcr1Initial = bar0.read32(0xF4);

    bar0.write32 (0xF4, 0x00000001 | _iowcr1Initial);
    bar0.write32 (0x30, 0xF);
       
    // ---- Read EEPROM
   
    for(u32 i = 0; i < bufferSize; ++i)
    {
        eepromBuffer[i] = bar1.read8(i + offset);
    }
   
    // ---- Close EEPROM
   
    bar0.write32 (0xC4, _iowbsr1Initial);
    bar0.write32 (0xC0, _iodwbsrInitial);
    bar0.write32 (0xF4, _iowcr1Initial);
    bar0.write32 (0x30, 0x00);
   
    bus->destroyAddressSpace(bar0);
    bus->destroyAddressSpace(bar1);
}

//
// Read calibration info from eeprom
//
void eepromReadMSeries(iBus *bus, u8 *eepromBuffer, u32 bufferSize)
{
    const u32 kStartCalEEPROM = 1024;
    const u32 kEndCalEEPROM = kStartCalEEPROM + 1024;
  
    readFromEeprom(bus, kStartCalEEPROM, eepromBuffer, bufferSize);
}

//
// Read serial number from eeprom
//
void serialNumReadMSeries(iBus *bus, u32 *serialNumber)
{
    readFromEeprom(bus, 4, (u8 *)serialNumber, 4);
  
    //
    // Serial number is returned as big-endian U32
    //
    *serialNumber = ReadBigEndianU32(*serialNumber);
}


0 Kudos
Message 7 of 10
(10,447 Views)
Writing and reading from the scratch pad register bar1 + 0x05 didn't work.

I tried reading some other registers directly after writing them... and they don't see to work either.

The fact that I can read the correct serial number tells me that I am able to read the registers ok.  It just seems to not be taking the writes.

Is there something specific that I have to do to get write access to the registers?

I've double checked the acquireBoard routine with the RTOS support people... and I'm pretty sure it is ok.  When I map the memory, I set the access to User Read and Write:              mem0 = GetDevicePtr(ioBaseAdrs0, 4096, RT_PG_USERREADWRITE);

The RTOS sees ioBaseAdrs0 (bar0) at 0xD7101000 and ioBaseAdrs1 (bar1) at 0xD7102000 which agrees with my DOS pcicfg program.

Is there another scratch pad register that I can try?



0 Kudos
Message 8 of 10
(10,440 Views)
Success.

I actually feel kind of silly now.  The problem was that I was not calling the initMite() function after the acquireBoard().  Somehow I overlooked it in porting it over to RTOS. 


I did have to change the Convert signal to high as you mentioned above:
   aiPersonalize (board, tMSeries::tAI_Output_Control::kAI_CONVERT_Output_SelectActive_High);


I am getting readings, and they appear to be correct.  What was the scaling bug that you were mentioning above?  I changed the gain to 0 (+/- 10 V).  Is there something else I have to do to?

        aiConfigureChannel (board,
                            i,  // channel number
                            0, // 1,  // gain -- check ai.h for allowed values
                            tMSeries::tAI_Config_FIFO_Data::kAI_Config_PolarityBipolar,
//                            tMSeries::tAI_Config_FIFO_Data::kAI_Config_Channel_TypeDifferential,
                            tMSeries::tAI_Config_FIFO_Data::kAI_Config_Channel_TypeRSE,
                            (i == numberOfChannels-1)?kTrue:kFalse); // last channel?

0 Kudos
Message 9 of 10
(10,434 Views)

Hi Bruce-

Glad to hear you found the issue.  You made the correct change to your aiConfigureChannel() call to address the issue I mentioned.  If you plan to use any range other than +-10V, you'll need to make sure that the gain setting you select in aiConfigureChannel() is matched correctly in aiGetScalingCoefficients().  The allowed offsets and enum values are available in ai.h and scale.h.  Otherwise, your current settings look fine.

Let us know if you run into anything else.  Thanks-

Tom W
National Instruments
0 Kudos
Message 10 of 10
(10,429 Views)