This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28379D: Help with ECAP not correctly capturing PWM input

Part Number: TMS320F28379D


Tool/software:

I am trying to configure eCap to continuously measure Period and Duty of a PWM input.  I am testing with a 50% duty 10kHz PWM.  ePWM0 generates the PWM, and I connect EPWM0A on the LaunchPad to the appropriate input also on the LaunchPad, GPIO104, with Xbar configured appropriately.

With a Logic Analyzer I confirmed the 50% duty cycle on GPIO104.

I see the CAP1 register as 0x26FB, CAP2=0x1C, CAP3=0x26FB,CAP4=0x1C, which of course does not match the 50% duty cycle.  

Below are configuration details, based mainly on ecap_ex2_capture_pwm.c.  Any suggestion on why I'm not capturing the PWM correctly?

Thanks!

GPIO configuration:

GPIO_setPinConfig(GPIO_104_GPIO104);
GPIO_setDirectionMode(104, GPIO_DIR_MODE_IN);
GPIO_setPadConfig(104, GPIO_PIN_TYPE_STD);

XBAR_setInputPin(XBAR_INPUT7, 104);

ECAP Config:

ECAP_setCaptureMode(ECAP1_BASE, ECAP_CONTINUOUS_CAPTURE_MODE, ECAP_EVENT_4);

ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_1, ECAP_EVNT_FALLING_EDGE);
ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_2, ECAP_EVNT_RISING_EDGE);
ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_3, ECAP_EVNT_FALLING_EDGE);
ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_4, ECAP_EVNT_RISING_EDGE);

ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_1);
ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_2);
ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_3);
ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_4);

ECAP_enableLoadCounter(ECAP1_BASE);
ECAP_startCounter(ECAP1_BASE);
ECAP_enableTimeStampCapture(ECAP1_BASE);
ECAP_reArm(ECAP1_BASE);

ECAP_enableInterrupt(ECAP1_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);

  • Some further comment:

    The Falling Edge captures seem to be correct.  The values there are ~50us, which matches.  It is the rising edge that is off.

    If I switch which edges are rising and falling, the issue follows the rising edge:

    ECAP_setEventPolarity(ecap_bases[i], ECAP_EVENT_1, ECAP_EVNT_RISING_EDGE);
    ECAP_setEventPolarity(ecap_bases[i], ECAP_EVENT_2, ECAP_EVNT_FALLING_EDGE);
    ECAP_setEventPolarity(ecap_bases[i], ECAP_EVENT_3, ECAP_EVNT_RISING_EDGE);
    ECAP_setEventPolarity(ecap_bases[i], ECAP_EVENT_4, ECAP_EVNT_FALLING_EDGE);


    If I set all edges to rising edge, I get 0x1C for all CAP registers.

    So it seems the rising edge capture is the issue.

    I have also tried all different settings for input qualification, with no change in behavior.

  • Hi Mark Feller,

    First can you confirm if the example 2 of the eCAP works as expected? I am able to correctly run this example.

    I also switched the example over to sample from pin 104. I see no issues.

    //#############################################################################
    //
    // FILE:    ecap_capture_pwm.c
    //
    // TITLE:   Capture ePWM3.
    //
    //! \addtogroup driver_example_list
    //! <h1>eCAP Capture PWM Example</h1>
    //!
    //! This example configures ePWM3A for:
    //! - Up count mode
    //! - Period starts at 500 and goes up to 8000
    //! - Toggle output on PRD
    //!
    //! eCAP1 is configured to capture the time between rising
    //! and falling edge of the ePWM3A output.
    //!
    //! \b External \b Connections \n
    //! - eCAP1 is on GPIO16
    //! - ePWM3A is on GPIO4
    //! - Connect GPIO4 to GPIO16.
    //!
    //! \b Watch \b Variables \n
    //! - \b ecap1PassCount - Successful captures.
    //! - \b ecap1IntCount - Interrupt counts.
    //
    //#############################################################################
    //
    // 
    // $Copyright:
    // Copyright (C) 2013-2024 Texas Instruments Incorporated - http://www.ti.com/
    //
    // Redistribution and use in source and binary forms, with or without 
    // modification, are permitted provided that the following conditions 
    // are met:
    // 
    //   Redistributions of source code must retain the above copyright 
    //   notice, this list of conditions and the following disclaimer.
    // 
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the 
    //   documentation and/or other materials provided with the   
    //   distribution.
    // 
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    // 
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    // $
    //#############################################################################
    
    //
    // Included Files
    //
    #include "driverlib.h"
    #include "device.h"
    
    //
    // Defines
    //
    #define PWM3_TIMER_MIN     500U
    #define PWM3_TIMER_MAX     8000U
    #define EPWM_TIMER_UP      1U
    #define EPWM_TIMER_DOWN    0U
    
    //
    // Globals
    //
    uint32_t ecap1IntCount;
    uint32_t ecap1PassCount;
    uint32_t epwm3TimerDirection;
    volatile uint16_t cap2Count;
    volatile uint16_t cap3Count;
    volatile uint16_t cap4Count;
    volatile uint16_t epwm3PeriodCount;
    
    //
    // Function Prototypes
    //
    void error(void);
    void initECAP(void);
    void initEPWM(void);
    __interrupt void ecap1ISR(void);
    
    //
    // Main
    //
    void main(void)
    {
        //
        // Initialize device clock and peripherals
        //
        Device_init();
    
        //
        // Disable pin locks and enable internal pullups.
        //
        Device_initGPIO();
    
        //
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
    
        //
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
    
        //
        // Configure GPIO4/5 as ePWM3A/3B
        //
        GPIO_setPadConfig(4, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_4_EPWM3A);
        GPIO_setPadConfig(5, GPIO_PIN_TYPE_STD);
        GPIO_setPinConfig(GPIO_5_EPWM3B);
    
        //
        // Configure GPIO 16 as eCAP input
        //
        XBAR_setInputPin(XBAR_INPUT7, 104);
        GPIO_setPinConfig(GPIO_104_GPIO104);
        GPIO_setDirectionMode(16, GPIO_DIR_MODE_IN);
        GPIO_setQualificationMode(16, GPIO_QUAL_ASYNC);
    
        //
        // Interrupts that are used in this example are re-mapped to ISR functions
        // found within this file.
        //
        Interrupt_register(INT_ECAP1, &ecap1ISR);
    
        //
        // Configure ePWM and eCAP
        //
        initEPWM();
        initECAP();
    
        //
        // Initialize counters:
        //
        cap2Count = 0U;
        cap3Count = 0U;
        cap4Count = 0U;
        ecap1IntCount = 0U;
        ecap1PassCount = 0U;
        epwm3PeriodCount = 0U;
    
        //
        // Enable interrupts required for this example
        //
        Interrupt_enable(INT_ECAP1);
    
        //
        // Enable Global Interrupt (INTM) and Real time interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        //
        // Loop forever. Suspend or place breakpoints to observe the buffers.
        //
        for(;;)
        {
           NOP;
        }
    }
    
    //
    // initEPWM - Configure ePWM
    //
    void initEPWM()
    {
        //
        // Disable sync(Freeze clock to PWM as well)
        //
        SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    
        //
        // Configure ePWM
        //       Counter runs in up-count mode.
        //       Action qualifier will toggle output on period match
        //
        EPWM_setTimeBaseCounterMode(EPWM3_BASE, EPWM_COUNTER_MODE_UP);
        EPWM_setTimeBasePeriod(EPWM3_BASE, PWM3_TIMER_MIN);
        EPWM_setPhaseShift(EPWM3_BASE, 0U);
        EPWM_setActionQualifierAction(EPWM3_BASE,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_TOGGLE,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD);
        EPWM_setClockPrescaler(EPWM3_BASE,
                               EPWM_CLOCK_DIVIDER_1,
                               EPWM_HSCLOCK_DIVIDER_2);
    
        epwm3TimerDirection = EPWM_TIMER_UP;
    
        //
        // Enable sync and clock to PWM
        //
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    }
    
    //
    // initECAP - Configure eCAP
    //
    void initECAP()
    {
        //
        // Disable ,clear all capture flags and interrupts
        //
        ECAP_disableInterrupt(ECAP1_BASE,
                              (ECAP_ISR_SOURCE_CAPTURE_EVENT_1  |
                               ECAP_ISR_SOURCE_CAPTURE_EVENT_2  |
                               ECAP_ISR_SOURCE_CAPTURE_EVENT_3  |
                               ECAP_ISR_SOURCE_CAPTURE_EVENT_4  |
                               ECAP_ISR_SOURCE_COUNTER_OVERFLOW |
                               ECAP_ISR_SOURCE_COUNTER_PERIOD   |
                               ECAP_ISR_SOURCE_COUNTER_COMPARE));
        ECAP_clearInterrupt(ECAP1_BASE,
                            (ECAP_ISR_SOURCE_CAPTURE_EVENT_1  |
                             ECAP_ISR_SOURCE_CAPTURE_EVENT_2  |
                             ECAP_ISR_SOURCE_CAPTURE_EVENT_3  |
                             ECAP_ISR_SOURCE_CAPTURE_EVENT_4  |
                             ECAP_ISR_SOURCE_COUNTER_OVERFLOW |
                             ECAP_ISR_SOURCE_COUNTER_PERIOD   |
                             ECAP_ISR_SOURCE_COUNTER_COMPARE));
    
        //
        // Disable CAP1-CAP4 register loads
        //
        ECAP_disableTimeStampCapture(ECAP1_BASE);
    
        //
        // Configure eCAP
        //    Enable capture mode.
        //    One shot mode, stop capture at event 4.
        //    Set polarity of the events to rising, falling, rising, falling edge.
        //    Set capture in time difference mode.
        //    Select input from XBAR7.
        //    Enable eCAP module.
        //    Enable interrupt.
        //
        ECAP_stopCounter(ECAP1_BASE);
        ECAP_enableCaptureMode(ECAP1_BASE);
    
        ECAP_setCaptureMode(ECAP1_BASE, ECAP_CONTINUOUS_CAPTURE_MODE, ECAP_EVENT_4);
    
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_1, ECAP_EVNT_FALLING_EDGE);
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_2, ECAP_EVNT_RISING_EDGE);
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_3, ECAP_EVNT_FALLING_EDGE);
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_4, ECAP_EVNT_RISING_EDGE);
    
        ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_1);
        ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_2);
        ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_3);
        ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_4);
    
        XBAR_setInputPin(XBAR_INPUT7, 104);
    
        ECAP_enableLoadCounter(ECAP1_BASE);
        ECAP_setSyncOutMode(ECAP1_BASE, ECAP_SYNC_OUT_SYNCI);
        ECAP_startCounter(ECAP1_BASE);
        ECAP_enableTimeStampCapture(ECAP1_BASE);
        ECAP_reArm(ECAP1_BASE);
    
        ECAP_enableInterrupt(ECAP1_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
    }
    
    //
    // eCAP 1 ISR
    //
    __interrupt void ecap1ISR(void)
    {
        //
        // Get the capture counts. Each capture should be 4x the ePWM count
        // because of the ePWM clock dividers.
        //
        cap2Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_2);
        cap3Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_3);
        cap4Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_4);
    
        //
        // Compare the period value with the captured count
        //
        epwm3PeriodCount = EPWM_getTimeBasePeriod(EPWM3_BASE);
    
        if(cap2Count > ((epwm3PeriodCount * 4) + 4) ||
           cap2Count < ((epwm3PeriodCount * 4) - 4))
        {
            error();
        }
    
        if(cap3Count > ((epwm3PeriodCount * 4) + 4) ||
           cap3Count < ((epwm3PeriodCount * 4) - 4))
        {
            error();
        }
    
        if(cap4Count > ((epwm3PeriodCount * 4) + 4) ||
           cap4Count < ((epwm3PeriodCount * 4) - 4))
        {
            error();
        }
    
        ecap1IntCount++;
    
        //
        // Keep track of the ePWM direction and adjust period accordingly to
        // generate a variable frequency PWM.
        //
        if(epwm3TimerDirection == EPWM_TIMER_UP)
        {
            if(epwm3PeriodCount < PWM3_TIMER_MAX)
            {
               EPWM_setTimeBasePeriod(EPWM3_BASE, ++epwm3PeriodCount);
            }
            else
            {
               epwm3TimerDirection = EPWM_TIMER_DOWN;
               EPWM_setTimeBasePeriod(EPWM3_BASE, ++epwm3PeriodCount);
            }
        }
        else
        {
            if(epwm3PeriodCount > PWM3_TIMER_MIN)
            {
                EPWM_setTimeBasePeriod(EPWM3_BASE, --epwm3PeriodCount);
            }
            else
            {
               epwm3TimerDirection = EPWM_TIMER_UP;
               EPWM_setTimeBasePeriod(EPWM3_BASE, ++epwm3PeriodCount);
            }
        }
    
        //
        // Count correct captures
        //
        ecap1PassCount++;
    
        //
        // Clear interrupt flags for more interrupts.
        //
        ECAP_clearInterrupt(ECAP1_BASE,ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
        ECAP_clearGlobalInterrupt(ECAP1_BASE);
    
        //
        // Start eCAP
        //
        ECAP_reArm(ECAP1_BASE);
    
        //
        // Acknowledge the group interrupt for more interrupts.
        //
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);
    }
    
    //
    // error - Error function
    //
    void error()
    {
        ESTOP0;
    }
    

    Best,

    Ryan Ma

  • Hi Ryan,

    The example2  works.  I changed to pin 104, and also changed to EPWM1, and the example2  still works. 

    I switched to one-shot mode in my project, in order to match the example, and there is still the issue with rising edge capture.  If I look at the register contents for ECAP1, these all look as expected.

  • I provided code snippet for your configuration for pin 104. I didn't see any issues with using epwm1.

    Can you confirm?

    Best,

    Ryan Ma

  • Hi Ryan,

    The issue is related to the call to ECAP_enableLoadCounter(ECAP1_BASE);

    This is setting ECCTL2.SYNCI_EN.  If I disable this in my project, the issue goes away, and ECAP behaves normally.  

    I am configuring XBARINPUT5 for other purposes, but have the GPIO floating/disconnected.  XBARINPUT5 is connected to EXTSYNC1

  • Hi Mark, 

    Got it, sync in was being set causing TSCTR to change.

    Good catch!

    Best regards,

    Ryan Ma