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.

CCS/TMS320F28335: How to configure the ECAP register to realize the function: detect the rising edge and the falling edge when capturing a 50HZ pwm with a 50% duty?

Part Number: TMS320F28335

Tool/software: Code Composer Studio

Hi,

Actually, I need to detect the grid voltage when it passes through the zero point(if it is from negative to positive, output a high level; if it is from positive to negative, output a low level.).

so, I write a test program to verify this function. I use EPwm1A to generate a 50HZ pwm with a 50% duty. Then the ECap1 will capture this pwm. If ECap capture the rising edge, force the EPwm1B to output a high level; if the falling edge, force the EPwm1B to output a low level. The ideal result is that I will detect a Synchronous 50Hz pwm with a 50% duty in pin GPIO1(EPwm1B) by an Oscilloscope.

However, I came across some problems after the dsp run. I didn't see the ideal result. 

At first, the GPIO1 didn't output a pwm. It output either high or low. Then I changed some configuration. The GPIO1 output a 25Hz pwm with a 50% duty.

And I compared the output EPwm1B with the input EPwm1A. I found the output of EPwm1B didn't change at the rising or falling edge of EPwm1A.  It changed at the mid point of the high level or low level of EPwm1A. It seems that ECap1 didn't capture the rising edge or falling edge.

I know there must be some wrong configurations with my ECap1 module. the following is my configuration code:

void SetCap1Mode(void)
{
ECap1Regs.ECEINT.all  = 0x0000; // disable all interrupts
ECap1Regs.ECCLR.all   = 0xFFFF; // clear all flag

ECap1Regs.ECCTL1.bit.CAP1POL     = EC_RISING; // rising edge
ECap1Regs.ECCTL1.bit.CAP1POL     = EC_FALLING; // falling edge
ECap1Regs.ECCTL1.bit.CAPLDEN    = EC_DISABLE; // disable CAP1-CAP4 register loads
ECap1Regs.ECCTL1.bit.PRESCALE  = EC_DIV1; // input / 1

ECap1Regs.ECCTL2.bit.CAP_APWM         = EC_CAP_MODE; // work at cap mode
ECap1Regs.ECCTL2.bit.CONT_ONESHT  = EC_ONESHOT; // work at one-shot mode
ECap1Regs.ECCTL2.bit.SYNCO_SEL        = EC_SYNCO_DIS; // Disable sync out signal
ECap1Regs.ECCTL2.bit.SYNCI_EN            = EC_DISABLE; // Disable sync in
ECap1Regs.ECCTL2.bit.TSCTRSTOP        = EC_FREEZE; // stop the counter when not used
ECap1Regs.ECCTL2.bit.STOP_WRAP       = EC_EVENT2; // stop at event 2
ECap1Regs.ECCTL2.bit.REARM                 = EC_ARM; // arm one-shot

ECap1Regs.ECEINT.bit.CEVT1 = 1;
ECap1Regs.ECEINT.bit.CEVT2 = 1;

}

interrupt void ISRCap1(void)
{
if( ( ECap1Regs.ECFLG.bit.CEVT1 == 1 )&&(EPwm1Regs.AQCSFRC.bit.CSFB == 1 ) )
{
capcount1++;
LED1 = ~LED1;
EPwm1Regs.AQCSFRC.bit.CSFB = 2;

ECap1Regs.ECCLR.bit.CEVT1 = 1; // clear the flag for event 1
ECap1Regs.ECCLR.bit.CEVT2 = 1;
ECap1Regs.ECEINT.bit.CEVT1 = 0;
ECap1Regs.ECEINT.bit.CEVT2 = 1;
}

if( ( ECap1Regs.ECFLG.bit.CEVT2 == 1 )&&( EPwm1Regs.AQCSFRC.bit.CSFB == 2 ) )
{
capcount2++;
LED2 = ~LED2;
EPwm1Regs.AQCSFRC.bit.CSFB = 1;

ECap1Regs.ECCLR.bit.CEVT1 = 1;
ECap1Regs.ECCLR.bit.CEVT2 = 1; // clear the flag for event 2
ECap1Regs.ECEINT.bit.CEVT1 = 1;
ECap1Regs.ECEINT.bit.CEVT2 = 0;
}

ECap1Regs.ECCLR.bit.INT = 1; // clear the global interrupt flag;
ECap1Regs.ECCTL2.bit.REARM = EC_ARM; // acknowledge next interrupt
PieCtrlRegs.PIEACK.all = PIEACK_GROUP4;
}

I look up the registers, it indicates that every time when it goes into the interrupt, the ECap1Regs.ECFLG.bit.CEVT1 and ECap1Regs.ECFLG.bit.CEVT2 will both chaned to 1, I guess the configuration

ECap1Regs.ECCTL2.bit.STOP_WRAP       = EC_EVENT2; // stop at event 2

might be the cause. but if this bit is set at EC_EVENT1, it can't detect the falling edge,right?

So I wonder if there any solutions to solve this problem, better not use the interrupt.

Thank you.

Regards,

  • sorry, the code

    ECap1Regs.ECCTL1.bit.CAP1POL     = EC_RISING; // rising edge
    ECap1Regs.ECCTL1.bit.CAP1POL     = EC_FALLING; // falling edge

    is 

    ECap1Regs.ECCTL1.bit.CAP1POL     = EC_RISING; // rising edge
    ECap1Regs.ECCTL1.bit.CAP2POL     = EC_FALLING; // falling edge

  • Serenity_pjb,

    The eCAP was not intended to be used in this manner, but I think you could get this to work with a reasonable software delay. It looks like you have configured one-shot mode, for this purpose I would suggest continuous mode. One-shot mode is really so that you can capture a fast signal and process the result several cycles later. It sounds like you would like to trip reliably every cycle.

    If you would like to continue using the eCAP interrupt I would suggest added a GPIO toggle to the eCAP interrupt and observe this output on an oscilloscope. This should point out if its correctly tripping when you expect. It should not be delayed unless another interrupt has priority.

    Are you already using the Trip Zone submodule (TZ) for something else? It sounds like the TZ may work better for this purpose. Please know that you would still need to synchronize the PWM's period, because the trips would be cycle-by-cycle or one-shot. The TZ will be able to force high or force low, not both. You could use the action qualifier to force the signal high at the beginning at the PWM period and then use the TZ to force it low when you receive the zero crossing signal.

    Unfortunately the PWM is not setup to be a signal follower as you have described above. 

    Regards,
    Cody 

  • thanks for your reply, Cody,

    Cody Watkins said:

    The eCAP was not intended to be used in this manner

    but I have found someone else to use ECap to lock phase with grid. and you said

    Cody Watkins said:

    One-shot mode is really so that you can capture a fast signal and process the result several cycles later.

    you mean when working at  one-shot mode, the ECap captures an edge signal then the dsp needs to several cycles to process something. Is this cycle the system's cycle? If so, even 10 cycles costs only 10/150000000s. but the edge signal comes every 0.01s.

    I didn't use the TZ module, for the action qualifier has the control bit to force high or low.

    And yesterday, I tried another idea(I suppose one-shot mode can be used in this manner.).

    At first, I configured CAP1POL = RISING_EDGE. when interrupt is triggered, configured the CAP1POL to FALLING_EDGE. The next time interrupt is triggered, change back to RISING_EDGE, and this will be cycled.

    void SetCap1Mode(void)
    {
        ECap1Regs.ECEINT.all = 0x0000;                 // disable all interrupts
        ECap1Regs.ECCLR.all = 0xFFFF;                  // clear all flag

        ECap1Regs.ECCTL1.bit.CAP1POL = EC_RISING;        // rising edge
        ECap1Regs.ECCTL1.bit.CAPLDEN  = EC_DISABLE;   // disable CAP1-CAP4 register loads
        ECap1Regs.ECCTL1.bit.PRESCALE = EC_DIV1;          // input / 1

        ECap1Regs.ECCTL2.bit.CAP_APWM      = EC_CAP_MODE;      // work at cap mode
        ECap1Regs.ECCTL2.bit.CONT_ONESHT = EC_ONESHOT;     // work at one-shot mode
        ECap1Regs.ECCTL2.bit.SYNCO_SEL   = EC_SYNCO_DIS;     // Disable sync out signal
        ECap1Regs.ECCTL2.bit.SYNCI_EN    = EC_DISABLE;              // Disable sync in
        ECap1Regs.ECCTL2.bit.TSCTRSTOP   = EC_FREEZE;            // stop the counter when not used
        ECap1Regs.ECCTL2.bit.STOP_WRAP   = EC_EVENT1;           // stop at event 1
        ECap1Regs.ECCTL2.bit.REARM       = EC_ARM;                         // arm one-shot

        ECap1Regs.ECEINT.bit.CEVT1 = 1;


    }

    interrupt void ISRCap1(void)
    {
        if( ( ECap1Regs.ECFLG.bit.CEVT1 == 1 )&&( ECap1Regs.ECCTL1.bit.CAP1POL == EC_RISING ) )
        {
            capcount1++;
            LED1 = ~LED1;
            EPwm1Regs.AQCSFRC.bit.CSFB = 2;

            ECap1Regs.ECCLR.bit.CEVT1  = 1;            // clear the flag for event 1
            ECap1Regs.ECCTL1.bit.CAP1POL = EC_FALLING;
        }

        if( ( ECap1Regs.ECFLG.bit.CEVT1 == 1 )&&( ECap1Regs.ECCTL1.bit.CAP1POL == EC_FALLING ) )
        {
            capcount2++;
            LED2 = ~LED2;

            EPwm1Regs.AQCSFRC.bit.CSFB = 1;

            ECap1Regs.ECCLR.bit.CEVT1  = 1;            // clear the flag for event 1
            ECap1Regs.ECCTL1.bit.CAP1POL = EC_RISING;
        }

        ECap1Regs.ECCLR.bit.INT    = 1;            // clear the global interrupt flag;
        ECap1Regs.ECCTL2.bit.REARM = EC_ARM;    // acknowledge next edge detect
        PieCtrlRegs.PIEACK.all     = PIEACK_GROUP4;

    }

    I tested it in the debug mode with a breakpoint at the first line of interrupt function. Then I run step by step, watching the corresponding register bit at the same time. The logic is right. But when the DSP run with no breakpoints, EPwm1B keeps outputing high level.

    Regards,

    Serenity_pjb

  • Serenity,

    I do think that this will work, but we did not plan on someone using the device in this way so you will not find many hardware implementations which make this easier. You will need to use software intervention as you have done.

    Serenity_pjb said:
    Cody Watkins

    The eCAP was not intended to be used in this manner

    but I have found someone else to use ECap to lock phase with grid.

    I don't believe one-shot mode is required for this system. But it is fine to use, I don't see any potential issues with this.

    Are any other PWM sub-modules that are setup? It is possible that they are influencing the output.


    Regards,
    Cody 

  • Hi, Cody,

    Finally, I solved this problem. And I think your guess that the PWM sub-module will influence the output is right.

    Because in the previous code, I used the PWM register AQCSFRC to force outputing high or low(EPwm1B).

    Yesterday, I configured the pin of EPwm1B as a GPIO. Then toggle the output level when edge event comes.

    after dsp run, the GPIO1 output a 50Hz pwm almost sychronous to the input.

    But I don't know why the AQCSFRC register can not realize this function

    I just changed the code

    EPwm1Regs.AQCSFRC.bit.CSFB = 2;

    EPwm1Regs.AQCSFRC.bit.CSFB = 1;

    to

    GpioDataRegs.GPASET.bit.GPIO1 = 1;

    GpioDataRegs.GPACLEAR.bit.GPIO1 = 1;

    of course, I configured the corresponding pin as a GPIO.

    Maybe I need to understand more configuration about the PWM modules in the datasheet.

    Whatever, thanks for your reply.

    regards,

    Serenity_pjb

  • Serenity_pjb,

    the GPIO mux selects different functions, if a PWM is configured then the GPIO's output will be blocked. If the GPIO is configured then the PWM's output is blocked.

    Glad you got it solved. Additionally, being that this requires so much software intervention the best way to do this is probably a GPIO, as you have done.

    Regards,
    Cody