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,593 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,574 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,567 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,521 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,519 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,505 Views)