From Friday, January 17th 11 PM CDT (January 18th 5 AM UTC) through Saturday, January 18th 11:30 AM CDT (January 18th 5:30 PM UTC), ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

Driver Development Kit (DDK)

cancel
Showing results for 
Search instead for 
Did you mean: 

M-Series Buffered Event Counting with DMA -- gating problem

Solved!
Go to solution

Hi --

I am implementing DMA-based buffered event counting on a PCIe-6259 board.  I use G0_Out as the gate for G1, which counts events on a PFI pin.   So by setting the speed of G0, I get an event count (either cumulative or non-cumulative) on a periodic basis, which is directly DMA'd to my buffer, and synchronized with other i/o operations.

This is working well right now, except for one problem, which is that the I only get data if there is at least one  source edge between gates.  i.e. if there are no edges, nothing gets pumped to the dma buffer.

I am guessing that a stale data error is somehow choking off the DMA transfer from the counter.   Is that possible?

Is there some magic that I need to do to avoid this, because for this application, especially if I am counting cumulatively, I don't care about a missing edge, but I do care if the dma transfers get out of phase with the rest of my timing.

Thanks in advance for any help!

--spg
 

Here is a snippet of the code that sets up the event counting on G1, partly based on gpctex6.cpp:


// ----------------------------------------------------

const int sDMASelect[] = {1,2,4,8,3,5};

// source:  pfi, or -1 for 20Khz clock

void eventTimerSetup(tMSeries *board, tTIO *tio, int dmaChannel, bool cumulative, int source)
{
    int sourceSelect = (source==-1) ? 0 : (source+1);
    //MSeries.CTR.Source
    tio->G1_Input_Select.setG1_Source_Select(sourceSelect); // (pfi+1) or 20Khz=0
    tio->G1_Input_Select.setG1_Source_Polarity(0); //rising=0
    tio->G1_Input_Select.setG1_OR_Gate(0);
    tio->G1_Input_Select.flush();
    //MSeries.CTR.Gate
    tio->G1_Input_Select.setG1_Gate_Select(20); //the G_OUT signal from other clock=20
    tio->G1_Input_Select.setG1_Output_Polarity(0); //active high=0
    tio->G1_Input_Select.flush();

    //MSeries.CTR.IncrementRegisters
    tio->G1_AutoIncrement.writeRegister(0);

    //MSeries.CTR.InitialCountRegisters
    tio->G1_Mode.writeG1_Load_Source_Select(tTIO::tG1_Mode::kG1_Load_Source_SelectLoad_A);
    tio->G1_Load_A.writeRegister(0);
    tio->G1_Command.writeG1_Load(1);
    tio->G1_Load_B.writeRegister(0);
    tio->G1_Load_A.writeRegister(0);
    tio->G1_Command.setG1_Bank_Switch_Enable(tTIO::tG1_Command::kG1_Bank_Switch_EnableBank_X);
    tio->G1_Command.setG1_Bank_Switch_Mode(tTIO::tG1_Command::kG1_Bank_Switch_ModeGate);
    tio->G1_Command.flush();

    //MSeries.CTR.ApplicationRegisters
    tio->G1_Input_Select.setG1_Gate_Select_Load_Source(0);
    tio->G1_Mode.setG1_Reload_Source_Switching(tTIO::tG1_Mode::kG1_Reload_Source_SwitchingAlternate);
    tio->G1_Mode.setG1_Loading_On_Gate(cumulative ? tTIO::tG1_Mode::kG1_Loading_On_GateNo_Reload : tTIO::tG1_Mode::kG1_Loading_On_GateReload_On_Stop_Gate);
    tio->G1_Mode.setG1_Loading_On_TC(tTIO::tG1_Mode::kG1_Loading_On_TCRollover_On_TC);
    tio->G1_Mode.setG1_Gating_Mode (tTIO::tG1_Mode::kG1_Gating_ModeEdge_Gating_Active_High);
    tio->G1_Mode.setG1_Gate_On_Both_Edges (tTIO::tG1_Mode::kG1_Gate_On_Both_EdgesBoth_Edges_Disabled);
    tio->G1_Mode.setG1_Trigger_Mode_For_Edge_Gate(tTIO::tG1_Mode::kG1_Trigger_Mode_For_Edge_GateGate_Does_Not_Stop);
    tio->G1_Mode.setG1_Stop_Mode(tTIO::tG1_Mode::kG1_Stop_ModeStop_On_Gate);
    tio->G1_Mode.setG1_Counting_Once(tTIO::tG1_Mode::kG1_Counting_OnceNo_HW_Disarm);
    tio->G1_Second_Gate.setG1_Second_Gate_Gating_Mode(0);
    tio->G1_Input_Select.flush();
    tio->G1_Mode.flush();
    tio->G1_Second_Gate.flush();
    //MSeries.CTR.UpDown.Registers
    tio->G1_Command.writeG1_Up_Down(tTIO::tG1_Command::kG1_Up_DownSoftware_Up); //kG1_Up_DownSoftware_Down
    //MSeries.CTR.OutputRegisters
    tio->G1_Mode.writeG1_Output_Mode(tTIO::tG1_Mode::kG1_Output_ModePulse);
    tio->G1_Input_Select.writeG1_Output_Polarity(0);

    //MSeries.CTR.BufferEnable
    board->G1_DMA_Config.writeG1_DMA_Reset(1);

    board->G1_DMA_Config.setG1_DMA_Write(0);  
    board->G1_DMA_Config.setG1_DMA_Int_Enable(0);
    board->G1_DMA_Config.setG1_DMA_Enable(1);   
    board->G1_DMA_Config.flush();

    tio->G1_Counting_Mode.setG1_Encoder_Counting_Mode(0);
    tio->G1_Counting_Mode.setG1_Alternate_Synchronization(0);
    tio->G1_Counting_Mode.flush();

    //MSeries.CTR.EnableOutput
    //board->Analog_Trigger_Etc.setGPFO_1_Output_Enable(tMSeries::tAnalog_Trigger_Etc::kGPFO_1_Output_EnableOutput);
    //board->Analog_Trigger_Etc.setGPFO_1_Output_Select(tMSeries::tAnalog_Trigger_Etc::kGPFO_1_Output_SelectG_OUT);
    //board->Analog_Trigger_Etc.flush();

    //MSeries.CTR.StartTriggerRegisters
    tio->G1_MSeries_Counting_Mode.writeG1_MSeries_HW_Arm_Enable(0);    

    board->G0_G1_Select.writeG1_DMA_Select(sDMASelect[dmaChannel]);   

    tio->G1_Command.writeG1_Arm(1); // arm it
}

 
--------------------------------------------------
Scott Gillespie
http://www.appliedbrain.com
--------------------------------------------------

------------------
scott gillespie
applied brain, inc.
------------------
0 Kudos
Message 1 of 6
(8,880 Views)

Hi Scott-

 

The "magic" you need is referred to as synchronous counting mode (or Duplicate Count Prevention in NI-DAQmx).  Try setting G1_Encoder_Counting_Mode to 6 (synchronous source mode) and G1_Alternate_Synchronization to 1 (enabled).  I haven't tried this, so there may be other settings necessary that I'm overlooking.  Let me know if you have any problems and I'll dig deeper.

 

Hopefully this helps-

Tom W
National Instruments
0 Kudos
Message 2 of 6
(8,861 Views)

Awesome -- thanks Tom.  I won't be able to try this out until next week.  I'll let you know if it works for me.

 

thanks much!

 

--spg 

------------------
scott gillespie
applied brain, inc.
------------------
0 Kudos
Message 3 of 6
(8,854 Views)

Tom --

 

Unfortunately, your suggestion didn't make a difference.  Any other ideas? 

 

-spg 

------------------
scott gillespie
applied brain, inc.
------------------
0 Kudos
Message 4 of 6
(8,808 Views)

I'm wondering if my problem might be that I adapted event timing sample code for my application (which is actually doing event counting). Perhaps I missed something in the counter setup, but I just don't see it.

 

 

------------------
scott gillespie
applied brain, inc.
------------------
0 Kudos
Message 5 of 6
(8,806 Views)
Solution
Accepted by topic author spg


Okay, I have it working now.  In addition to your suggested changes, I had to remove the following line:
 
tio->G1_MSeries_Counting_Mode.writeG1_MSeries_HW_Arm_Enable(0);    

It appears that writing something to MSeries_Counting_Mode causes that register to supersede the Counting_Mode register.  Is that right?

So code that now works for  me is listed below.

thanks Tom!

-spg

--------------------------------------


void eventCounterSetup(tMSeries *board, tTIO *tio, int dmaChannel, bool cumulative, int source) // pfi, or -1 for 20Khz clock
{
int sourceSelect = (source==-1) ? 0 : (source+1);
//MSeries.CTR.Source
tio->G1_Input_Select.setG1_Source_Select(sourceSelect); // (pfi+1) or 20Khz=0
tio->G1_Input_Select.setG1_Source_Polarity(0); //rising=0
tio->G1_Input_Select.setG1_OR_Gate(0);
tio->G1_Input_Select.flush();
//MSeries.CTR.Gate
tio->G1_Input_Select.setG1_Gate_Select(20); //the G_OUT signal from other clock=20
tio->G1_Input_Select.setG1_Output_Polarity(0); //active high=0
tio->G1_Input_Select.flush();

//MSeries.CTR.IncrementRegisters
tio->G1_AutoIncrement.writeRegister(0);

//MSeries.CTR.InitialCountRegisters
tio->G1_Mode.writeG1_Load_Source_Select(tTIO::tG1_Mode::kG1_Load_Source_SelectLoad_A);
tio->G1_Load_A.writeRegister(0);
tio->G1_Command.writeG1_Load(1);
tio->G1_Load_B.writeRegister(0);
tio->G1_Load_A.writeRegister(0);
tio->G1_Command.setG1_Bank_Switch_Enable(tTIO::tG1_Command::kG1_Bank_Switch_EnableBank_X);
tio->G1_Command.setG1_Bank_Switch_Mode(tTIO::tG1_Command::kG1_Bank_Switch_ModeGate);
tio->G1_Command.flush();

//MSeries.CTR.ApplicationRegisters
tio->G1_Input_Select.setG1_Gate_Select_Load_Source(0);
tio->G1_Mode.setG1_Reload_Source_Switching(tTIO::tG1_Mode::kG1_Reload_Source_SwitchingAlternate);
tio->G1_Mode.setG1_Loading_On_Gate(cumulative ? tTIO::tG1_Mode::kG1_Loading_On_GateNo_Reload : tTIO::tG1_Mode::kG1_Loading_On_GateReload_On_Stop_Gate);
tio->G1_Mode.setG1_Loading_On_TC(tTIO::tG1_Mode::kG1_Loading_On_TCRollover_On_TC);
tio->G1_Mode.setG1_Gating_Mode (tTIO::tG1_Mode::kG1_Gating_ModeEdge_Gating_Active_High);
tio->G1_Mode.setG1_Gate_On_Both_Edges (tTIO::tG1_Mode::kG1_Gate_On_Both_EdgesBoth_Edges_Disabled);
tio->G1_Mode.setG1_Trigger_Mode_For_Edge_Gate(tTIO::tG1_Mode::kG1_Trigger_Mode_For_Edge_GateGate_Does_Not_Stop);
tio->G1_Mode.setG1_Stop_Mode(tTIO::tG1_Mode::kG1_Stop_ModeStop_On_Gate);
tio->G1_Mode.setG1_Counting_Once(tTIO::tG1_Mode::kG1_Counting_OnceNo_HW_Disarm);
tio->G1_Second_Gate.setG1_Second_Gate_Gating_Mode(0);
tio->G1_Input_Select.flush();
tio->G1_Mode.flush();
tio->G1_Second_Gate.flush();
//MSeries.CTR.UpDown.Registers
tio->G1_Command.writeG1_Up_Down(tTIO::tG1_Command::kG1_Up_DownSoftware_Up); //kG1_Up_DownSoftware_Down
//MSeries.CTR.OutputRegisters
tio->G1_Mode.writeG1_Output_Mode(tTIO::tG1_Mode::kG1_Output_ModePulse);
tio->G1_Input_Select.writeG1_Output_Polarity(0);

//MSeries.CTR.BufferEnable
board->G1_DMA_Config.writeG1_DMA_Reset(1);

board->G1_DMA_Config.setG1_DMA_Write(0);  
board->G1_DMA_Config.setG1_DMA_Int_Enable(0);
board->G1_DMA_Config.setG1_DMA_Enable(1);   
board->G1_DMA_Config.flush();

// from Tom:
// The "magic" you need is referred to as synchronous counting mode (or Duplicate Count Prevention in NI-DAQmx).  
// Try setting G1_Encoder_Counting_Mode to 6 (synchronous source mode) and G1_Alternate_Synchronization to 1 (enabled).

tio->G1_Counting_Mode.setG1_Encoder_Counting_Mode(6); // 0
tio->G1_Counting_Mode.setG1_Alternate_Synchronization(1); // 0
tio->G1_Counting_Mode.flush();

board->G0_G1_Select.writeG1_DMA_Select(sDMASelect[dmaChannel]);   

tio->G1_Command.writeG1_Arm(1); // arm it
}


------------------
scott gillespie
applied brain, inc.
------------------
Message 6 of 6
(8,792 Views)