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.

AM13E23019: ECAP Capture Count Offset Observation

Part Number: AM13E23019
Other Parts Discussed in Thread: SYSCONFIG

Hello there
 
I am observing an issue with the ECAP module capture counts and have attached a project that demonstrates the behavior.
 
In this project:
 
  • The PWM frequency is configured to 16 kHz without any prescaler.
  • MCPWM is generating the SyncOut pulse for ECAP.
  • PWM1A is configured to:
Go high on Compare A
Go low on Compare B
 
I am observing an offset in the capture counts. Please have a look at the image from the watch window 
 
It appears that when the pulse width approaches the PWM period, the ECAP counter restarts, even though the PWM pulse width is still shorter than the configured period and Sync Out is still not generated. I have attached the Logic analyzer capture with the measurements along with Watch window when the PWM Low pulse generated is almost near to the PWM period. 
 
 
Could you please help verify whether this is expected behavior or if there might be any issue in the ECAP synchronization/capture handling?
  • #include "device.h"
    #include "log.h"
    #include <stdint.h>
    
    #include "ti_sdk_dl_config.h"
    #include "BSP_AM13E230_E2.hpp"
    
    uint16_t tick_high_pulse = 245;
    uint16_t tick_low_pulse = APP_MCPWM_4_PERIOD - 5; // 6244
    volatile uint32_t cap1, cap2, cap3, cap4;
    
    /******** Public Constants *************************************/
    
    /******** Public Variables *************************************/
    
    /******** Public Functions Prototype ***************************/
    
    /******** Local Functions Definition ***************************/
    
    /******** Public Functions Definition **************************/
    void HAL_MotorControl_PulseGenerate_Callback_UpMode()
    {
    
        cap1 = DL_ECAP_getEventTimeStamp(APP_ECAP0_INST, DL_ECAP_EVENT_1);
        cap2 = DL_ECAP_getEventTimeStamp(APP_ECAP0_INST, DL_ECAP_EVENT_2);
        cap3 = DL_ECAP_getEventTimeStamp(APP_ECAP0_INST, DL_ECAP_EVENT_3);
        cap4 = DL_ECAP_getEventTimeStamp(APP_ECAP0_INST, DL_ECAP_EVENT_4);
        
        DL_MCPWM_setCounterCompareShadowValue(APP_MCPWM_4_INST, DL_MCPWM_COUNTER_COMPARE_1A, tick_high_pulse);
        DL_MCPWM_setCounterCompareShadowValue(APP_MCPWM_4_INST, DL_MCPWM_COUNTER_COMPARE_1B, tick_low_pulse);
    }
    
    int main()
    {
        Device_Init();
        SYSCFG_DL_init();
    
        /* Enable ECAP timestamp capture */
        DL_ECAP_startCounter(APP_ECAP0_INST);
        DL_ECAP_enableTimeStampCapture(APP_ECAP0_INST);
        
        DL_MCPWM_enableTBCLK();
        
        LOG("Entering While Loop \r\n");
        while (1)
        {
          
        }
    
        return 0;
    }
    
    
    /*********************************************************************************************
    ************************ INTERRUPT HANDLERS **************************************************
    *********************************************************************************************/
    extern "C" void APP_MCPWM_4_INT_Handler()
    {
        // BSP_AM13E230_E2::Debug3Pin_High();
        HAL_MotorControl_PulseGenerate_Callback_UpMode();
        DL_MCPWM_clearInterrupt(APP_MCPWM_4_INST, DL_MCPWM_INT_ET_1);
        DL_MCPWM_clearGlobalInterrupt(APP_MCPWM_4_INST);
        // BSP_AM13E230_E2::Debug3Pin_Low();
    }
    
    extern "C" void APP_ECAP0_INT_Handler()
    {
        BSP_AM13E230_E2::Debug3Pin_Toggle();
        DL_ECAP_clearInterrupt(APP_ECAP0_INST, DL_ECAP_ISR_SOURCE_CEVT1 | DL_ECAP_ISR_SOURCE_CEVT2 |
                                                  DL_ECAP_ISR_SOURCE_CEVT3 | DL_ECAP_ISR_SOURCE_CEVT4 |
                                                  DL_ECAP_ISR_SOURCE_CTROVF);
    
        DL_ECAP_clearGlobalInterrupt(APP_ECAP0_INST);
    }
    

  • Hello Dheeraj,

    Thank you for the detailed description and excellent debug data with the logic analyzer captures and watch window screenshots. I can see the issue you're experiencing with the ECAP capture counts.

    Root Cause

    Based on your observations, this is related to ECAP synchronization timing. When your PWM pulse width approaches the full period (as shown in your second screenshot with tick_low_pulse: 6245), the following sequence occurs:

    1. PWM1A goes low (ECAP Event 2 should capture this)
    2. Almost immediately, MCPWM generates the SyncOut pulse
    3. ECAP counter resets due to the SyncOut before Event 2 capture completes properly
    4. Result: cap2 shows a very small value (~6 counts) instead of the expected value

    From your logic analyzer, the PWM1A duty cycle is 96.72%, leaving only a very narrow low pulse. The MCPWM SyncOut appears to be generated at the end of the PWM period, which causes the ECAP counter to reset prematurely when the pulse width is near the period boundary.

    Recommended Solution

    Since you're measuring PWM pulse widths and don't appear to need synchronized capture across multiple ECAP modules, I recommend disabling ECAP's SYNCIN:

    int main()
    {
        Device_Init();
        SYSCFG_DL_init();
        
        // Disable ECAP synchronization input
        DL_ECAP_disableSyncIn(APP_ECAP0_INST);
        
        /* Enable ECAP timestamp capture */
        DL_ECAP_startCounter(APP_ECAP0_INST);
        DL_ECAP_enableTimeStampCapture(APP_ECAP0_INST);
        DL_MCPWM_enableTBCLK();
        
        LOG("Entering While Loop \r\n");
        while (1)
        {
        }
        return 0;
    }
    This prevents the MCPWM SyncOut from resetting the ECAP counter during capture operations.

    Verification

    After implementing this change, please test with extreme duty cycles:

    • tick_low_pulse = APP_MCPWM_4_PERIOD - 1
    • tick_low_pulse = 1

    You should now see consistent and accurate capture values in cap2 regardless of pulse width.

    Alternative Solutions (if synchronization is required)

    If you need to maintain ECAP synchronization for your application:

    1. Configure MCPWM SyncOut timing - Change the SyncOut generation point to CTR=ZERO (beginning of period) instead of CTR=PRD (end of period) in your TBCTL register configuration

    2. Set ECAP Phase Register - Ensure the counter phase is set to 0 with DL_ECAP_setCounterPhaseValue(APP_ECAP0_INST, 0)

    Please try the recommended solution and let me know if the issue persists or if you have any questions.

    Best Regards,
    Zackary Fleenor

  • Hi Zackary Fleenor

    this code is stripped down version of my application. In actual application, we need the synchronization of Counters of MCPWM and eCAP Modules.

    I am generating the SyncOut pulse when time base counter is becoming zero. I will upload the sysconfig screenshots here 



    Here is some more information for explaining behaviour. 

    Cap1 Cap2 Commanded Tick high pulse

    Commanded Tick Low Pulse 

    212 6214 200

    6200

    212 6218 200 6205
    212-214 6222-6224 200 6210
    212-214 6226-6228 200 6215
    212-214 6232-6234 200 6220
    212-214 6236-6238 200 6225
    212-214 6242-6244 200 6230
    212-214 6246-6248 200 6235
    212-214 2-4 200 6240
    212-214 6-8 200 6245

    I do see a constant Offset in readings (an overflow also near the boundary conditions) 

    Above data is captured again with optimisation changes and shifting relevant code into RAM 

  • I am attaching the logic analyser Screenshots 

    Zoomed in view 

    Even More Zoomed in 

  • Hello Dheeraj,

    Thank you for the additional data and SysConfig screenshots. Looking at your table more carefully, there are actually two separate issues present: a constant capture offset and a boundary overflow condition. I want to address each one individually.


    Issue 1: Constant Capture Offset

    Your data shows a consistent offset on both Cap1 and Cap2 regardless of duty cycle:

    Expected Cap1 = tick_high_pulse + fixed_offset
    212 = 200 + 12 (consistent across all rows)

    This offset is a fixed pipeline and routing delay composed of three contributors:

    1. INPUTXBAR signal routing latency from PWM1A to the ECAP input
    2. SyncIn-to-counter-load pipeline delay internal to the ECAP hardware
    3. ECAP event detection pipeline, typically 2 to 3 clock cycles

    Because the offset is constant and independent of duty cycle, this is not a configuration error. At your 200 MHz clock, 12 to 14 counts corresponds to approximately 60 to 70 ns, which is consistent with the expected INPUTXBAR routing latency on this device.


    Issue 2: Boundary Overflow Near Full Period

    Your data shows Cap2 wrapping to a small value when tick_low_pulse approaches the PWM period. The following timing reconstruction explains why this occurs.

    With tick_low_pulse = 6240 and the routing delay of 12 counts:

    TBCTR = 0 : SyncOut fires, ECAP counter resets
    ECAP_CTR = 12 : PWM1A goes high, Cap1 captured (~212)
    ECAP_CTR = 212 : PWM1A goes low, Cap2 should be ~6452
    ECAP_CTR = 6237 : TBCTR reaches 6249 (PRD), rolls to 0, new SyncOut fires
    ECAP counter resets before the falling edge is captured
    Cap2 captured : 2 to 4 counts (the remaining low pulse after reset)

    The overflow threshold can be verified directly:

    tick_high_pulse + routing_delay + tick_low_pulse > PWM_PERIOD
    200 + 12 + 6240 = 6452 > 6249 -- overflow confirmed


    Recommended Solution

    Since synchronization is required in your application, I recommend the following combined approach.

    Step 1: Set the ECAP Phase Register to compensate for routing delay

    This causes the ECAP counter to start at the measured offset value when the SyncIn arrives, aligning it with the actual PWM counter state and eliminating the Cap1 offset.

    DL_ECAP_setCounterPhaseValue(APP_ECAP0_INST, 12U);

    The value 12 should match your measured Cap1 offset. If that offset varies slightly across builds or devices, measure it once at startup and store it as a calibration constant.

    Step 2: Add boundary detection and wrap correction in the ISR

    When the ECAP counter is reset by SyncIn between Event 1 and Event 2, Cap2 will be smaller than Cap1. Detect this condition and reconstruct the correct low pulse width using the known period.

    void APP_ECAP0_INT_Handler(void)
    {
        uint32_t cap1 = DL_ECAP_getCaptureData(APP_ECAP0_INST, DL_ECAP_INPUT_CHAN_1);
        uint32_t cap2 = DL_ECAP_getCaptureData(APP_ECAP0_INST, DL_ECAP_INPUT_CHAN_2);
    
        uint32_t high_ticks;
        uint32_t low_ticks;
    
    if (cap2 < cap1)
        {
            /* SyncIn reset the counter between Event 1 and Event 2.
            Reconstruct the full low pulse from the two partial segments. */
            low_ticks = (APP_MCPWM_4_PERIOD - cap1) + cap2;
        }
    else
        {
            low_ticks = cap2 - cap1;
        }
    
    high_ticks = cap1;
    }

    Step 3: Apply software offset subtraction if residual error remains

    If a small residual offset persists after setting the phase register, subtract the calibrated offset values directly:

    #define ECAP_CAP1_OFFSET 12U
    
    high_ticks = (high_ticks >= ECAP_CAP1_OFFSET) ? high_ticks - ECAP_CAP1_OFFSET : 0U;


    Summary

    Issue
    Root Cause
    Resolution
    Cap1 offset (~12 counts)
    INPUTXBAR routing and ECAP pipeline delay
    Set phase register to measured offset value
    Cap2 offset (~14 counts)
    Same as Cap1 plus one additional capture pipeline stage
    Software offset subtraction after phase correction
    Cap2 overflow near period boundary
    SyncIn resets counter before falling edge is captured
    Boundary detection with period-wrap reconstruction in ISR

    Please try these changes and let me know if the behavior improves or if any questions come up.

    Best Regards,
    Zackary Fleenor