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.

TMS320F28384D: eCAP inaccurate timestamp of the first capture event

Part Number: TMS320F28384D

Dear TI community,

I am using an eCAP module to observe and check the generated signal of an ePWM module via the X-BAR. (example ecap_ex2_capture_pwm.c as basis)

After setting everything up (4 capture events to observe the PWM characteristic, counter reset on event enabled) and enabling the interrupt, I am stumbling over the following problem:

  • first interrupt: event time stamp of ECAP_EVENT_1 is 15214 where all others (2-4) are all equal 8003 (as expected having a period count of 2000)
  • following interrupts: event time stamp of ECAP_EVENT_1 is between 8000-8006 where all others (2-4) are still all equal 8003 (as expected)

It seems that the timestamp value of the first interrupt drifts a lot after initialization and setup.

But why is it also unconsistent after the first cycle and for all following cycles regarding capture event 1 when all other events (2-4) are still consistently 8003?

What is the expected maximum shift of the value of the first event?

Thanks in advance!

  • Hello Jules,

    It seems that the timestamp value of the first interrupt drifts a lot after initialization and setup.

    Is the eCAP started before the ePWM is? If so, that may be why there is some deviation for the first interrupt.

    But why is it also unconsistent after the first cycle and for all following cycles regarding capture event 1 when all other events (2-4) are still consistently 8003?

    What is the expected maximum shift of the value of the first event?

    To verify, if you use the default example is there any difference? What did you modify in the example, was it just modifying the input to the eCAP?

  • Thank you for the reply.

    The eCAP is started after rPWM but the first cycle is not a concern for me, I can simply ignore it.

    Addidtional to the changed input via the X-BAR the only thing I added to the example is reading out the first event because I want to use the whole capture range of 4 events. I feel like the first event was omitted from the example for exactly the same reason I encountered.

    For me it would be enough to understand where the shifts are coming from in order to be able to argue. Thank you!

  • Edit: during analysis I noticed that it is not limited to event 1 but to one event out of these 4. For example in a modified setup with counter mode down and an additional compare value, the second event timestamp is drifting while the timestamps of events 1, 3 and 4 are consistent.

  • Hello Jules,

    I believe I've found the reason for one of the captures being different, it's more than likely because of the example itself. The example, as stated in the comments at the top of the main C file, uses an ePWM that's changing its time base period during the eCAP interrupt. Because the period is changing, likely the difference being seen is the moment the eCAP is capturing this change (which doesn't necessarily always happen at the first capture event, but that's probably most likely where it occurs). I tested with a consistent ePWM signal and there is no deviation, so this is the reason that the capture values weren't consistent, which is not unexpected behavior.

  • Hello Omer and thanks for the reply.

    I quickly modified the example itself to be able to share it with you. I also deactivated the period incrementation.

    Setting a breakpoint at line 293 and observing cap1Count-cap4Count results in the described behavior for me. Event 1 is slightly drifting while all the others are as expected.

    //#############################################################################
    //
    // FILE:    ecap_ex2_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.
    //
    //#############################################################################
    // $TI Release: F2838x Support Library v3.04.00.00 $
    // $Release Date: Fri Feb 12 19:08:49 IST 2021 $
    // $Copyright:
    // Copyright (C) 2021 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 cap1Count;
    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_setDirectionMode(4, GPIO_DIR_MODE_OUT);
    
        //
        // Configure GPIO 16 as eCAP input
        //
        XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT7, 4);
    
        //
        // 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:
        //
        cap1Count = 0U;
        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_ONE_SHOT_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_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.
        //
        cap1Count = ECAP_getEventTimeStamp(ECAP1_BASE, ECAP_EVENT_1);
        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++;
    
        //
        // 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;
    }
    

  • Hello Jules,

    I'm only able to replicate what you see when I use breakpoints with your code. If I run normally and use Continuous Refresh in the Expressions window then the values are consistent. There is no issue here, likely the difference you're seeing now is just because you're setting a breakpoint (which should be somewhat expected, since a device running in standalone mode won't be expecting to pause in the middle of an ISR).

  • Thank you for your help, Omer! The breakpoints really were my issue and I was too deep into it, forgetting about the side effects of breakpoints.