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.

LAUNCHXL-F28379D: Measure DC bus via the eCAP module from gate driver (UCC21710), pwm pulse train

Part Number: LAUNCHXL-F28379D
Other Parts Discussed in Thread: UCC21710, C2000WARE, SYSCONFIG

Hello,

We would like to measure the DC bus using the eCAP module from a PWM pulse train generated by UCC21710.We need some clarification regarding the eCAP module .

Firstly, Can the eCAP measure the duty cycle from a 400 Khz pwm pulse train?, I ask this because looking at the example projects in c2000ware, i see that it is measuring a pwm pulse train of a few kilo hertz.

We tried to simulate the same example , but at a higher frequency, but as we increase the pwm frequency , the duty cycle calculation keeps deteriorating. The variable derivedDT is the result which is calculated from the eCAP module.

  

__interrupt void INT_myECAP0_ISR(void)
{
    ecap_counter++;
    cap1_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_1);    //1st raising edge
    cap2_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_2);    //1st falling edge
    cap3_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_3);    //2nd raising edge
    cap4_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_4);    //2nd falling edge
    derivedDT = (float)(cap2_count-cap1_count)/(cap3_count-cap1_count);
    ECAP_reArm(myECAP0_BASE);
    ECAP_clearGlobalInterrupt(myECAP0_BASE);
    ECAP_clearInterrupt(myECAP0_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);

}

At 10 Khz:

At 100 Khz

At 500 Khz:

  • Hi AK,

    I will see if I can reproduce what you're seeing and get back to you as soon end of day tomorrow!

    Thank you,

    Ryan Ma

  • Hi AK,

    I was not able to reproduce the difference in duty cycles you were getting at higher frequency PWM.

    Here is the attached code for my setup. I based it off of example 2 of the ecap examples within C2000Ware. 

    Here is also a screenshot of what I am getting for the derived duty cycle at 500Khz.

    //#############################################################################
    //
    // 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.
    //
    //#############################################################################
    //
    // $Release Date: $
    // $Copyright:
    // Copyright (C) 2013-2022 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     100U
    #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 cap1Count;
    volatile uint16_t cap2Count;
    volatile uint16_t cap3Count;
    volatile uint16_t cap4Count;
    volatile uint16_t epwm3PeriodCount;
    float derivedDT;
    //
    // 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, 16);
        GPIO_setPinConfig(GPIO_16_GPIO16);
        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_setCounterCompareShadowLoadMode(EPWM3_BASE,
                                             EPWM_COUNTER_COMPARE_A,
                                             EPWM_COMP_LOAD_ON_CNTR_ZERO);
    
        EPWM_setCounterCompareValue(EPWM3_BASE, EPWM_COUNTER_COMPARE_A,
                                    PWM3_TIMER_MIN >> 1);
        EPWM_setActionQualifierAction(EPWM3_BASE,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_HIGH,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
        EPWM_setActionQualifierAction(EPWM3_BASE,
                                      EPWM_AQ_OUTPUT_A,
                                      EPWM_AQ_OUTPUT_LOW,
                                      EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
        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_ONE_SHOT_CAPTURE_MODE, ECAP_EVENT_4);
    
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_1, ECAP_EVNT_RISING_EDGE);
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_2, ECAP_EVNT_FALLING_EDGE);
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_3, ECAP_EVNT_RISING_EDGE);
        ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_4, ECAP_EVNT_FALLING_EDGE);
    
        ECAP_enableCounterResetOnEvent(ECAP1_BASE, ECAP_EVENT_4);
    
        XBAR_setInputPin(XBAR_INPUT7, 16);
    
        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.
        //
        uint32_t tb_ctr_ecap = ECAP_getTimeBaseCounter(ECAP1_BASE);
        cap1Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_1);    //1st raising edge
        cap2Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_2);    //1st falling edge
        cap3Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_3);    //2nd raising edge
        cap4Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_4);    //2nd falling edge
        derivedDT = (float)(cap2Count-cap1Count)/(cap3Count-cap1Count);
    
        //
        // Compare the period value with the captured count
        //
        epwm3PeriodCount = EPWM_getTimeBasePeriod(EPWM3_BASE);
    
        ecap1IntCount++;
    
        //
        // Keep track of the ePWM direction and adjust period accordingly to
        // generate a variable frequency PWM.
        //
    
        //
        // 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;
    }
    

    Let me know if you are still running into any issues!

    Best,

    Ryan Ma

  • Hi Ryan,

    Did you try changing the duty cycle on the fly , for me it keeps on fluctuating.

    If its not too much trouble, Could you kindly try these settings and check:

    The pwm generation is baed off the example "epwm_ex11_configure_signal" in C2000WARE located at (\C2000Ware_4_01_00_00\driverlib\f2837xd\examples\cpu1\epwm)

    The struct "pwmSignal" can be changed on the fly , I have connected GPIO0 and GPIO61 together, GPIO0 generates the PWM(PWM1A is used) and GPIO61 is configured for eCAP. Just call EPWM_configureSignal(base, &pwmSignal); in the main to update the pwm values.

    /*
     * ecap_test.c
     *
     *  Created on: 18-Nov-2022
     *      Author: AK
     *
     *  Connect GPIO0 to GPIO 61
     */
    #include "ecap_test.h"
    
    uint32_t pwm_counter = 0;
    uint32_t ecap_counter = 0;
    uint32_t cap1_count = 0;
    uint32_t cap2_count = 0;
    uint32_t cap3_count = 0;
    uint32_t cap4_count = 0;
    
    float32_t derivedDT = 0.0;
    
    EPWM_SignalParams pwmSignal = {
                                   50000,                       //!< Desired Signal Frequency(in Hz)
                                   0.5f,                        //!< Desired ePWMxA Signal Duty
                                   0.5f,                        //!< Desired ePWMxB Signal Duty
                                   true,                        //!< Invert ePWMxB Signal if true
                                   DEVICE_SYSCLK_FREQ,          //!< SYSCLK Frequency(in Hz)
                                   SYSCTL_EPWMCLK_DIV_2,        //!< EPWM Clock Divider
                                   EPWM_COUNTER_MODE_UP_DOWN,   //!< Time Base Counter Mode
                                   EPWM_CLOCK_DIVIDER_1,        //!< Time Base Counter Clock Divider
                                   EPWM_HSCLOCK_DIVIDER_1       //!< Time Base Counter HS Clock Divider
    };
    //__interrupt void pwmISR(void)
    //{
    //    pwm_counter++;
    //    EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
    //    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
    //}
    __interrupt void INT_myECAP0_ISR(void)
    {
        ecap_counter++;
        cap1_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_1);    //1st raising edge
        cap2_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_2);    //1st falling edge
        cap3_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_3);    //2nd raising edge
        cap4_count = ECAP_getEventTimeStamp(myECAP0_BASE, ECAP_EVENT_4);    //2nd falling edge
        derivedDT = (float)(cap2_count-cap1_count)/(cap3_count-cap1_count);
        ECAP_reArm(myECAP0_BASE);
        ECAP_clearGlobalInterrupt(myECAP0_BASE);
        ECAP_clearInterrupt(myECAP0_BASE, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP4);
    
    }
    
    void HAL_setupECAP()
    {
        // GPIO61->ECAP1
        GPIO_setMasterCore(61, GPIO_CORE_CPU1);
        GPIO_setPinConfig(GPIO_61_GPIO61);
        GPIO_setPadConfig(61, GPIO_PIN_TYPE_PULLUP);
        GPIO_setQualificationMode(61, GPIO_QUAL_ASYNC);
    }
    
    void pwm_init(uint32_t base)
    {
        // GPIO0->EPWM1A->UH_M1
        GPIO_setMasterCore(0, GPIO_CORE_CPU1);
        GPIO_setPinConfig(GPIO_0_EPWM1A);
        GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
    
        // GPIO1->EPWM1B->UL_M1
        GPIO_setMasterCore(1, GPIO_CORE_CPU1);
        GPIO_setPinConfig(GPIO_1_EPWM1B);
        GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
    
        EPWM_configureSignal(base, &pwmSignal);
        EPWM_setSyncOutPulseMode(base, EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);
        SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
        //Interrupt_enable(INT_EPWM1);
    }
    void pwm_update_duty(uint32_t base)
    {
        switch (rec_data)
        {
        case 232:   //up arrow
        {
            pwmSignal.dutyValA += 0.05f;
            pwmSignal.dutyValB += 0.05f;
            rec_data = 0;
        }
            break;
        case 244:   //down arrow
        {
            pwmSignal.dutyValA -= 0.05f;
            pwmSignal.dutyValB -= 0.05f;
            rec_data = 0;
        }
            break;
        default:
            break;
        }
        if (pwmSignal.dutyValA > 1.0f)
        {
            pwmSignal.dutyValA = 0.99f;
        }
        else if (pwmSignal.dutyValA < 0)
        {
            pwmSignal.dutyValA = 0;
        }
        if (pwmSignal.dutyValB > 1.0f)
        {
            pwmSignal.dutyValB = 0.99f;
        }
        else if (pwmSignal.dutyValB < 0)
        {
            pwmSignal.dutyValB = 0;
        }
    
        EPWM_configureSignal(base, &pwmSignal);
    }
    
    //void HAL_setupMotorPWMs()
    //{
    //    float32_t switchingFreqKHz = 100.0;
    //    uint16_t halfPeriod = 0;
    //    EALLOW;
    //    // GPIO0->EPWM1A->UH_M1
    //    GPIO_setMasterCore(0, GPIO_CORE_CPU1);
    //    GPIO_setPinConfig(GPIO_0_EPWM1A);
    //    GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD);
    //
    //    // GPIO1->EPWM1B->UL_M1
    //    GPIO_setMasterCore(1, GPIO_CORE_CPU1);
    //    GPIO_setPinConfig(GPIO_1_EPWM1B);
    //    GPIO_setPadConfig(1, GPIO_PIN_TYPE_STD);
    //
    //    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);
    //
    //    // Time Base SubModule Registers
    //    // set Immediate load
    //    EPWM_setPeriodLoadMode(EPWM1_BASE, EPWM_PERIOD_DIRECT_LOAD);
    //    EPWM_setTimeBasePeriod(EPWM1_BASE, 0);
    //    EPWM_setPhaseShift(EPWM1_BASE, 0);
    //    EPWM_setTimeBaseCounter(EPWM1_BASE, 0);
    //    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
    //
    //    EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1,
    //                           EPWM_HSCLOCK_DIVIDER_1);
    //
    //    // Counter Compare Submodule Registers
    //    // set duty 0% initially
    //    EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 0);
    //    EPWM_setCounterCompareShadowLoadMode(EPWM1_BASE, EPWM_COUNTER_COMPARE_A,
    //                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);
    //
    //    // Action Qualifier SubModule Registers
    //    EPWM_setActionQualifierActionComplete(
    //            EPWM1_BASE,
    //            EPWM_AQ_OUTPUT_A,
    //            (EPWM_ActionQualifierEventAction) (EPWM_AQ_OUTPUT_LOW_UP_CMPA
    //                    | EPWM_AQ_OUTPUT_HIGH_DOWN_CMPA));
    //
    //    // Active high complementary PWMs - Set up the deadband
    //    EPWM_setRisingEdgeDeadBandDelayInput(EPWM1_BASE, EPWM_DB_INPUT_EPWMA);
    //    EPWM_setFallingEdgeDeadBandDelayInput(EPWM1_BASE, EPWM_DB_INPUT_EPWMA);
    //
    //    EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_RED, true);
    //    EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_FED, true);
    //    EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_RED,
    //                                  EPWM_DB_POLARITY_ACTIVE_HIGH);
    //    EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_FED,
    //                                  EPWM_DB_POLARITY_ACTIVE_LOW);
    //    /*
    //     * INFO: PWM Dead Time
    //     * Change this to change the pwm dead time.
    //     */
    //    EPWM_setRisingEdgeDelayCount(EPWM1_BASE, 50);
    //    EPWM_setFallingEdgeDelayCount(EPWM1_BASE, 50);
    //
    //    EPWM_enablePhaseShiftLoad(EPWM1_BASE);
    //
    //    EPWM_setCountModeAfterSync(EPWM1_BASE, EPWM_COUNT_MODE_UP_AFTER_SYNC);
    //    // configure sync
    //    EPWM_setSyncOutPulseMode(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_EPWMxSYNCIN);
    //
    //    //EPWM1->EWPM4
    //    SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM4,
    //                              SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    //
    /////-----------------------///
    //        halfPeriod = ((((DEVICE_SYSCLK_FREQ / 1000000U)/2.0)/switchingFreqKHz)*1000) / 2;     // 100MHz EPWMCLK
    //        EPWM_disablePhaseShiftLoad(EPWM1_BASE);
    //
    //        // sync "down-stream"
    //        EPWM_setSyncOutPulseMode(EPWM1_BASE,
    //                                 EPWM_SYNC_OUT_PULSE_ON_COUNTER_ZERO);
    //
    //        EPWM_setPhaseShift(EPWM1_BASE, 0);
    ////        EPWM_setPhaseShift(obj->pwmHandle[1], 2);
    ////        EPWM_setPhaseShift(obj->pwmHandle[2], 4);
    //
    //        EPWM_setTimeBasePeriod(EPWM1_BASE, halfPeriod);
    ////        EPWM_setTimeBasePeriod(obj->pwmHandle[1], halfPeriod);
    ////        EPWM_setTimeBasePeriod(obj->pwmHandle[2], halfPeriod);
    //
    /////-----------------------///
    //
    //    // Setting up link from EPWM to ADC
    //    // EPWM1/EPWM4 - Inverter currents at sampling frequency
    //    //               (@ PRD or @ (PRD&ZRO) )
    //    // Select SOC from counter at ctr = prd
    //    EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_SOC_A,
    //                             EPWM_SOC_TBCTR_ZERO);
    //
    //    // Generate pulse on 1st event
    //    EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_SOC_A, 1);
    //
    //    // Enable SOC on A group
    //    EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
    //
    //    EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
    //    // Enable Interrupt Generation from the PWM module
    //    EPWM_enableInterrupt(EPWM1_BASE);
    //
    //    // This needs to be 1 for the INTFRC to work
    //    EPWM_setInterruptEventCount(EPWM1_BASE, 1);
    //
    //    // Clear ePWM Interrupt flag
    //    EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
    //    EPWM_clearTripZoneFlag(EPWM1_BASE,
    //                           (EPWM_TZ_FLAG_OST | EPWM_TZ_FLAG_DCAEVT1));
    //
    //    Interrupt_register(INT_EPWM1, &pwmISR);
    //
    //    Interrupt_enable(INT_EPWM1);
    //    return;
    //}
    

    /*
     * ecap_test.h
     *
     *  Created on: 18-Nov-2022
     *      Author: AK
     */
    
    #ifndef ECAP_TEST_H_
    #define ECAP_TEST_H_
    
    #include "driverlib.h"
    #include "device.h"
    #include "board.h"
    #include "serial_driver.h"
    extern __interrupt void INT_myECAP0_ISR();
    //extern __interrupt void pwmISR();
    
    extern void HAL_setupECAP();
    extern void pwm_init(uint32_t);
    extern void pwm_update_duty(uint32_t);
    //extern void HAL_setupMotorPWMs();
    
    
    
    #endif /* ECAP_TEST_H_ */
    

  • Hi AK,

    Thank you for providing your code, I will take a look into this and respond back by end of day.

  • Hi AK,

    So I have been changing the PWM frequencies within the registers tab (in CCS) to see if I am seeing any changes.

    This is when PWM is at 50KHz:

    PWM at 200 KHz:

    PWM at 500 KHz:

    PWM at 1 MHz:

    I am still getting a reasonable duty cycle from the eCAP calculations in the above screenshots.

    Are you synchronizing the eCAP to the EPWM? Could you provide me your ECAP initialization code. Here is my initialization of eCAP code, I made sure to disable  the load counter since I am not synching with epwm:

    //
    // 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_ONE_SHOT_CAPTURE_MODE, ECAP_EVENT_4);
    
    ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_1, ECAP_EVNT_RISING_EDGE);
    ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_2, ECAP_EVNT_FALLING_EDGE);
    ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_3, ECAP_EVNT_RISING_EDGE);
    ECAP_setEventPolarity(ECAP1_BASE, ECAP_EVENT_4, ECAP_EVNT_FALLING_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, 16);
    
    //    ECAP_enableLoadCounter(ECAP1_BASE);
    ECAP_disableLoadCounter(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);

    One thing to note is the way your solving for the duty cycle could be solved in another way. 

    For example, if we have a 50Khz PWM signal, and set CMPA(999) to be half of the TBPRD (1999) in up count mode. We expect a 50% duty cycle.

    cap1_count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_1); //1st rising edge

    cap2_count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_2); //1st falling edge

    cap1_count will return the counter value when it reaches the first rising edge and cap2_count will return counter value when it reaches falling edge.

    When we enable the counter to reset on events 1 and 2, we should get the same counter for both. As shown in the screenshot below. This means that the PWM was on/off with the same count. Also meaning that it had a 50% duty cycle.

    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);

    You might notice that the cap1_count is 2*CMPA (CMPA is where the rising edge occured), this is because EPWM is clocked by SYSCLK / 2. eCAP is clocked by SYSCLK.

  • Hi Ryan, Thankyou for such a detailed explanation

    Are you synchronizing the eCAP to the EPWM? Could you provide me your ECAP initialization code. Here is my initialization of eCAP code, I made sure to disable  the load counter since I am not synching with epwm:

    Here is my initialization code, I had used sysconfig to generate the initial code, but the settings all look similar to your initialization.In the furture i plan to synchronize the eCAP with PWM switching frequency. Correct me if I am wrong but synchronization is done just by re-arming the eCAP module from the PWM ISR?

    /*
     * Copyright (c) 2020 Texas Instruments Incorporated - http://www.ti.com
     * All rights reserved.
     *
     * 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.
     *
     */
    
    #include "board.h"
    
    void Board_init()
    {
    	EALLOW;
    
    	PinMux_init();
    	INPUTXBAR_init();
    	SYNC_init();
    	CPUTIMER_init();
    	ECAP_init();
    	GPIO_init();
    	SCI_init();
    	INTERRUPT_init();
    
    	EDIS;
    }
    
    void PinMux_init()
    {
    	// GPIO31 -> blue_led Pinmux
    	GPIO_setPinConfig(GPIO_31_GPIO31);
    	//
    	// SCIA -> mySCI0 Pinmux
    	//
    	GPIO_setPinConfig(GPIO_43_SCIRXDA);
    	GPIO_setPinConfig(GPIO_42_SCITXDA);
    
    }
    
    void CPUTIMER_init(){
    	//myCPUTIMER0 initialization 
    	CPUTimer_setEmulationMode(myCPUTIMER0_BASE, CPUTIMER_EMULATIONMODE_STOPAFTERNEXTDECREMENT);
    	CPUTimer_setPreScaler(myCPUTIMER0_BASE, 0U);
    	CPUTimer_setPeriod(myCPUTIMER0_BASE, 30000U);
    	CPUTimer_enableInterrupt(myCPUTIMER0_BASE);
    	CPUTimer_stopTimer(myCPUTIMER0_BASE);
    
    	CPUTimer_reloadTimerCounter(myCPUTIMER0_BASE);
    	CPUTimer_startTimer(myCPUTIMER0_BASE);
    }
    void ECAP_init(){
    
    	//myECAP0 initialization
        // Disable ,clear all capture flags and interrupts
        ECAP_disableInterrupt(myECAP0_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(myECAP0_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));
    	// Disables time stamp capture.
    	ECAP_disableTimeStampCapture(myECAP0_BASE);
    	// Stops Time stamp counter.
    	ECAP_stopCounter(myECAP0_BASE);
    	// Sets eCAP in Capture mode.
    	ECAP_enableCaptureMode(myECAP0_BASE);
    	// Sets the capture mode.
    	ECAP_setCaptureMode(myECAP0_BASE,ECAP_ONE_SHOT_CAPTURE_MODE,ECAP_EVENT_4);
    	// Sets the Capture event prescaler.
    	ECAP_setEventPrescaler(myECAP0_BASE, 0U);
    	// Sets the Capture event polarity.
    	ECAP_setEventPolarity(myECAP0_BASE,ECAP_EVENT_1,ECAP_EVNT_RISING_EDGE);
    	ECAP_setEventPolarity(myECAP0_BASE,ECAP_EVENT_2,ECAP_EVNT_FALLING_EDGE);
    	ECAP_setEventPolarity(myECAP0_BASE,ECAP_EVENT_3,ECAP_EVNT_RISING_EDGE);
    	ECAP_setEventPolarity(myECAP0_BASE,ECAP_EVENT_4,ECAP_EVNT_FALLING_EDGE);
    	// Configure counter reset on events 
    	ECAP_disableCounterResetOnEvent(myECAP0_BASE,ECAP_EVENT_1);
    	ECAP_disableCounterResetOnEvent(myECAP0_BASE,ECAP_EVENT_2);
    	ECAP_disableCounterResetOnEvent(myECAP0_BASE,ECAP_EVENT_3);
    	ECAP_enableCounterResetOnEvent(myECAP0_BASE,ECAP_EVENT_4);	
    	// Sets a phase shift value count.
    	ECAP_setPhaseShiftCount(myECAP0_BASE,0U);
    	// Disable counter loading with phase shift value.
    	ECAP_disableLoadCounter(myECAP0_BASE);
    	// Configures Sync out signal mode.
    	ECAP_setSyncOutMode(myECAP0_BASE,ECAP_SYNC_OUT_SYNCI);
    	// Configures emulation mode.
    	ECAP_setEmulationMode(myECAP0_BASE,ECAP_EMULATION_STOP);
    
    	// Starts Time stamp counter for myECAP0.
    	ECAP_startCounter(myECAP0_BASE);
    	// Enables time stamp capture for myECAP0.
    	ECAP_enableTimeStampCapture(myECAP0_BASE);
    	// Re-arms the eCAP module for myECAP0.
    	ECAP_reArm(myECAP0_BASE);
    
    	// Enables interrupt source for myECAP0.
    	ECAP_enableInterrupt(myECAP0_BASE,(ECAP_ISR_SOURCE_CAPTURE_EVENT_4));
    
    }
    void GPIO_init(){
    		
    	//blue_led initialization
    	GPIO_setDirectionMode(blue_led, GPIO_DIR_MODE_OUT);
    	GPIO_setPadConfig(blue_led, GPIO_PIN_TYPE_STD);
    	GPIO_setMasterCore(blue_led, GPIO_CORE_CPU1);
    	GPIO_setQualificationMode(blue_led, GPIO_QUAL_SYNC);
    	GPIO_writePin(blue_led, 0);
    }
    void INPUTXBAR_init(){
    	
    	//myINPUTXBAR0 initialization
    	XBAR_setInputPin(XBAR_INPUT7, 61);
    }
    void INTERRUPT_init(){
    	
    	// Interrupt Setings for INT_myECAP0
    	Interrupt_register(INT_myECAP0, &INT_myECAP0_ISR);
    	Interrupt_enable(INT_myECAP0);
    	
    	// Interrupt Setings for INT_mySCI0_RX
    	Interrupt_register(INT_mySCI0_RX, &INT_mySCI0_RX_ISR);
    	Interrupt_enable(INT_mySCI0_RX);
    	
    	// Interrupt Setings for INT_mySCI0_TX
    	Interrupt_register(INT_mySCI0_TX, &INT_mySCI0_TX_ISR);
    	Interrupt_enable(INT_mySCI0_TX);
    }
    
    void SCI_init(){
    	
    	//mySCI0 initialization
    	SCI_clearInterruptStatus(mySCI0_BASE, SCI_INT_RXFF | SCI_INT_TXFF | SCI_INT_FE | SCI_INT_OE | SCI_INT_PE | SCI_INT_RXERR | SCI_INT_RXRDY_BRKDT | SCI_INT_TXRDY);
    	SCI_clearOverflowStatus(mySCI0_BASE);
    
    	SCI_disableFIFO(mySCI0_BASE);
    	SCI_resetChannels(mySCI0_BASE);
    
    	SCI_setConfig(mySCI0_BASE, DEVICE_LSPCLK_FREQ, mySCI0_BAUDRATE, (SCI_CONFIG_WLEN_8|SCI_CONFIG_STOP_ONE|SCI_CONFIG_PAR_NONE));
    	SCI_disableLoopback(mySCI0_BASE);
    	SCI_performSoftwareReset(mySCI0_BASE);
    	SCI_enableInterrupt(mySCI0_BASE, SCI_INT_RXRDY_BRKDT);
    	SCI_enableModule(mySCI0_BASE);
    }
    void SYNC_init(){
    	SysCtl_setSyncOutputConfig(SYSCTL_SYNC_OUT_SRC_EPWM1SYNCOUT);
    	// For EPWM1, the sync input is: SYSCTL_SYNC_IN_SRC_EXTSYNCIN1
    	SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    	SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM7, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    	SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_EPWM10, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    	SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_ECAP1, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    	SysCtl_setSyncInputConfig(SYSCTL_SYNC_IN_ECAP4, SYSCTL_SYNC_IN_SRC_EPWM1SYNCOUT);
    	// SOCA
    	SysCtl_enableExtADCSOCSource(0);
    	// SOCB
    	SysCtl_enableExtADCSOCSource(0);
    }
    

    When we enable the counter to reset on events 1 and 2, we should get the same counter for both. As shown in the screenshot below. This means that the PWM was on/off with the same count. Also meaning that it had a 50% duty cycle.

    I see, so basically we just wait for events 1 and 2 and check the deviation between the two time counts to measure the duty cycle...The advantage here is that we don't need to wait for all the 4 events to occur?

  • Hi AK,

    Synchronization is done when you enable load counter for the eCAP. If you plan to use eCAP as a asymmetric PWM signal, you could then enable load counter. However if you plan to use eCAP to capture the duty cycle, make sure to disable the load counter.

    "Once armed, the eCAP module waits for 1-4 (defined by stop-value) capture events before freezing both
    the Mod4 counter and contents of CAP1-4 registers (time stamps).
    Re-arming prepares the eCAP module for another capture sequence. Also, re-arming clears (to zero) the
    Mod4 counter and permits loading of CAP1-4 registers again, providing the CAPLDEN bit is set."

    To the second point, yes you are correct!

    Hope this helps.

    Best,

    Ryan Ma

  • Thanks Ryan , I finally was able to get it working at high frequencies.

  • No problem!

    Best Regards,

    Ryan Ma