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.

MSP430F5529: Changing PWM duty cycle based on ADC input

Part Number: MSP430F5529


Hi MSP Low-Power microcontroller Forum, 

I am currently using an MSP430F5529 and trying to change the duty cycle based on ADC input. When I run the code in the debugger it will run through maybe twice and update the TA0CCR1, but then it will get stuck on   __bis_SR_register(LPM0_bits + GIE); in the while loop. 

Could you please help figure out why this is? 

Please see my code below: 

#include <msp430.h>



int main(void)
{
  TA0CCR1 = 499; //Duty Cycle 
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT

  ADC12CTL0 = ADC12SHT02 + ADC12ON;         // Sampling time, ADC12 on
  ADC12CTL1 = ADC12SHP;                     // Use sampling timer
  ADC12IE = 0x01;                           // Enable interrupt
  ADC12CTL0 |= ADC12ENC;
  P6SEL |= 0x01;                            // P6.0 ADC option select
  P1DIR |= 0x01;                            // P1.0 output
 
    P2DIR |= BIT2;                       // P2.2
    P2SEL |= BIT2;                      // P2.2 Option select
     TA0CCR0 = 512-1;                          // PWM Period
     TA0CCTL1 = OUTMOD_7;                      // CCR1 reset/set
     TA0CTL = TASSEL_2 + MC_1 + TACLR;         // SMCLK, up mode, clear TAR

//       __bis_SR_register(LPM0_bits + GIE);
  while (1)
  {
    ADC12CTL0 |= ADC12SC;                   // Start sampling/conversion
    
    __bis_SR_register(LPM0_bits + GIE);     // LPM0, ADC12_ISR will force exit
   // __no_operation();                       // For debugger
  }
}

#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(__even_in_range(ADC12IV,34))
  {
  case  0: break;                           // Vector  0:  No interrupt
  case  2: break;                           // Vector  2:  ADC overflow
  case  4: break;                           // Vector  4:  ADC timing overflow
  case  6:                                  // Vector  6:  ADC12IFG0
    if (ADC12MEM0 >= 0x7ff){                 // ADC12MEM = A0 > 0.5AVcc?
      P1OUT |= BIT0;
      if (TA0CCR1 == 0){TA0CCR1 = 0;}
      if (TA0CCR1 > TA0CCR0) {TA0CCR1 = TA0CCR0;}
      else
          TA0CCR1--;
      }              // P1.0 = 1
    else{
      if (TA0CCR1 == 0){TA0CCR1 = 0;}
      if (TA0CCR1 > TA0CCR0) {TA0CCR1 = TA0CCR0;}
      P1OUT &= ~BIT0;
      TA0CCR1++;

      }
   
    
    __bic_SR_register_on_exit(LPM0_bits);   // Exit active CPU
  case  8: break;                           // Vector  8:  ADC12IFG1
  case 10: break;                           // Vector 10:  ADC12IFG2
  case 12: break;                           // Vector 12:  ADC12IFG3
  case 14: break;                           // Vector 14:  ADC12IFG4
  case 16: break;                           // Vector 16:  ADC12IFG5
  case 18: break;                           // Vector 18:  ADC12IFG6
  case 20: break;                           // Vector 20:  ADC12IFG7
  case 22: break;                           // Vector 22:  ADC12IFG8
  case 24: break;                           // Vector 24:  ADC12IFG9
  case 26: break;                           // Vector 26:  ADC12IFG10
  case 28: break;                           // Vector 28:  ADC12IFG11
  case 30: break;                           // Vector 30:  ADC12IFG12
  case 32: break;                           // Vector 32:  ADC12IFG13
  case 34: break;                           // Vector 34:  ADC12IFG14
  default: break; 
  }
}

  • Hi Mitchell,

    Mitchell Spears said:
    __bis_SR_register(LPM0_bits + GIE);

    This puts the CPU to sleep by configuring the MSP430 to enter LPM0. Just use GIE and you should be able to debug. Also, high code optimization settings can make debugging challenging.

    Low power mode debugging behavior?

    CCS/MSP430F2274: Verify that device is in low-power mode using CCS debugger

    Regards,

    James

  • Hi James,

    Thanks for the reply. The code no longer gets stuck, but I can't figure out why the PWM Duty cycle won't update every time the TA0CCRR1 changes. What is the right way to implement it?

    Thanks

  • Your PWM period (one cycle) is 512 usec, and your conversion is taking about 15 usec, plus (rough guess) about 50 usec for the ISR, so you're doing about 7 CCR1 updates per cycle.

    It's not really useful to update the CCR more than once per cycle. At best, it has no effect, and at worst it will cause glitches. In many/most applications (I don't know yours) you want multiple PWM periods between changes. Another effect is that by incrementing CCR1 multiple times the duty cycle will jump.

    So just slow your ADC sampling down. A simple tactic would be to use something like __delay_cycles(512) before setting ADCSC. Another would be to create a CCR0 interrupt and do the ADCSC there.

    One thing I've done is have the stimulus (ADC in this case) compute a target duty cycle, and then have the CCR0 interrupt increment towards the target to produce a smooth transition (without overshoot). 

    I'll just mention here: Timer_A is susceptible to glitches if CCR1 happens to be near the counter value when set. Timer_B (with CLLD=1) is pretty much immune to this. If you're not tied to the TA0.1 pin, this might be a useful move.

**Attention** This is a public forum