Digital I/O

cancel
Showing results for 
Search instead for 
Did you mean: 

Convert from PCIe-6535 to PCI-653x using DAQmx Sampling Clock Timing

Greetings,

Our device uses PCI-6533/6534 using Low Level Programming (LLP) driver for Windows 32-bit kernel, but doesn't work for Windows 7 64-bit.  These PCIs will discontinue, so I switch to PCIe-6535 using DAQmx driver, and working fine, but doesn't compatible with PCI-653x.  I would like to convert the code from PCIe-6535 to PCI-653x, please help.  Thank you in advance.

Here is our device spec.  We have a device system can cascade upto 8 chassises, and each chassis can have upto 8 slot cards, and each card has peripheral i.e. EEPROM.  To get data from peripheral of a specified Chassis, Slot Card, the system design are as follows:

Port 0 is Input (Read data from device peripheral i.e. EEPROM).  Note: This port-0 will be Output when want to write data to peripheral i.e. EEPROM.

Port 1 is Output (Peripheral Address i.e. EEPROM Address)

Port 2 is Output (Card Address)

Port 3 is Output (Main Frame or chassis Address + control bits i.e. Addr Strobe, R/W direction, and Data Strobe)

Port 4 line 0 to 2 is used as Status bits.

 

Here is the source code:

#define DAQmxErrChk(functionCall) if ( DAQmxFailed(iError = (functionCall)) ) goto LabelError; else
#define DAQmxDispErrorIfAny(line) if ( DAQmxFailed(iError) && g_iUseNIDriver == NI_DAQ_DRIVER ) { DAQmxGetExtendedErrorInfo(acErrBuff, sizeof(acErrBuff)); printf("Line %d::DAQmx Error: %s\n", line, acErrBuff); }

int DAQmxFastReadRegisterDataBlockBytes(unsigned short int ui16MainFrame, unsigned short int ui16Slot,
       unsigned short int ui16AddressStart, unsigned short int ui16AddressStop, ULONG ui32NumSamples, unsigned char *pui8Data, ULONG ui32SamplingRate)
{
       int                  iRet = ERR_OK;
       unsigned short       ui16Address;
       char                 acErrBuff[ERR_BUFF_SIZE] = {'\0'};
       int                  iError = 0;
       long                 i32BytesPerSample;
       ULONG                i,
                            *pui32DataPortBCD;
       char                 acPort[80], acPFISrc[80], acPFIDest[80];
       TaskHandle           taskHandlePortBCDO = 0,
                            taskHandlePortAI = 0;
       ULONG                ui32NewNumSamples = (ui32NumSamples < MIN_NUM_SAMPLES ? MIN_NUM_SAMPLES : ui32NumSamples);     //Need at least MIN_NUM_SAMPLES bytes, if less make it 10, and then truncate later
       unsigned char        *pui8InputData = NULL;
       int                  iMultiStates = GetPrivateProfileInt("DATA","MultiStates", 0,"SWS15100.INI");
       long                 i32SamplingRate = ui32SamplingRate;      //SAMPLING_RATE;

       //2 States (toggle DS)
       if ( iMultiStates )
       {
              ui32NewNumSamples *= 2;
              //2 States Data, so the odd bytes will ignore.
              if ((pui8InputData = (unsigned char *) malloc((ui32NewNumSamples + 1) * sizeof(char))) == NULL )
              {
                  return ERR_NOMEM;
              }
       }

       if ((pui32DataPortBCD = (ULONG *) malloc((ui32NewNumSamples + 1) * sizeof(ULONG))) == NULL )
       {
              return ERR_NOMEM;
       }

       EnterCriticalSection(&gCriticalSection);

       if ( g_iInterfaceMode == DAQ_CARD_6535 )
       {
              sprintf(acPFISrc,"/%s/PFI4", g_tdsDaqDevInfo.acDevName);
              sprintf(acPFIDest,"/%s/PFI5", g_tdsDaqDevInfo.acDevName);
       }
       else if ( g_iInterfaceMode == PCI_DIO_32HS || g_iInterfaceMode == DAQ_CARD_6533 || g_iInterfaceMode == DAQ_CARD_6534 )
       {
              sprintf(acPFISrc,"/%s/PFI6", g_tdsDaqDevInfo.acDevName);
              sprintf(acPFIDest,"/%s/PFI7", g_tdsDaqDevInfo.acDevName);
       }

       //Port-A Input
       sprintf(acPort,"/%s/port0", g_tdsDaqDevInfo.acDevName);
       DAQmxErrChk (DAQmxCreateTask("PortAI_Read", &taskHandlePortAI));
       DAQmxErrChk (DAQmxCreateDIChan(taskHandlePortAI, acPort, "", DAQmx_Val_ChanForAllLines));

       //Combines Port B, C, and D as Output Task
       sprintf(acPort,"/%s/port1:3", g_tdsDaqDevInfo.acDevName);
       DAQmxErrChk (DAQmxCreateTask("PortBCDO", &taskHandlePortBCDO));
       DAQmxErrChk (DAQmxCreateDOChan(taskHandlePortBCDO, acPort, "", DAQmx_Val_ChanForAllLines));

       //Config Sampling Clock Timing, and Exporting the Clock Timing.
       DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandlePortBCDO, "OnBoardClock", i32SamplingRate, DAQmx_Val_Rising, DAQmx_Val_ContSamps, ui32NewNumSamples));
       DAQmxErrChk (DAQmxExportSignal(taskHandlePortBCDO, DAQmx_Val_SampleClock, acPFISrc ));
       DAQmxErrChk (DAQmxCfgSampClkTiming(taskHandlePortAI,  acPFIDest  , i32SamplingRate, DAQmx_Val_Rising, DAQmx_Val_FiniteSamps, ui32NewNumSamples));
       DAQmxErrChk (DAQmxConnectTerms(acPFISrc, acPFIDest, DAQmx_Val_DoNotInvertPolarity ));

       /****************************************************************************
       Place the composite address on the data lines. The composite address includes
       the mainframe address, cassette address, and peripheral address
       ****************************************************************************/
       ui16Address = ui16AddressStart;
       for ( i = 0; i < ui32NewNumSamples; i++ )
       {
              //Write the first 8 bits of the Peripheral Address PORT-1 or PORT-B
              pui32DataPortBCD[i] =  ( ui16Address & 0xFF );
              //Slot (Cassette) Address PORT-2 or PORT-C
              pui32DataPortBCD[i] |= (ui16Slot & 0xFF) << 8;
              /****************************************************************************
              Main Frame Address. PORT-3 or PORT-D
              Set Read Mode
              AS is low => Activate the Address Strobe.
              Activate the data strobe to notify the peripherals in the bus that the
              CPU has placed the byte on the bus
              ****************************************************************************/
              //Toggling DS PORT-3 or PORT-D
              if ( i % 2 == 0 || iMultiStates == 0 )
              {
                     pui32DataPortBCD[i] |= ((ACTIVATE_DS << 6 & 0x40) | (MODE_READ << 4 & 0x10) | (ACTIVATE_AS << 3 & 0x8) | (ui16MainFrame & 0x7)) << 16;
              }
              else
              {
                     pui32DataPortBCD[i] |= ((DEACTIVATE_DS << 6 & 0x40) | (MODE_READ << 4 & 0x10) | (DEACTIVATE_AS << 3 & 0x8) | (ui16MainFrame & 0x7)) << 16;
              }
              if ( i % 2 != 0 || iMultiStates == 0 )
              {
                     //Get next Data from Peripheral Address (Wrapped around if number of samples larger than the different between Start & Stop Address)
                     //Address go upward
                     if ( ui16AddressStop >= ui16AddressStart )
                     {
                           if ( (ui16Address = ui16Address + 1) > ui16AddressStop )
                           {
                                  ui16Address = ui16AddressStart;
                           }
                     }
                     //Address go downward
                     else
                     {
                           if ( (ui16Address = ui16Address - 1) < ui16AddressStop )
                           {
                                  ui16Address = ui16AddressStart;
                           }
                     }
              }
       }
 
       //Configure Read Start Trigger
       DAQmxErrChk (DAQmxCfgDigEdgeStartTrig(taskHandlePortAI,  acPFIDest  , DAQmx_Val_Falling /* DAQmx_Val_Rising */));
       //Write at least minimum number of samples of ui32NewNumSamples
       DAQmxErrChk (DAQmxWriteDigitalU32(taskHandlePortBCDO, i, 0, 10.0, DAQmx_Val_GroupByChannel, pui32DataPortBCD, &i32BytesPerSample, NULL));
       DAQmxErrChk (DAQmxStartTask(taskHandlePortAI));
       DAQmxErrChk (DAQmxStartTask(taskHandlePortBCDO)); 

       if ( iMultiStates )
       {
              DAQmxErrChk (DAQmxReadDigitalU8(taskHandlePortAI, -1, 10.0, DAQmx_Val_GroupByChannel, pui8InputData, ui32NumSamples * 2, &i32BytesPerSample, NULL));
       }
       else
       {
              DAQmxErrChk (DAQmxReadDigitalU8(taskHandlePortAI, -1, 10.0, DAQmx_Val_GroupByChannel, pui8Data, ui32NumSamples, &i32BytesPerSample, NULL));
       }
       if ( iMultiStates )
       {
              //Filter Data (only even byte are good)
              for ( i = 0; i < (ULONG) i32BytesPerSample; i++ )
              {
                     if ( i % 2 == 0 )
                     {
                           pui8Data[i / 2] = pui8InputData[i];
                     }
              }
       }
       DAQmxErrChk (DAQmxStopTask(taskHandlePortAI));
       DAQmxErrChk (DAQmxStopTask(taskHandlePortBCDO));
       DAQmxErrChk (DAQmxClearTask(taskHandlePortAI));
       DAQmxErrChk (DAQmxClearTask(taskHandlePortBCDO));
LabelError:
       DAQmxDispErrorIfAny(__LINE__)
 
       if ( iError )
       {
              DAQmxErrChk (DAQmxStopTask(taskHandlePortAI));
              DAQmxErrChk (DAQmxStopTask(taskHandlePortBCDO));
              DAQmxErrChk (DAQmxClearTask(taskHandlePortAI));
              DAQmxErrChk (DAQmxClearTask(taskHandlePortBCDO));
       }

       LeaveCriticalSection(&gCriticalSection);

       if ( pui32DataPortBCD )
       {
              free(pui32DataPortBCD);
       }
       if ( pui8InputData && iMultiStates )
       {
              free(pui8InputData);
       }
       return iRet;
}      //End DAQmxFastReadRegisterDataBlockBytes

 

 

 

0 Kudos
Message 1 of 39
(5,242 Views)

Hi Dominator,  

 

I think I have an understanding of what you are tying to do and I'm curious if you can address a few questions for me as well.

 

 

1.  Both the PCI-6533 and PCIe-6535 devices are supported by the DAQmx driver.  What driver version do you currently have installed? 

 

2.  You said the PCI-653x wasn't compatible with the other code.  What do you mean specifically?  Do you get a specific error?  Code/programs written for the older 6533 devices are interchangeable with the new 6535 devices.  Therefore, there shouldn't be any functionality absent in one card compared to the other.    

 

3.  When you have the PCI-653x plugged in do you see the cord listed properly under 'Devices & Interfaces' in Measurement Automation Explorer?  

 

Please shine some light on the specific issues you are dealing with and I will do my best to help you in every way that I can.  

Regards,

Ben N.
Applications Engineering
ni.com/support
0 Kudos
Message 2 of 39
(5,235 Views)

The DAQmx driver version 9.1.7 works well for all cards without using Sampling Clock Timing, we're using unstrobed method withour any problem but it's very slow (10 times slower than using Low Level Programming and it's not acceptable for our device specification).  Here are the sequence of unstrobed method we used:

     //Writting Data to Output ports B, C, D to trigger Data Strobe of DEVICE, and put data to the Data Bus

     DAQmxErrChk (DAQmxWriteDigitalU8(g_taskHandlePortBO, 1, 0, 1.0, DAQmx_Val_GroupByChannel, (unsigned char *)&uhDataB, &i32Written, NULL));

     DAQmxErrChk (DAQmxWriteDigitalU8(g_taskHandlePortCO, 1, 0, 1.0, DAQmx_Val_GroupByChannel, (unsigned char *)&uhDataC, &i32Written, NULL));
     DAQmxErrChk (DAQmxWriteDigitalU8(g_taskHandlePortDO, 1, 0, 1.0, DAQmx_Val_GroupByChannel, (unsigned char *)&uhDataD, &i32Written, NULL));

     //Read data from device data bus at Port A

     DAQmxErrChk (DAQmxReadDigitalU8(g_taskHandlePortAI, 1, 1.0, DAQmx_Val_GroupByChannel, &ui8DataA, sizeof(ui8DataA), &i32BytesPerSample, NULL));

I meant the H/W is not compatiple between PCIe-6535 and PCI-653x in term of DAQmx driver .  When setting task for Sampling Clock Timing, I can't use port as a single port, it must be in a group of 2 or 4 ports i.e Port 1 must has Port 0, and also Port1 to Port 3 neet Port 0.  Here one of the error I got.

 

Port 1 cannot be used without port 0 on this device given the Sample Timing Type.
You can use ports 0 and 2 by themselves.  To use port 1, you also need to use port 0.
Property: DAQmx_SampTimingType
Requested Value: DAQmx_Val_SampClk
Output Channels: Dev3/port1
Task Name: PortBO
Status Code: -200899

 

Function DAQmxConnectTerms() is not supported for PCI-653x.

 

Is there any methods to get data from peripheral device based on our device design as described above? (1 port for Input (Reading) and the other 3 ports for Outputs (Writting)).

0 Kudos
Message 3 of 39
(5,232 Views)

Dom, 

 

I think the trouble you are running into is that the PCI-6535 has only one timing engine as opposed to two on the 33/34 series cards.  When you are routing the timing signals you will want to route the same Sample Clock reference for all tasks.  I simulated this programming structure in LabVIEW and had no problems.  Let me know if this makes sense and/or if I can assist you further with this post.  Thanks!  

 

Regards,

Ben N.
Applications Engineering
ni.com/support
0 Kudos
Message 4 of 39
(5,222 Views)

Thank you for your response,

The main problem I have is I CAN NOT use PORT 0 ALONE as the INPUT port. and the rest are OUTPUT ports.

The error code -200899 asserted.

0 Kudos
Message 5 of 39
(5,220 Views)

It's not that it can't be used, its that it can't be used with the way you have the timing setup in your program.  

 

I just tested a simulated PCIe-6535 reading on port 1 and writing on port 0,2 and 3 with no conflict or error.  I wanted to test it out with physical hardware but I currently don't have easy access to that particular module.  

 

The 653x device could have been configured differently with the timing properties and not show this problem simply because it has the dual timing engines as opposed to a single engine on this new device.  

Regards,

Ben N.
Applications Engineering
ni.com/support
0 Kudos
Message 6 of 39
(5,218 Views)

Hi Benjemin,

I think you misunderstanding about my problem,  the problem I have is on the card PCI-6533, NOT PCIe-6535.  The PCIe-6535 works perfectly.

0 Kudos
Message 7 of 39
(5,214 Views)

My apologies, now I understand your issue and can see the same behavior as well on my end.  Unfortunately, this is a hardware limitation as opposed to a problem with the source code.  

 

If you reference our KnowledgeBase here : http://digital.ni.com/public.nsf/allkb/09E85B311D74F2BB862569070058751E

you will see that these are the only port combinations supported by the hardware.   Essentially this is something that we are not going to have any control over.  

 

Out of curiosity why are you looking to migrate the 6535 BACK to an EOL device like the 6533?  Are you looking to just make the most of your existing resources and continue to use the cards?  

Regards,

Ben N.
Applications Engineering
ni.com/support
0 Kudos
Message 8 of 39
(5,205 Views)

Thank you Ben for your help,

 

I already described in the first message.

Currently, our instruments use PCI-6533 and using LLR driver.  The existing customers want to upgrade the PC from 32-bit to 64-bit Win7, and DAQmx is the way to go.

 

Is there any methods to get data using Strobed I/O using PCI-6533/6534 for our instrument?

 

If not the customers have 2 options:

[1] Use Unstrobed I/O DAQmx with very very slow speed. 😞 smileysad:

[2] Use the new card PCIe-6535 if they have PCI Express on the PC. $$$$ Smiley Mad

 

Regards,

Dom

0 Kudos
Message 9 of 39
(5,203 Views)

Dom, 

 

There is a potential workaround for this issue.  You can set up a generation of 4 ports and an acquisition on one port.  You will generate 32-bit samples and generate the 'Z' tri-state on 8 lines for the acquisition port.  These lines would now allow the DUT to drive the logic.  An FYI on doing this, is that it will force the channels into a high impedance state.  Do you think this would potentially work for your customers' application(s)? 

Regards,

Ben N.
Applications Engineering
ni.com/support
0 Kudos
Message 10 of 39
(5,181 Views)