Counter/Timer

cancel
Showing results for 
Search instead for 
Did you mean: 

Error -50175 (The specified mathematical operation results in an overflow) when writting multiple counter channels samples in a task

I using NI-DAQmx C API to create a task and then create 4 counters in that task. The task is not started at this point. Later, I call DAQmxWriteCtrFreq to write the frequency and duty cycle samples, 1 sample per channel, so each array (frequency and duty cycle) has 4 float64 positions. The write function is returning error -50175 (The specified mathematical operation results in an overflow). Running the same code in a simulated hardware works. If I run the same code, but instead of 4 counters I create just one in the task, it works. 

 

My hw setup is a CCA,CDAQ-9185 ENET CDAQ, 4-SLOT, and a MODULE ASSY, NI 9474

 

This is a simple code to reproduce the error:

#include "pch.h"

#include "NIDAQmx.h"

static const char* counters[] =
{
   #if !defined _DEBUG
   "cDAQ9185-23617DBMod3/ctr0",
   "cDAQ9185-23617DBMod3/ctr1",
   "cDAQ9185-23617DBMod3/ctr2",
   "cDAQ9185-23617DBMod3/ctr3",
   #else
   "cDAQ1Mod6/ctr0",
   "cDAQ1Mod6/ctr1",
   "cDAQ1Mod6/ctr2",
   "cDAQ1Mod6/ctr3",
   #endif
};

static const float64 frequencies[] = { 2000, 2000, 2000, 1000 };
static const float64 dutyCycles[] = { 99, 99, 99, 1 };

static void showError( int rc );

int main()
{
   int rc;
   TaskHandle task;

   std::cout << "Creating task..." << std::endl;

   if ( !DAQmxFailed( rc= DAQmxCreateTask("", &task) ) )
   {
      std::cout << "Task created, creating channels..." << std::endl;

      for ( int i = 0; !DAQmxFailed( rc ) && i < ( sizeof( counters ) / sizeof( counters[ 0 ] ) ); i++ )
      {
         if ( !DAQmxFailed( rc = DAQmxCreateCOPulseChanFreq(
            task,                                    // The task handle
            counters[ i ],                           // The name of the physical channel to use for generating the PWM pulse.
            "",                                    // The name(s) to assign to the created virtual channel(s). ("" = NI-DAQmx uses the physical channel name as the virtual channel name).
            DAQmx_Val_Hz,                           // The units in which to specify frequency.
            DAQmx_Val_Low,                           // The resting state of the output terminal.
            0,                                       // The amount of time in seconds to wait before generating the first pulse.
            frequencies[ i ],                        // The frequency at which to generate pulses.
            dutyCycles[ i ] / 100.0 ) ) )          // The width of the pulse divided by the pulse period. NI-DAQmx uses this ratio, combined with frequency, to determine pulse width and the interval between pulses.
         {
            // Specifies that the task generates samples continuously. NI-DAQmx uses the last parameter to determine the buffer size.
            rc = DAQmxCfgImplicitTiming( task, DAQmx_Val_ContSamps, 1 );
         }
      }

      if ( !DAQmxFailed( rc ) )
      {
         std::cout << "Retrieving current counter parameters from the task..." << std::endl;

         uint32_t numberOfChannels = 0;
         if ( !DAQmxFailed( rc = DAQmxGetTaskNumChans( task, ( uInt32* )&numberOfChannels ) ) )
         {
            std::vector<float64> frequencySamples( numberOfChannels );
            std::vector<float64> dutyCycleSamples( numberOfChannels );

            for ( uint32_t i = 0; i < numberOfChannels && !DAQmxFailed( rc ); i++ )
            {
               uint32_t index = i + 1; // For DAQmx functions the first channel starts in 1, hence the i + 1.
               size_t len = DAQmxGetNthTaskChannel( task, index, nullptr, 0 );
               if ( len > 0 )
               {
                  std::vector<char> ch( len, 0 ); // Allocate the required size (the null terminator is included)
                  if ( !DAQmxFailed( DAQmxGetNthTaskChannel( task, index, &ch[ 0 ], len ) ) ) // The first call was just to get the required string length. This second call will actually return the channel name.
                  {
                     DAQmxGetCOPulseFreq( task, &ch[ 0 ], &frequencySamples[ i ] );
                     DAQmxGetCOPulseDutyCyc( task, &ch[ 0 ], &dutyCycleSamples[ i ] );
                  }
               }
            }

            DAQmxResetBufOutputBufSize( task );

            if ( !DAQmxFailed( rc ) )
            {
               rc = DAQmxWriteCtrFreq(
                  task,
                  1,
                  true,
                  DAQmx_Val_WaitInfinitely,
                  DAQmx_Val_GroupByChannel,
                  &frequencySamples[ 0 ],
                  &dutyCycleSamples[ 0 ],
                  nullptr,
                  nullptr );
            }
         }
      }

      DAQmxStopTask( task );
      DAQmxClearTask( task );
   }

   if ( DAQmxFailed( rc ) )
   {
      showError( rc );
   }
}

static void showError( int rc )
{
   size_t len = DAQmxGetErrorString(
      rc,      // The NIDAQmx API error code
      nullptr, // Buffer that will have the converted error message. Passing nullptr will cause the function to return the required buffer size.
      0 );     // The size, in bytes, of the buffer passed in the errorString. Passing 0 will cause the function to return the required buffer size.

   if ( len > 0 )
   {
      std::vector<char> errorDescription( len + 1, 0 ); // Allocate the required size. Make sure we have the string terminator.
      if ( DAQmxGetErrorString( rc, &errorDescription[ 0 ], errorDescription.size() ) == 0 ) // Retrieve the error message.
      {
         std::cout << "DAQmx error: " << rc << " - " << &errorDescription[ 0 ] << std::endl;
      }
   }
}
0 Kudos
Message 1 of 1
(113 Views)