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.

LP-AM263: ECAP duty cycle issue

Part Number: LP-AM263
Other Parts Discussed in Thread: SYSCONFIG

Hello,

my purpose, is to read frequency and duty cycle of input PWM signal. When duty cycle of input signal is 50%, the frequency is read correctly. But when i'm setting 75% of duty cycle, the frequency is changed, unlike DC.

Example : I had 1800hz with 50% of DC of input signal. When 75% of DC for input signal was set. The frequency was changed to 3600 hz, DC was unchanged.

I'm using the following equation to calculate this params:

    DebugP_log("freq! %d\r\n", 1000000000/(5*(cap1Count- cap2Count)+5*(cap1Count- cap3Count)));//miliseconds
    DebugP_log("duty! %d%'%'\r\n", 100*5*(cap1Count- cap2Count)/(5*(cap1Count - cap3Count) + 5 * (cap1Count - cap4Count)));

Settings are the same as for ecap_capture_pwm project.

Ecap timestamps were setted in the interrupt

static void App_ecapIntrISR(void *handle)
{
    volatile uint16_t status;

    status = ECAP_getInterruptSource(gEcapBaseAddr);

    if(status & ECAP_ISR_SOURCE_CAPTURE_EVENT_4)
    {
        // Get the capture counts. Each capture should be 4x the ePWM count
        // because of the ePWM clock divider.
        cap1Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_1);
        cap2Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_2);
        cap3Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_3);
        cap4Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_4);



        SemaphoreP_post(&gEcapSyncSemObject);

    }

    return;
}

  • Hello Alex,

    I think your calculation logic may be wrong for the Frequency.

    What you are trying to do with the frequency is get the period of the signal which would be the amount of time to complete a full cycle. So you need to measure both the duration of the high and the low and then calculate based on that. I am going to assume your ECAP is setup as follows (part way through this I realized you may have ECAP counting down but count direction isn't important at the moment):

    With that in mind, you want to calculate the period based on the delta from ECAP1 to ECAP2 for the high signal, and the delta from ECAP2 to ECAP3 for the low signal.

    Your current formula, however, is this:

       DebugP_log("freq! %d\r\n", 1000000000/(5*(cap1Count- cap2Count)+5*(cap1Count- cap3Count)));//miliseconds

    You have the delta from ECAP2 to ECAP1, but then you have a delta from ECAP3 back to ECAP1.

    So likely both your frequency measurements are actually wrong. But what happens when you go from the 50% to 75% duty cycle is now instead of ECAP1-ECAP2 = -50, it is now equal to -75. But for both cases, since the frequency hasn't actually changed, your ECAP1-ECAP3 calculation is yielding the same result of -100. So while the frequency didn't actually change, your calculation will report a different frequency because of the duty cycle change.

    As for the magnitude of difference (2x), I think that's either an artifact of that the 1800Hz measure is also wrong or due to the specific formula you are using amplifying the error.

    Provided my assumptions are right, then revising the formula to go from (cap1Count- cap3Count) to (cap2Count- cap3Count) would prevent the duty cycle from influencing the frequency calculation.

    Best Regards,

    Ralph Jacobi

  • I'll try it today and come back with results

  • I have changed the formula based on your proposal:

     DebugP_log("freq! %d\r\n", 1000000000/(ECAP_TICK_TIME*(cap1Count- cap2Count)+ECAP_TICK_TIME*(cap2Count- cap3Count)));//miliseconds

    Now, i'm seeing the following, but I need to see the 1.8kz but not 7.2

  • for duty cycle formula is the same

  • Hi Alex,

    Sorry for the delay in reply but I wanted to do some measurements on my end with a similar tool to make sure I was interpreting your image correctly.

    I'm trying to work out how you'd get 4x the result based on what you've shown and I am not entirely clear where the error could be.

    Does it report back 7.2kHz as you change the duty cycle? Or does the frequency still change as the duty cycle changes? That would be a good first area to check to see if the formula had any positive effects.

    If it's changing with duty cycle then that'd indicate the current formula is only catching the period of half the wave form. So the question then would be where exactly the ECAP signals are actually triggering.

    What is ECAP_TICK_TIME set to and can you share what your system clock is running at?

    Best Regards,

    Ralph Jacobi

  • Hello, clock settings are the following

    ECAP_TICK_TIME is equel to 5 as in example ecap_capture_pwm.

    After some tests, I got that my formula is reporting this value

  • same result  as with previous formula, I got with this formula  1000000000/(ECAP_TICK_TIME*(cap1Count- cap3Count)

  • Hello Alex,

    That's a strange result... sorry, but I am actually out of office until Wednesday. But to try and figure out what's going on here, can you get the following printed out: cap1Count through cap4Count for a sequence?

    I'm very curious how 1Count and 2Count will compare given that 1Count to 3Count is giving just the first part of the signal.

    Also have you looked with an oscilloscope to see how sharp the waveforms are? Basically make sure there aren't slow transitions or noise?

    Also which LaunchPad pin(s) are you measuring on?

    With those details hopefully something will become apparent on what is going wrong here.

    Best Regards,

    Ralph Jacobi

  • I'm using functional genarator to make pwm signal on this pin


  • cap1Count! 159939
    cap2Count! 21
    cap3Count! 43
    cap4Count! 65



    cap1Count! 43
    cap2Count! 21
    cap3Count! 43
    cap4Count! 65


    cap1Count! 159939
    cap2Count! 21
    cap3Count! 43
    cap4Count! 65


    cap1Count! 159939
    cap2Count! 21
    cap3Count! 43
    cap4Count! 65

  • can we have a debug session on Wednesday?

  • Hi Alex,

    Sorry but I can't offer a debug session over E2E. The print results you posted are not what I was I expecting to see at all. Especially the case where cap1Count was 43. Can you share the project you are using? I'd like to run it on my own LaunchPad. I can try and configure similar but replicating your exact setup would allow me to better understand your configuration if there is anything regarding that which is leading to this issue.

    Best Regards,

    Ralph Jacobi

  • Hi Alex,

    I've been tinkering with some configurations for the ECAP and for a 1800 Hz signal, those values seem very far off the mark for what I'd expect.

    Can you please provide the .syscfg file with the ECAP configuration?

    Best Regards,

    Ralph Jacobi

  • yes, I can provide sysconfig, but code no

  • actually all formulas and clock configs were shared from my side, I don't know what can be else added. Could you please provide your implementation of frequency measurement?

  • Hello Alex,

    Thanks for sharing that. Updates on two ends from my side.

    First I did get this worked out:

    Could you please provide your implementation of frequency measurement?

    Here are the formulas I am using which I have tested across multiple Frequency and Duty Cycle combinations:

            //
            // Get the capture counts.
            //
            cap2Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_2);
            cap3Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_3);
            cap4Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_4);
    
            frequencyArray[ecap1IntCount] = (200000000 / (cap2Count + cap3Count) );
            dutyCycleArray[ecap1IntCount] = ( cap3Count / (cap2Count + cap3Count) ) * 100;
    

    I haven't gotten around to it yet but I think the 4th event can just be dropped. I don't use that count to get frequency and duty cycle results.

    I print write the results from the application rather than the ISR.

    Edit: I should also explain... the 200000000 is the EPWM source clock which is the System Clock. Because the Capture Counts are based on how many clock cycles occurred between edges, using two subsequent readings gets the high and low portion of the signal. The combined value then is the measured period for the signal and so you just need to divide the source clock value with the count values to get the frequency of the signal.

    For duty cycle the cap3Count reflects the period when the signal is high, so that is what should be used as the numerator for the duty cycle calculation.

    Lastly, I set all of those variables to float in order to get the floating point calculations done to not have any truncation. The duty cycle formula would break if not using float as it is written (though the quick fix would be to multiply cap3Count by 100 first and then do the divide process).

    Example:

    Calculated Frequency: 25009.378906
    Calculated Duty Cycle: 75.003120

    cap1Count! 159939
    cap2Count! 21
    cap3Count! 43
    cap4Count! 65

    Now circling back to these results versus your SysConfig, I think you are feeding a much faster signal in than 1800 Hz. I compared the SysConfig you sent me with my own and found negligible differences with the ECAP side. But the EPWM side it looks like the EPWM is significantly faster as it only has a Time Base Period of 10.

    Best Regards,

    Ralph Jacobi

  • could you please also share your sysconfig?

  • Hello Alex,

    Sure! See attached.

    https://e2e.ti.com/cfs-file/__key/communityserver-discussions-components-files/791/6746.example.syscfg

    Best Regards,

    Ralph Jacobi

  • Hello, I have tried with your settings, it's much better than was. But still not that what I want to have.

     What I see on logic analyzer.

    The results is very vary and they don't reflect actual setting. This is what I've obtain.

  • few more results

    Btw what amplitude you are using, in my case it's 3 volts?

  • Hi Alex,

    Yes I am using 3 Volts.

    Are those results from using a continuous signal on the EPWM9 pin and just running the ECAP endlessly? Or is the frequency being varied? If varied, by how much and at what interval?

    I had tried a number of frequencies and duty cycles previously and didn't see such issues, so I want to be sure to better replicate the exact conditions of your signal to see if I can observe the same.

    I won't likely be able to test before Monday but want to know ahead of time so I can prioritize this on Monday AM.

    Best Regards,

    Ralph Jacobi

  • Frequency was always the same during test. See picture of waveform. 1.25kHz, 40% DC and 3 Volts of amplitude. I used your configuration for EPWM and ECAP.

  • Hello Alex,

    I put together a longer test today running the ECAP capture for a 1250 Hz, 40% duty cycle, 3.3V signal for an extended period of time and did not observe any notable variation with the measurement.

    For this test I used an external signal rather than the EPWM of the AM263 module, though I did run a brief test with a 50% duty cycle 1250 Hz signal from the EPWM of AM263 as well.

    Where are you calculating and printing the results? My code is setup to not print the results in the ISR to minimize the time spent inside of it. Also are you using floats for the variables to both read the counts and stored the calculated values?

    If you are using the same settings, I'm kind of at a loss as to why we are seeing such drastically different results. Just trying to think of what software related differences could be influencing that.

    Best Regards,

    Ralph Jacobi

  • Hi, the following code I'm using, it runs continuously in 50ms freertos periodic task

    #include "bsp_tasks.h"
    
    #include <kernel/dpl/SemaphoreP.h>
    
    #include "messages.h"
    #include "module_interface.h"
    #include "task_mng.h"
    #include "sw_pwm.h"
    
    #include "gpio_do.h"
    #include <drivers/epwm.h>
    #include "pifi.h"
    
    #define APP_INT_IS_PULSE  (1U)
    #define ECAP_TICK_TIME    (5U)
    
    freq_t freq;
    duty_cycle_t duty;
    /* variable to hold base address of EPWM that is used */
    uint32_t gEpwmBaseAddr;
    uint32_t gEcapBaseAddr;
    
    static SemaphoreP_Object gEcapSyncSemObject;
    static HwiP_Object gEcapHwiObject;
    
    volatile uint32_t cap1Count;
    volatile uint32_t cap2Count;
    volatile uint32_t cap3Count;
    volatile uint32_t cap4Count;
    
    void captureSignal(uint32_t *data)
    {
        cap1Count = 0U;
        cap2Count = 0U;
        cap3Count = 0U;
        cap4Count = 0U;
    
        DebugP_log("call captureSignal\r\n");
    
        ECAP_clearInterrupt(gEcapBaseAddr, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
        ECAP_clearGlobalInterrupt(gEcapBaseAddr);
        //
        // Start eCAP
        //
        ECAP_reArm(gEcapBaseAddr);
    
        SemaphoreP_pend(&gEcapSyncSemObject, SystemP_WAIT_FOREVER);
    
                      frequ = (200000000 / (cap3Count + cap2Count) );
                      uk = ( cap3Count*100 / (cap3Count + cap2Count) )  ;
    
                      DebugP_log("freq! %d\r\n", frequ);//miliseconds
                      DebugP_log("duty! %d\r\n", uk);//miliseconds
    }
    
    static void App_ecapIntrISR(void *handle)
    {
        volatile uint16_t status;
    
        status = ECAP_getInterruptSource(gEcapBaseAddr);
    
        if(status & ECAP_ISR_SOURCE_CAPTURE_EVENT_4)
        {
            // Get the capture counts. Each capture should be 4x the ePWM count
            // because of the ePWM clock divider.
            cap1Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_1);
            cap2Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_2);
            cap3Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_3);
            cap4Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_4);
    
    
    
            SemaphoreP_post(&gEcapSyncSemObject);
    
        }
    
        return;
    }
    
    

  • Compare please my implementation with yours. If smth wrong please text me.

  • If it's possible could you please also share your example

  • Hi Alex,

    Thanks for posting your code. I'll dig through it in more detail but at an initial glance nothing seems out of place compared to mine. 

    The code from my example is attached below, and originally started as ecap_capture_no_pwm_am263x-lp_r5fss0-0_nortos_ti-arm-clang

    /*
     *  Copyright (C) 2021 Texas Instruments Incorporated
     *
     *  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 <kernel/dpl/DebugP.h>
    #include <kernel/dpl/SemaphoreP.h>
    #include <kernel/dpl/HwiP.h>
    #include <drivers/epwm.h>
    #include "ti_drivers_config.h"
    #include "ti_drivers_open_close.h"
    #include "ti_board_open_close.h"
    
    /*
        This example configures ePWM9A 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 ePWM9A output.
    
         ecap1PassCount - Successful captures.
         ecap1IntCount - Interrupt counts.
    */
    
    /* Output frequency of the PWM wave (in Hz) */
    #define APP_ECAP_APWM_OUT_FREQ  (1000U)
    /* App run time (in seconds) */
    #define APP_ECAP_RUN_TIME  (10U)
    /* FIXME : To be removed after syscfg integration */
    #define APP_INT_IS_PULSE  (1U)
    
    /* Global variables and objects */
    static HwiP_Object  gEcapHwiObject;
    static SemaphoreP_Object  gEcapSyncSemObject;
    
    /* Function Prototypes */
    static void App_ecapIntrISR(void *handle);
    
    /* variable to hold base address of ECAP and EPWM that is used */
    uint32_t gEcapBaseAddr;
    uint32_t gEpwm9BaseAddr;
    
    //
    // 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 epwm9TimerDirection;
    uint16_t ecap_tick_time;
    volatile float cap2Count;
    volatile float cap3Count;
    volatile float cap4Count;
    volatile float frequencyArray;
    volatile float dutyCycleArray;
    
    void ecap_capture_pwm_main(void *args)
    {
        int32_t status;
        uint32_t numIsrCnt = 500;
        HwiP_Params hwiPrms;
    
        Drivers_open();
        Board_driversOpen();
    
        //
        // Initialize counters:
        //
        cap2Count = 0U;
        cap3Count = 0U;
        cap4Count = 0U;
        ecap1IntCount = 0U;
        ecap1PassCount = 0U;
    
        /* The ECAP gets SYSCLK
           1 tick time = 1/SYSCLK = 5 ns
        */
        ecap_tick_time = 5;
    
        DebugP_log("ECAP Capture Pwm Test Started ...\r\n");
    
         /* Get ECAP address */
        gEcapBaseAddr = CONFIG_ECAP0_BASE_ADDR;
    
        status = SemaphoreP_constructCounting(&gEcapSyncSemObject, 0, numIsrCnt);
        DebugP_assert(SystemP_SUCCESS == status);
    
        /* Register & enable interrupt */
        HwiP_Params_init(&hwiPrms);
        /* Integrate with Syscfg */
        hwiPrms.intNum      = CSLR_R5FSS0_CORE0_CONTROLSS_INTRXBAR0_OUT_22;
        hwiPrms.callback    = &App_ecapIntrISR;
        /* Integrate with Syscfg */
        hwiPrms.isPulse     = APP_INT_IS_PULSE;
        status              = HwiP_construct(&gEcapHwiObject, &hwiPrms);
        DebugP_assert(status == SystemP_SUCCESS);
    
    
        /* Wait for specified time */
        while(numIsrCnt > 0)
        {
            //
            // Clear interrupt flags for upcoming interrupts.
            //
            ECAP_clearInterrupt(gEcapBaseAddr, ECAP_ISR_SOURCE_CAPTURE_EVENT_4);
            ECAP_clearGlobalInterrupt(gEcapBaseAddr);
    
            //
            // Start eCAP
            //
            ECAP_reArm(gEcapBaseAddr);
    
            SemaphoreP_pend(&gEcapSyncSemObject, SystemP_WAIT_FOREVER);
            numIsrCnt--;
    
            DebugP_log("Calculated Frequency: %f\n",frequencyArray);
            DebugP_log("Calculated Duty Cycle: %f\n",dutyCycleArray);
        }
    
        DebugP_log("Interrupt No.: %u and Pass Count: %u\n",ecap1IntCount,ecap1PassCount);
    
        /* Stop ECAP Counter */
        ECAP_stopCounter(CONFIG_ECAP0_BASE_ADDR);
    
        /* Disable and clear interrupts */
        ECAP_disableInterrupt(gEcapBaseAddr, ECAP_ISR_SOURCE_ALL);
        ECAP_clearInterrupt(gEcapBaseAddr, ECAP_ISR_SOURCE_ALL);
        HwiP_destruct(&gEcapHwiObject);
        SemaphoreP_destruct(&gEcapSyncSemObject);
    
        DebugP_log("ECAP Capture Pwm Passed!!\r\n");
        DebugP_log("All tests have passed!!\r\n");
    
        Board_driversClose();
        Drivers_close();
    }
    
    static void App_ecapIntrISR(void *handle)
    {
        volatile uint16_t status;
    
        status = ECAP_getInterruptSource(gEcapBaseAddr);
    
        if(status & ECAP_ISR_SOURCE_CAPTURE_EVENT_4)
        {
            SemaphoreP_post(&gEcapSyncSemObject);
    
            //
            // Get the capture counts.
            //
            cap2Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_2);
            cap3Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_3);
            cap4Count = ECAP_getEventTimeStamp(gEcapBaseAddr, ECAP_EVENT_4);
    
            frequencyArray = (200000000 / (cap2Count + cap3Count) );
            dutyCycleArray = ( cap3Count / (cap2Count + cap3Count) ) * 100;
    
            ecap1IntCount++;
    
            //
            // Count correct captures
            //
            ecap1PassCount++;
        }
    
        return;
    }
    

    Best Regards,

    Ralph Jacobi

  • Hi Alex,

    As mentioned, I haven't been able to get a FreeRTOS equivalent of this working with the periodic task. If you could help provide the FreeRTOS configurations specifically for the periodic task creation and plugging the ECAP task into FreeRTOS, that would go a long way for me to implement the same and test.

    Best Regards,

    Ralph Jacobi