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 giving jittery signal

Other Parts Discussed in Thread: MSP430G2553

I am using the M430G2553 chip and trying to do a PWM program to control a servo.  I have the script running and it works good except I can see on my scope that every few seconds I get a signal that is at full voltage for the duration of the idle time.  It only happens very suddenly and at random and only for 1 signal duration.  This is causing my servo to jitter.  I have isolated it to the program because when the pot is fully turned to the 10k resistance (the ADC10MEM reads 0x03FF) there is no jitter at all.  When I move anything lower than this the jitteryness happens.  I think it has something to do with the ACD10MEM having problems because when I remove this and hard code a value in it's place, everything works fine.  If I put a 1k resistor in place of the pot it still jitters so it does not have anything to do with a bad pot.  Do you know why this is happening?  Code is below:

 

#include "msp430g2553.h" // make sure you change the header to suit your particular device.

/*  

* Vcc To POT  

* P1.1 From POT  

* P1.2 To Servo  

*/

#define MCU_CLOCK   1000000

#define PWM_FREQUENCY  46  // In Hertz, ideally 50Hz.

unsigned int PWM_Period  = (MCU_CLOCK / PWM_FREQUENCY); // PWM Period

void main(void) {  

WDTCTL = WDTPW + WDTHOLD; // Stop WDT

P1DIR |= 0x0C; // P1.2 and P1.3 output  

P1SEL |= 0x0C; // P1.2 and P1.3 TA1/2 options

TACCTL1 = OUTMOD_7;            // TACCR1 reset/set  

TACTL = TASSEL_2 + MC_1;     // SMCLK, upmode - SETUPS TIMER  

TACCR0 = PWM_Period-1;        // PWM Period - NUMBER TO COUNT TO

 //ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled  

ADC10CTL0 = SREF0 + ADC10SHT_2 + ADC10ON + REFON + REF2_5V + ADC10SR;

ADC10CTL1 = INCH_1; // input A1  ADC10AE0 |= 0x02; // PA.1 ADC option select

 for (;;){

  ADC10CTL0 |= ENC + ADC10SC;

  while (ADC10CTL1 & ADC10BUSY);

  TACCR1 = ADC10MEM;

 }

}

  • You only posted part of your code. The part that causes the problem is not posted. But I think I know what you did and why that causes the PWM to misbehave occasionally.

    1. You set up TAR to count from 0 to 21739-1, back to 0, and repeat automatically.

    2. You set up TACCR1 to a certain percentage of 21739.

    3. You set up P1.2 to go high when TAR changes to 0, and to go low when TAR counts to become equal to TACCR1.

    4. When there is a new reading of the pot, you re-calculate the percentage and reload TACCR1 with that new percentage.

    This normally works. There are 21739 counts from 0 to 21739-1. Thus the period is always 21739 counts. P1.2 is high from 0 to TACCR1 during that period. Thus, it is high for the desired percentage of a period. If TACCR1 has a different value, a different percentage results. However, when you change TACCR1, the pulse width of that particular period may not be correct.

    For example:

    TACCR1 was 10869, the pulse width was about 50% of a period.

    You want to reduce it to 40%, thus you want TACCR1 = 8695 instead.

    Now, when you make that change, if TAR happens to be about 9000, you will see a single long pulse of 140%. After that, it will be 40% as desired.

    This is because at TAR = 9000, P1.2 is already high. The old TACCR1 did not turn it low. The new TACCR1 cannot turn it low either during the rest of this current period. (TAR has already passed that opportunity.)

  • Thanks for your help.  I am new to this so much of what you said went over my head.  Just to let you know, that is my entire code set that was posted.  It is a combination of a code example for a PWM that had fix intervals when the PWM would change and a code example using the ACD10 for measuring a POT.  If you can help me with this code by explicitly saying what needs to change, that would be great.  Also, explain why it is not working as it is.

     

    Thanks

    Chris

  • #include "msp430g2553.h" // make sure you change the header to suit your particular device.

    /*  

    * Vcc To POT  

    * P1.1 From POT  

    * P1.2 To Servo  

    */

    #define MCU_CLOCK   1000000

    #define PWM_FREQUENCY  46  // In Hertz, ideally 50Hz.

    unsigned int PWM_Period  = (MCU_CLOCK / PWM_FREQUENCY); // PWM Period

    void main(void) {  

    WDTCTL = WDTPW + WDTHOLD; // Stop WDT

    P1DIR |= 0x0C; // P1.2 and P1.3 output  

    P1SEL |= 0x0C; // P1.2 and P1.3 TA1/2 options

    TACCTL1 = OUTMOD_7;            // TACCR1 reset/set  

    TACTL = TASSEL_2 + MC_1;     // SMCLK, upmode - SETUPS TIMER  

    TACCR0 = PWM_Period-1;        // PWM Period - NUMBER TO COUNT TO

     //ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE; // ADC10ON, interrupt enabled  

    ADC10CTL0 = SREF0 + ADC10SHT_2 + ADC10ON + REFON + REF2_5V + ADC10SR;

    ADC10CTL1 = INCH_1; // input A1  ADC10AE0 |= 0x02; // PA.1 ADC option select

     for (;;){

     while ((TAR < 1024) || (TAR > 20000)) { /* a kluge */ }

      ADC10CTL0 |= ENC + ADC10SC;

      while (ADC10CTL1 & ADC10BUSY);

      TACCR1 = ADC10MEM;

     }

    }

     

  • Christopher Sonnenburg said:
    I am new to this so much of what you said went over my head.


    The PWM changes its output twice,. Once at timer overrun, once at the set trigger point. This is what results in the duty cycle.

    Now let's look at the trigger point. Assume it is your wakeup alarm. You set the alarm time before you go to bed and it will wake you at the set time.This usually works.

    But what if you go to bed at 6AM (it was a long night) and you want to wake up at 5AM? If you set the alarm to 5AM, you'll sleep until next day.

    That's what happens to the PWM too. If the timer is at, say 5000. And previous PWM trigger was at 6000. Now you change it to 4000. Then it won't be triggered at 6000 anymore (you already changed to 4000). Instead it will run to maximum (one 100% DC cycle) and trigger at 4000 on the next cycle. That's what you experience.

    TimerB has an option to synchronize the update of the CCRx register with the timer overrun. So this won't happen. But on TimerA, you must ensure that you won't change the trigger point to something less than the current timer count.
    Just like you should not set your alarm to a time that has already passed.

**Attention** This is a public forum