TMS320F280025: ECAP mit DMA

Part Number: TMS320F280025

Hello support team,

I'd like to have some questions

  • First question:

Based on example ecap_ex2_capture_pwm I write the code to capture PWM signal on GPIO PIN (inputxbar1)

According to SPRUIN7C, chapter 18.6.4, I'll get duty cycle (% on time)  in ECap1Regs.CAP1 with

But I use the same settings as ecap_ex2_capture_pwm with different polarity and still get duty cycle from ECap1Regs.CAP1

CAP1POL = ECAP_EVNT_FALLING_EDGE;

CAP2POL = ECAP_EVNT_RISING_EDGE;

CAP3POL = ECAP_EVNT_FALLING_EDGE;

CAP4POL = ECAP_EVNT_RISING_EDGE;

I don't get this point, could you please explain it?

  • Second question:

I want to use the DMA to get capture registers:

If I use the DMA SW Trigger inside the interrupt ECAP1_INT, I get correct data through DMA (#define TEST_SW_TRIGGER)

If I use DMA_TRIGGER_ECAP1 instead of DMA_SOFTWARE_TRIGGER, I get all 0s inside DMA interrupt. Coud you please check my settings?

Below are the code of ecap_init, dma_init as well as ecap_irq

void Ecap_Init(void)
{
  EALLOW;
  /* turn on the module clock */
  ECAP_PCLKC_BIT = 1u;

  // Disable ,clear all capture flags and interrupts
  ECAP_DBK_REGS.ECEINT.all = 0;       /* Clear bits in ECEINT register => disable all interrupts */
  ECAP_DBK_REGS.ECCLR.all = 0xFFFFu;  /* Clear bits in ECCLR register => clear all interrupts */

	// Disables time stamp capture.
  ECAP_DBK_REGS.ECCTL1.bit.CAPLDEN = 0u;

	// Stops Time stamp counter.
  ECAP_DBK_REGS.ECCTL2.bit.TSCTRSTOP = 0u;

	// Clear CAP/APWM bit => Sets eCAP in Capture mode.
  ECAP_DBK_REGS.ECCTL2.bit.CAP_APWM = 0u;

	// Sets the capture mode.
  ECAP_DBK_REGS.ECCTL2.bit.CONT_ONESHT = ECAP_CONTINUOUS_CAPTURE_MODE;
  // Capture Stops at Event 4
  ECAP_DBK_REGS.ECCTL2.bit.STOP_WRAP = ECAP_EVENT_4;
	// Sets the Capture event prescaler.
  ECAP_DBK_REGS.ECCTL1.bit.PRESCALE = 0u;

	// Sets the Capture event polarity.
  ECAP_DBK_REGS.ECCTL1.bit.CAP1POL = ECAP_EVNT_FALLING_EDGE;
  ECAP_DBK_REGS.ECCTL1.bit.CAP2POL = ECAP_EVNT_RISING_EDGE;
  ECAP_DBK_REGS.ECCTL1.bit.CAP3POL = ECAP_EVNT_FALLING_EDGE;
  ECAP_DBK_REGS.ECCTL1.bit.CAP4POL = ECAP_EVNT_RISING_EDGE;

	// Configure counter reset on events
  ECAP_DBK_REGS.ECCTL1.bit.CTRRST1 = 1;
  ECAP_DBK_REGS.ECCTL1.bit.CTRRST2 = 1;
  ECAP_DBK_REGS.ECCTL1.bit.CTRRST3 = 1;
  ECAP_DBK_REGS.ECCTL1.bit.CTRRST4 = 1;

  // Select eCAP input.
  InputXbarRegs.INPUT1SELECT = ECAP_PORTS_PIN;
  ECAP_DBK_REGS.ECCTL0.bit.INPUTSEL = ECAP_INPUT_INPUTXBAR1;

	// Sets a phase shift value count.
  ECAP_DBK_REGS.CTRPHS = 0uL;

	// Disable sync-in option
  ECAP_DBK_REGS.ECCTL2.bit.SYNCI_EN = 0u;
	// Set up the source for sync-in pulse.
  ECAP_DBK_REGS.ECAPSYNCINSEL.bit.SEL = ECAP_SYNC_IN_PULSE_SRC_DISABLE;

	// Configures Sync out signal mode.
  ECAP_DBK_REGS.ECCTL2.bit.SYNCO_SEL = ECAP_SYNC_OUT_DISABLED;

	// Configures emulation mode.
  ECAP_DBK_REGS.ECCTL1.bit.FREE_SOFT = ECAP_EMULATION_RUN_TO_ZERO;

	// Starts Time stamp counter for myECAP0.
  ECAP_DBK_REGS.ECCTL2.bit.TSCTRSTOP = 1u;

	// Enables time stamp capture for myECAP0.
  ECAP_DBK_REGS.ECCTL1.bit.CAPLDEN = 1u;

  /* DMA interrupt source is CEVT4 */
  ECAP_DBK_REGS.ECCTL2.bit.DMAEVTSEL = ECAP_EVENT_4;

	// Re-arms the eCAP module for myECAP0.
  ECAP_DBK_REGS.ECCTL2.bit.REARM = 1u;

	// Enables interrupt source for myECAP0. = Event 4
  ECAP_DBK_REGS.ECEINT.bit.CEVT4 = 1;

  CPU_EnableIRQ(CPU_INT_ECAP1);        /* Enable Interrupt */
  PieVectTable.ECAP1_INT = &Ecap_IRQHandler;   /* Map ISR function */
  EDIS;
  ECAP_InitDmaNormalMeas();
}

static void ECAP_InitDmaNormalMeas(void)
{
  EALLOW;
  /* Set up SOURCE addresses: */
  ECAP_DMA_REG.SRC_BEG_ADDR_SHADOW = (u32)&ECAP_DBK_REGS.CAP1;
  ECAP_DMA_REG.SRC_ADDR_SHADOW     = (u32)&ECAP_DBK_REGS.CAP1;

  /* Set up DESTINATION addresses: */
  ECAP_DMA_REG.DST_BEG_ADDR_SHADOW = (u32)u32CapCount;
  ECAP_DMA_REG.DST_ADDR_SHADOW     = (u32)u32CapCount;

  /* Set up BURST */
  /* all ECAP registers is transferred in a burst */
  ECAP_DMA_REG.BURST_SIZE.bit.BURSTSIZE = (u16)7; /* 4*2-1 = burst size in 16-bit words. */
  ECAP_DMA_REG.SRC_BURST_STEP = 2;  /* Increment source addr by 2 between each 32 bit transfer */
  ECAP_DMA_REG.DST_BURST_STEP = 2;  /* Increment destination addr by 2 between each 32 bit transfer */

  /* Set up Transfer */
  ECAP_DMA_REG.TRANSFER_SIZE = 0u;  /* Number of bursts per transfer */
  /* source addr is set back to ADC Result0 after each burst */
  ECAP_DMA_REG.SRC_TRANSFER_STEP = 0;
  ECAP_DMA_REG.DST_TRANSFER_STEP = 0;    /* Increment destination addr by 2 after each burst */

#ifdef TEST_SW_TRIGGER
  DmaClaSrcSelRegs.DMACHSRCSEL2.bit.CH5 = DMA_SOFTWARE_TRIGGER;//DMA_TRIGGER_ECAP1;
  ECAP_DMA_REG.MODE.bit.CONTINUOUS = 0u;
#else
  DmaClaSrcSelRegs.DMACHSRCSEL2.bit.CH5 = DMA_TRIGGER_ECAP1;
  ECAP_DMA_REG.MODE.bit.CONTINUOUS = 1u;
#endif

  ECAP_DMA_REG.MODE.bit.PERINTSEL  = ECAP_DMA_NUMBER; /* legacy bits - hard coded to channel number */
  ECAP_DMA_REG.MODE.bit.DATASIZE   = DMA_32_BIT_DAT_SIZE;
  ECAP_DMA_REG.MODE.bit.PERINTE    = 1u;
  ECAP_DMA_REG.MODE.bit.CHINTMODE  = 1u; /* interrupt at the end transfer */
  ECAP_DMA_REG.MODE.bit.CHINTE     = 1u; /* interrupt enabled */

  /* write 1 to clear any spurious flags: Interrupt flags and sync error flags */
  ECAP_DMA_REG.CONTROL.bit.PERINTCLR = 1u;
  ECAP_DMA_REG.CONTROL.bit.ERRCLR = 1u;
  /* set bit to start DMA */
  ECAP_DMA_REG.CONTROL.bit.RUN = 1u;

  PieVectTable.DMA_CH5_INT = &ECAP_DmaIsr;    /* Map interrupt function */

  EDIS;

  /* Configure DMA interrupts */
  CPU_EnableIRQ(CPU_INT_DMA_CH5);           /* Enable Dma interrupt */
}

static __interrupt void Ecap_IRQHandler(void)
{
  // Get the capture counts. Each capture should be 2x the ePWM count because of the ePWM clock divider.
  cap1Count = ECAP_DBK_REGS.CAP1;
  cap2Count = ECAP_DBK_REGS.CAP2;
  cap3Count = ECAP_DBK_REGS.CAP3;
  cap4Count = ECAP_DBK_REGS.CAP4;

  duty = 10000uLL*(uint64_t)(cap1Count+cap3Count);
  duty /= (cap1Count+cap2Count+cap3Count+cap4Count);
  frequency = 20000000uLL * CPU_SYSCLK;
  frequency /= (uint64_t)(cap1Count+cap2Count+cap3Count+cap4Count);

#ifdef TEST_SW_TRIGGER
  EALLOW;
  ECAP_DMA_REG.CONTROL.bit.RUN = 1u;
  ECAP_DMA_REG.CONTROL.bit.PERINTFRC = 1u;
  EDIS;
#endif

  EALLOW;
  // Clear interrupt flags for more interrupts.
  ECAP_DBK_REGS.ECCLR.bit.CEVT4 = 1u;
  ECAP_DBK_REGS.ECCLR.bit.INT = 1u;

  EDIS;

  Ports_TogglePin(PORTS_DEBUG_1_PIN);

  /* Acknowledge this interrupt to receive more interrupts from group 8 */
  PieCtrlRegs.PIEACK.all = CPU_PIEACK_GROUP4;
}

Thank you and regards,

Nguyen

  • Additional information:

    Example above is with PWM signal has duty cycle of 22% and frequence 1kHz

    #define DMA_TRIGGER_ECAP1             75u

  • Hi,

    Please find the reply to the above questions:

    1. The input signal as per your testcase seems to be as illustrated below:

    The duty in testcase is calculated as : 

    duty= (cap1Count+cap3Count)/(cap1Count+cap2Count+cap3Count+cap4Count);
    Using diagram and duty cycle formula used: duty = (DT+DT)/(2T)= D. Also, the value obtained by reading CAPEVT1 register is D.
    Therefore, CAPEVT1 register gives duty cycle.
    2. Can u poll CONTROL.PERINTFLG bit to check whether peripheral event trigger has arrived or not?
    Thanks,
    Divesh
  • Hi Dang,

    1. Sorry for the confusion. My first question in first post is: why in the example of SPRUIN7C, chapter 18.6.4, I should configure
    Cap1 with rising edge,
    Cap2 with falling edge,
    Cap3 with rising edge,
    Cap4 with falling edge,
    And then I can get duty cycle (% on time) from Cap1

    But in my code (based on ecap_ex2_capture_pwm), I configured
    Cap1 with falling edge,
    Cap2 with rising edge,
    Cap3 with falling edge,
    Cap4 with rising edge,
    I got duty cycle (% on time) from Cap1

    Accoding to SPRUIN7C, chapter 18.6.4, with settings in my code, I should get (% off time) in CAP1, not (% on time).
    Please correct me where I'm wrong.

    2. I think no need to poll CONTROL.PERINTFLG bit because I toggled debug pin in DMA_IRQ as well as Ecap_IRQ, the interrupt function is called

    static __interrupt void ECAP_DmaIsr(void)
    {
      Ports_TogglePin(PORTS_DEBUG_2_PIN);
    
      /* Acknowledge this interrupt to receive more interrupts from same group */
      PieCtrlRegs.PIEACK.all = CPU_PIEACK_GROUP7;
    }

    In both cases, I both get interrupt (signal 1 toggled).

    Channel 3: PWM on CAP pin

    Channel 1: Debug Pin 1

    Channel 2: Debug Pin 2

    in case of ECAP1_DMA, I got same phase offset of 2 Debug pins (2 interrupts) but the data got from DMA is 0s


    In case of SW Trigger, I get the 180° phase offset of both toggle pin but the values got from DMA are correct (please see post1)

    Regards,

    Nguyen

  • Hi,

    I already answered your first question. Please refer the following image again. 

    With respect to your example: The CAPEVT1 is configured when waveform transitions from high to low ( falling edge). Since you are resetting the counter at each counter event , the counter resets at counter event 4 also. Therefore, the counter value obtained when CAPEVT1 is detected is ON time. 

    In Case of example in 18.6.4 section of SPRUIN7C, CAPEVT2 gives us ON time while CAPEVT1 gives us OFF time.

    2. I will refer the second query to DMA expert.

    Thanks,

    Divesh

  • Hi Nguyen,

    I will help with your DMA question.

    I see that in the non-working case (eCAP triggering the DMA) you are also enabling continuous mode. The continuous mode can sometimes cause some timing issues, can you try disabling continuous and using the DMA end of transfer ISR to set the RUN bit each time?

    Also, when you run the code with TEST_SW_TRIGGER=0, what is the state of the DMA registers when you see only 0s transferred? Primarily I want to check the CONTROL register.

    Best Regards,

    Delaney

  • Hi Divesh,

    Thank you so much for the clarification.

    I think the example in 18.6.4 would be improved with info of CAPEVTx_REG to prevent the confusion.

    Regards,

    Quy

  • Hi Delaney,

    Thank you for your help.

    Without continuous mode I can get values at DMA interrupt. However I'd prefer the continuous mode (if it works) to remove the interrupt function.

    And below are the Dma registers in continuous mode:

    Regards,

    Nguyen

  • Hi Nguyen,

    I see, the continuous mode seems to isolate the issue then. From the screenshot, RUNSTS=1 and OVRFLG=0 which is good. Can you confirm with hardware watchpoints that these two states are maintained through the program run? Hardware Breakpoints and Watchpoints in CCS for C2000 devices.

    One other workaround is that you could also disable continuous mode and check if the DMA transfer has completed at the end of the ECAP ISR by looking at the RUNSTS bit. If RUNSTS=0, you can set the RUN bit again to re-enable the channel for the next transfer.

    Best Regards,

    Delaney

  • Hi Delaney,

    I solved the problem. Bit DEBUGCTRL.bit.FREE is set in other module, then I don't see correct value at break point in DMA Isr.

    Regards,

    Nguyen