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.

problem with pwm and timer



i have a problem with pwm's.i am using timer A and the total period is 80 and on times  are 5%, 75% and 50%. i want to generate 3 different PWM's for same application.

 

Hold Watchdog
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

// Configure DCO to oscillate at 8MHz
 
  BCSCTL1 = CALBC1_8MHZ;                    // Set DCO to 8MHz
  DCOCTL = CALDCO_8MHZ;



// Configure Timer A for generating PWM with initialization values.
  TA0CCR0 = 8*PWM_PERIOD_uS;                  // PWM Period
  TA0CCTL1 = OUTMOD_7;                        // TA0CCR1 reset/set
  TA0CCR1 = 1*PWM_INIT_ON_TIME_uS;            // TA0CCR1 PWM duty cycle (Pin 23 i.e P1.2)
  TA0CTL = TASSEL_2 + MC_1;                   // SMCLK, up mode
  P1DIR|=0x0E;
  P1SEL|=0x0C;

 

For 50% iam usig this
  TA0CCR1 = 8*PWM_INIT_ON_TIME_uS;  ;            // TA0CCR1 PWM duty cycle 50%
 BATTERY_CV_LIMIT=EQUILIZATIONBATTERYVOLTAGE;

For 75% iam usig this

  TA0CCR1 =12 *PWM_INIT_ON_TIME_uS;  ;            // TA0CCR1 PWM duty cycle 50%
 BATTERY_CV_LIMIT=EQUILIZATIONBATTERYVOLTAGE;
 incremntal_conductance();

For 5% iam using this

  TA0CCR1 = 1*PWM_INIT_ON_TIME_uS;  ;            // TA0CCR1 PWM duty cycle 50%
 BATTERY_CV_LIMIT=EQUILIZATIONBATTERYVOLTAGE;

 

some times its happenning and some times its not hapening.give me some idea for this.is there any problem with oscillator selection or CCR1.

  • Unfortunately, you use lots of defined fvalues without providing the values itself. This might hide some problems.
    Also, you didn't post the MSP you're using, so I couldn't check the port settings at all (as they may vary for each device).

    e.g. since all registers are 16 bit, the maximum for the PWM_PERIOD_µS is 8192µs.
    It would be better ti use the /8 divider for the timer input clock and work with one tick per µs. It also saves some time for the multiplications (If later done at runtime, currently the compiler just precalculates the values).
    TA0CTL = TASSEL_2|IDX_4|MC_1;
    However, with only 10µs PWM cycle time, this is not necessary and would rathe rlimit the resolution.

    TA0CCR1 needs to be 1 less than the calculated value, since '0' counts also as a timer tick.

    What is PWM_INIT_ON_TIME_µS meant to be? The ON time in µs? Then with your current code the settings are nonsense. Wither you calculate the ON time based on the PWM_PERIOD and the duty cycle, or you give it in µs.

    In first case, for 75% it should be 6*PWM_PERIOD_µs, 4*PWM_PERIOD_µs for 50% and (2*PWM_PERIOD_µs/)/5 for 5% (which is terrible because of the division, if calculated at runtime.)

    In the second case, if it is indeed the ON time, it is the ON time in µs (and no duty cycle), and it should have been multiplied by 8 to result in an ON time in µs (well, this setup doesn't make much sense)

    For the given period of 80 ticks (of 1/8 µs each), the settings would be 60, 40 and 4. And it should work.

    BATTERY_CV_LIMIT and such doesn't seem to have anything to do with the problem.

  • I am using MSP4302132.

    There is no problem with all defined values.

    Actually the total time period is 80( PWM_PERIOD_uS*10), this i have given in the CCR0 register and in CCR1 register the duty cycle changes to charge the battery.

     PWM_INIT_ON_TIME_uS            5     // Initial ON time of PWM output
     PWM_PERIOD_uS                 10     // PWM signal period

     i am not dividing the clock and i have given 8MHz (Configured DCO to oscillate at 8MHz)

     

     

  • rams rd said:
    PWM_INIT_ON_TIME_uS            5

    Okay, so 1*PWM_INIT_ON_TIME_µs is 6.25% duty cycle and 0.625ms, so both won't fit the naming.

    Anywa, it should work except for one thing: if you change the duty cycle, you may have one erroneous cycle of 100%. Thsi is when you reduce the duty cycle. E.g. if you have it set to 75% and then go back to 50%, this might happen while the tiemr is already past the 50% mark. Since you then have CCRx not set to 75% anymore, the current cycles 'on' time externs to the full length of a cycle and then further to 50%, giving you a '150%' cycle.

    I don't see anything else. Perhaps if you describe more detailed what you expect to see and what you do see... Timing diagram or scope screenshot would be best.

  • my first question is can i use same ccp1 register to generate 3 different PWMs

    if yes then in my code iam using 3 different PWMs to charge battery for different modes(float,equlization and bulk)

     second if i dont use these three PWMs, the initial one where i have initialized timerA0, i have used a initial time for CCR1(1*PWM_INIT_ON_TIME_µs)

    // Configure Timer A for generating PWM with initialization values.
      TA0CCR0 = 8*PWM_PERIOD_uS;                  // PWM Period
      TA0CCTL1 = OUTMOD_7;                        // TA0CCR1 reset/set
      TA0CCR1 = 1*PWM_INIT_ON_TIME_uS;            // TA0CCR1 PWM duty cycle (Pin 23 i.e P1.2)
      TA0CTL = TASSEL_2 + MC_1;                   // SMCLK, up mode
      P1DIR|=0x0E;
      P1SEL|=0x0C;
    is this creating a problem.

    i am not able to see different PWMs .

     

  • With this setup, you should get a cycle time of 81 (!)  timer ticks. The value written to CCR0 shoudl be 1 less that the number of ticks, since 0 is also a tick.
    When TAR hits CCR0, next tick (!) it rolls over to zero. and sets TA0.1.
    PWM_INIT_ON_TIME_µS ticks later,  TA0.1 will be reset to zero. Looks fine so far.

    You don't set an OUTMODE to TA0CCTL0. Using OUTMOD_3 on it will generate a one-tick-long spike on TA0.0 every cycle. Using OUTMOD_4 will result in a square wave 50% duty-cycle signal with half the PWM frequency on TA0.0. To see the output, setting BIT1 in P1SEL is necessary too.

    When you write something else to TA0CCR1, the duty cycle on TA0.1 will change. TA0.0 will not change unless you change the PWM frequency by writing to CCR0.

    Do you actually use TA0CCR2? You activate the TA0.2 output pin, but don't program CCR2.

     

  • thank for ur suggestion..i will see that the CCR0 register is PWM-1.

    but the PWM total period should be same throughout  no.why have u said "When you write something else to TA0CCR1, the duty cycle on TA0.1 will change. TA0.0 will not change unless you change the PWM frequency by writing to CCR0."

    i want different duty cycles so ,change the values in CCR1  register is enough?

    but when i put only one duty cycle fixed it is working and i can see the PWM. But when i vary the PWM(duty cycles) the code is not responding accordingly.

    OUTMODE7 is set/reset is there any problem with that in getting output.i will try that also.

  • I was suggesting checking the duty cycle on P1.1 (TA0.0).

    rams rd said:
    i want different duty cycles so ,change the values in CCR1  register is enough?

    Yes, it should.

    rams rd said:
    but when i put only one duty cycle fixed it is working and i can see the PWM

    fine.

    rams rd said:
    OUTMODE7 is set/reset is there any problem with that in getting output.i will try that also.

    No, it's fine.

    rams rd said:
    But when i vary the PWM(duty cycles) the code is not responding accordingly.

    So one thing remains. How do you vary them. I don't mean 'by writing to CCR1" but rather how often, how fast, at which point.

    Changing the duty cycle must be precisely timed. You cannot change i reliably more often that once per PWM cycle. And when you do it a tthe wrong moment, you'll end up with a 100+x% cycle before the next settles.
    Imagine how the thing works: it set s a trigger point along the way of TAR. If you move the trigger point, TAR may have already passed it. It's okay if you move it up. THen it will trigger a secodn time, but in the set/reset mode, it will be a second reset and do nothing (a toggle mode, however, would affect the signal).

    But when you move the trigger down, TAR may have already passed the new trigger point but not the old, so on this cycle, the reset is never triggered, getting you one complete 100% cycle plus imediately following the new duty cycle, resulting in a 100%+x pulse.

    if you change the trigger points more often than once per 2 complete cycles, it may happen that any thinkable signal is generated. Or you need to synchronize it with the last trigger, so you always change ofter the trigger has occurred, but before the new cycle starts (probably the best way, but also th emost complex, as it requires ISR programming)

  • this change in pwm depends on battery voltage.

    there r 3 thresholds of battery voltages when one is crossed i am changing PWM signal,if it reaches another one i am changing PWM signal to another value....and so on....

    when i am changing the PWM value and it should go to another loop there comes the problem .it is not going to another loop

  • this change in pwm depends on battery voltage.

    there r 3 thresholds of battery voltages when one is crossed i am changing PWM signal,if it reaches another one i am changing PWM signal to another value....and so on....

    when i am changing the PWM value and it should go to another loop there comes the problem .it is not going to another loop

  • rams rd said:
    when i am changing the PWM value and it should go to another loop there comes the problem .it is not going to another loop

    Strange. I think there must be a glitch in your code.

    You shoudl post it. All of it, if possible (if you don't want to put it here, send me a private message)

    I cannot, however, promise to work on it soon. The larger the code, the higher the chance that I cannot handle it in the short breaks I have when the compiler runs and I have nothing to do.

  • #define BOOSTBATTERYVOLTAGE     (144/10) // counts for 14.8 Volts
    #define EQUILIZATIONBATTERYVOLTAGE (138/10)
    #define FLOATBATTERYVOLTAGE (136/10)

    //#define BATTERY_CONSTANT 203    // Counts per volts

    #define BATTERY_CV_LIMIT                         ((BATTERY_CONSTANT*136)/10) // counts

     

    // Hold Watchdog
      WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

    // Configure DCO to oscillate at 8MHz
     
      BCSCTL1 = CALBC1_8MHZ;                    // Set DCO to 8MHz
      DCOCTL = CALDCO_8MHZ;

    // Configure ADC
    //ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
      ADC10CTL0 = SREF_1+MSC+ REFON+ REF2_5V + ADC10ON + ADC10IE +REFOUT; // ADC10ON, interrupt enabled
      ADC10CTL1 = INCH_3 + CONSEQ_1 +ADC10SSEL_0;
      ADC10AE0 |= 0x0F;                           // P2.0 ADC option select
      ADC10DTC1 = 0x04;                           // 4 conversions

    // Configure Timer A for generating PWM with initialization values.
      TA0CCR0 = 8*PWM_PERIOD_uS;                  // PWM Period
      TA0CCTL1 = OUTMOD_7;                        // TA0CCR1 reset/set
      TA0CCR1 = 1*PWM_INIT_ON_TIME_uS;            // TA0CCR1 PWM duty cycle (Pin 23 i.e P1.2)
      TA0CTL = TASSEL_2 + MC_1;                   // SMCLK, up mode
      P1DIR|=0x0E;
      P1SEL|=0x0C;

    // Configure Watchdog in Interval Mode with an interval of 250ms
      WDTCTL=WDT_ADLY_250 ;
      IE1|=0x01;

    ////////////////////////these are different modes of battery/////////////////////////////////

    void boost(void)
    {
    // dutycycle=6;
    // TA0CCR1 = dutycycle*PWM_INIT_ON_TIME_uS;
     BATTERY_CV_LIMIT=BOOSTBATTERYVOLTAGE;
     incremntal_conductance();

    }
    void equlization(void)
    {
     // dutycycle=3;
    // TA0CCR1 = dutycycle*PWM_INIT_ON_TIME_uS;
     BATTERY_CV_LIMIT=EQUILIZATIONBATTERYVOLTAGE;
     incremntal_conductance();
    }

    void floatv(void)
    {
    // dutycycle=1;
    // TA0CCR1 = dutycycle*PWM_INIT_ON_TIME_uS;
     BATTERY_CV_LIMIT=FLOATBATTERYVOLTAGE;
    incremntal_conductance();
    }
    //////////////////////////////////this is the algo which will see the limits and increment the PWM//////////////////////////////

    if((TA0CCR1+1)<TA0CCR0 && Bat_Volts<BATTERY_CV_LIMIT)
                                       {  TA0CCR1 += 2 ; }

  • Okay, let's see...

    rams rd said:
    if((TA0CCR1+1)<TA0CCR0 && Bat_Volts<BATTERY_CV_LIMIT)
                                       {  TA0CCR1 += 2 ; }

    Well, it should work, as long as you have a long delay between two runds. Else it will bump to max DC before Bat_Volts has a chance to change.

    rams rd said:
    // dutycycle=6;
    // TA0CCR1 = dutycycle*PWM_INIT_ON_TIME_uS;

    THis should work too, if the comments ar eremoved. It is, however, better to define something like #define BOOST_DC 6 and use TAOCCR1 = BOOST_DC*PWM_INIT_ON_TIME_µS; so the compiler can calculate this fixxed value at compiler time rather than doing math at runtime.

    rams rd said:
    #define FLOATBATTERYVOLTAGE (136/10)

    I'm not sure whether this will result in a float constant. I think you must use (136.0/10) else the result will be plain int 13 and not 13.6.

    rams rd said:
     BATTERY_CV_LIMIT=BOOSTBATTERYVOLTAGE;

    This won't work. You're assigning one constant value to another constant value. I guess the code you posted is not the one you actually compile (and you have made BATTERY_CV_LIMIT a global variable now).

    rams rd said:
    P1DIR|=0x0E;
      P1SEL|=0x0C;

    I'm still wondering why you activate two output pins, TA0.1 and TA0.2

    If it is still not working, then the problem is most likely in the code that controls the flow (and which you didn't post). That means the ISRs or the loop that checks the conversion results and decides what to do.

**Attention** This is a public forum