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.

PWM 'glitch' using TIMER0_A0 on MSP430G2553

Other Parts Discussed in Thread: MSP430G2553

Hello,

I'm trying to make a pulsing LED using the PWM feature of the msp430g2553. I am using up-mode with reset/set output mode. I use the TA0CCR0 CCIFG (TIMER0_A0_VECTOR interrupt) to change the TA0CCR1 value (giving the changing duty cycle). There are some #defines I made up for my own convenience so if a few things look strange I'm sorry for the confusion.


I am noticing the 'glitch' when the TA0CCR1 is being decremented. As the duty cycle is decreased I get a 'glitch' pulse that is larger than a 100% cycle pulse. I change my macros for period and step size and the glitch always appears as the TA0CCR1 is being decremented right before the TA0CCR1 value reaches 0. The glitch isn't present with all values of period and step sizes (my macros) but when it is present it is consistent. I can't figure out why. Any help will be greatly appreciated. Thanks :)

changing TA0CTL input divider from ID_2 to ID_1 the glitch travels further away from the TA0CCR1 = 0 value.

#include <msp430g2553.h>

#define PERIOD         128
#define HALF_PERIOD 64
#define STEP         8
#define SMALL_STEP     1

void GPIO_init(void);
void BCS_init(void);
void TIMER0_A0_init(void);

void main(void)
{
    WDTCTL = WDTPW + WDTHOLD;

    GPIO_init();
    BCS_init();
    TIMER0_A0_init();

    __bis_SR_register(GIE);
    LPM3;
}

void GPIO_init(void)
{
    P1OUT = 0x07;                // P1.0 = TA0CCR1++, P1.1 = TA0CCR1--, P1.3 = pulsing
    P1SEL = 0x40;
    P1DIR = 0xF8;
    P1REN = 0x07;
    P1IES = 0x07;
    P1IFG = 0x00;
    P1IE  = 0x07;

    P2OUT = 0x00;
    P2SEL = 0xC0;
    P2DIR = 0xBF;
    P2REN = 0x00;
    P2IES = 0x00;
    P2IFG = 0x00;
    P2IE  = 0x00;
}

void BCS_init(void)
{
    do
    {    // waiting for cyrstal to warm up
        IFG1 &= ~OFIFG;
        __delay_cycles(50);
    } while (IFG1 & OFIFG);
    IE1 |= OFIE;

    BCSCTL1 |= XT2OFF + DIVA_0;
    BCSCTL2 = SELM_2 + DIVM_0 + SELS_1 + DIVS_0;
    BCSCTL3 = XT2S_0 + LFXT1S_0 + XCAP_3;
}


void TIMER0_A0_init(void)
{
    //         up mode
    TA0CTL = TASSEL_1 + ID_2 + MC_1 + TACLR + TAID;    // TAID = timer a interrupt disabled (0x0000)

    //        reset @ TA0CCR1, set @ TA0CCR0
    TA0CCTL1 = CM_0 + COM + OUTMOD_7;         // COM = compare (0x0000)

    TA0CCR0 = PERIOD;
    TA0CCR1 = HALF_PERIOD;
}

#pragma vector = PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
    switch (P1IFG)
    {
        case BIT0:    if (TA0CCR1 == PERIOD)            // TA0CCR1++
                                 TA0CCR1 = 0;
                             else
                                 TA0CCR1 += STEP;
                             P1IFG &= ~BIT0;
                             break;

        case BIT1:    if (TA0CCR1 == 0)                // TA0CCR1--
                                 TA0CCR1 = PERIOD;
                             else
                                 TA0CCR1 -= STEP;
                             P1IFG &= ~BIT1;
                             break;

        case BIT2:    TA0CCR1 = HALF_PERIOD;
                             TA0CCTL0 |= CCIE;
                             P1IFG &= ~BIT2;
                             break;

        default:    __never_executed();
    }
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void TIMER0_A0_ISR(void)
{
    TA0CCR1 -= SMALL_STEP;
    if (TA0CCR1 == 0)
        TA0CCR1 = PERIOD;
}



  • I will only briefly look at the code when you don't use:

    As Timer A can not buffer-and-latch values like Timer B can, I'm pretty sure it looks like you are not able to change the values in time.

  • I'm sorry you had a difficult time understanding code that wasn't formatted. I didn't know code formatting was possible and I updated the code with the code formatter button. Thanks for letting me know how to format it. I hope you are able to understand it now.
  • With TimerA, don't change CCR1 values close to either end of a duty ( >90% or <10%) as ISR can not get it done in time.
    With a LED I would use 0% to 80% duty (80%= nearly fully on) and change the value at the CCR1 IRQ as you are always subtracting it so there will not be a chance that you re-trigger it.

  • I thought the ISR could not change the value of CCR1 in time as well but as the oscilloscope screenshot shows the glitch doesn't happen at the smallest increment, it happens before the smallest increment. The glitch doesn't happen at 2nd smallest and smallest increment it only happens at second smallest. The smallest increment doesn't display a glitch.

    Also when I change TA0CTL input divider from ID_2 to ID_1 the glitch happens 5th from CCR1 hitting 0 and only then. (working on adding screen shot of o-scope)
  • So you are using 32K-crystal /4 for timerA0, so each tick takes 122µS

    Test example:
    CCR1=3
    The TIMER0_A0 IRQ happens at 128 (pin goes high), within ~10µS CCR1 is set to 2
    366µS later CCR1 hits and pin goes low

    CCR1=2
    The TIMER0_A0 IRQ happens at 128 (pin goes high), within ~10µS CCR1 is set to 1
    244µS later CCR1 hits and pin goes low

    CCR1=1
    The TIMER0_A0 IRQ happens at 128 (pin goes high), within ~10µS CCR1 is set to 0
    after another ~10µS CCR1 is reset to 128 (so zero is never used by CCR1)
    15738µS later CCR1 hits and pin goes low but at the same time as CCR0 hits and try to set pin high (who wins?)

    Or what happing is that the ISR pulls the rug underneath the CCR1 before it actually sees 128?,
    e.g at 128.1 the ISR changed CCR1 from 128 to 127.

    So try to change the last line to: TA0CCR1 = PERIOD-1;

  • unfortunately, setting TA0CCR1=PERIOD-1 doesn't fix the problem.

    as far as your test example the glitch isn't happening @CCR1=1 or @CCR1=0 or @CCR1=128 or CCR1=127.

    The glitch happens (see first oscilloscope screenshot: CLK/4) @CCR1~2
    The glitch happens (see second oscilloscope screenshot: CLK/2) @CCR1~5
    @CCR1=1, @CCR1=0, @CCR1=128, @CCR1=127 the waveform is as expected.
  • John Ruiz said:
    The glitch happens (see first oscilloscope screenshot: CLK/4) @CCR1~2
    The glitch happens (see second oscilloscope screenshot: CLK/2) @CCR1~5

    (1) Are they reproducible? (With no changes in you code.)

    (2) What happens if you change your Timer ISR and made it slower?

    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void TIMER0_A0_ISR(void)
    {
        __delay_cycles(20); //or more than 20
        TA0CCR1 -= SMALL_STEP;
        if (TA0CCR1 == 0)
            TA0CCR1 = PERIOD;
    }

  • Hello,

    I greatly appreciate all the help I can get :)

    1) I copied the code from this post into a new project and the glitch is still present (see attached oscilloscope screenshot)

    2) I applied the 20us delay but unfortunately the glitch did not disappear. The glitch only moved further from the CCR1 = 0 point (CCR1~7) as shown in the screenshot below.

  • Delay 20 cycles is just a test, not meant to cure the glitch.

    Here is a suggestion to hide the glitch.
    (a) Initialize TACCR2=0; use that to generate interrupt; do not use TACCR0 to generate interrupt.
    (b) The ISR decrements both TACCR1 and TACCR2 the same way.
  • I can use TA0CCR1 or TA0CCR2 to generate the capture/compare interrupt and the glitch no longer appears but I posted this thread to try to understand why TA0CCR0 capture/compare interrupt doesn't work. Using TA0CCR1 OR TA0CCR2 to generate the interrupt avoids the glitch but doesn't explain it.

    It took me a lot longer to figure out how to avoid the TA0CCR0 glitch then it took you and I thank you for your time and I understand if you no longer have an interest in this problem but if you can I'd appreciate any extra advice on the CCR0 glitch.

    If you would rather not spend time on the CCR0 glitch, I'll verify your answer.
  • John,

    I do not know the reason for the problem either. I was trying to evade the problem by working around it.

    It is good that you want to get to the bottom of the problem. I will try to help you.

    First, I cannot quite read the width of the pulses of your scope picture. Could you use higher horizontal resolution and show the area of interest (the red box below) so that we can see the width of the pulses (between the red arrows) down to 1, 2, 3 timer clock counts wide?

    Next, I suggest a small addition to your code to Toggle P1.5 at CCR0. Put that on another scope probe and show it together with the one you already have.

    I also suggest that you disable P1 interrupts and remove the corresponding ISR. I think they are not related to your current puzzle

    -- OCY.

**Attention** This is a public forum