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.

2 PWM and timing sampling with different ( CCR0 = 1250-1; // PWM Period )

Other Parts Discussed in Thread: MSP430F2013

Hi I am working on a project which I need a timer to be running all the time and sampling ADC every 5 minutes , the problem is that I also need to create a PWM pulse sometime and it has to be with different frequency. I am using MSP430F2013 which does not have 2 timers. Below there is an example of the code. When it runs the LED flash very fast and the 5 minutes sampling doesn't work . Can anybody help ? I don't have the ADC sample part in this code, because it would be too big to post, but I have the timer part that I want to fix.

Thanks

void main(void)
  { 
  CCTL0 = CCIE;                               // CCR0  interrupt enable
  DCOCTL = CALDCO_1MHZ;
  BCSCTL1 = CALBC1_1MHZ;                       
  
  P1OUT &= ~ 0X40;                            // Sets the output to low GPIO
  P1DIR |= 0X40;                              // Set pin P1.6 to output direction
  
 while(1)
  {
  
 _BIS_SR(LPM0_bits + GIE);                    // Enter LPM0
 
 //****************************************************************************************************************************************
 //             LED Control  Begine
 //****************************************************************************************************************************************
    if (Solar_Volts >= 5024)                  // If Solar panel is more than  1 Volts turn LED OFF;
       P1OUT &= ~0x40;                        // Turn LED OFF;
   
    if (Solar_Volts <= 4521)                  // If Solar panel is more than  1 Volts turn LED OFF;
    {
      WDTCTL = WDTPW + WDTHOLD;               // Stop WDT
      CCR0 = 1250-1;                          // PWM Period
      CCTL1 = OUTMOD_7;                       // CCR1 reset/set
      CCR1 = 500;                             // CCR1 PWM duty cycle
      TACTL = TASSEL_2 + MC_1;                // SMCLK, up mode 
      P1SEL |= 0x40;                          // Turn  LED ON;
    }
   
 //****************************************************************************************************************************************
 //             LED Control Finish
 //****************************************************************************************************************************************
 
 //***************************************************************************************
 //                       5 MINUTES SAMPLE TIME STARTS 
 //
   CCR0 =  61439;                         // CCR1 counts value for 15 seconds  
   TACTL = TASSEL_1 + MC_1 + ID_3;        // SMCLK UP MODE
 //*************************************************************************************** 
   }
  }

// Timer A0 interrup service routine
  #pragma vector = TIMERA0_VECTOR
__interrupt  void Timer_A (void)
   {
     P1OUT |= 0X40;                           // Turn LED ON
  } 

  • Hi,

    So here is what it looks to me what your program is going to do:

    If  Solar_Volts >= 5024

        turn off LED

        Timer A is then set to run from ACLK (32KHz?)

         Appoximately 15 seconds later you get a timer interrupt that turns the LED on.

         It is immediately turned off again by the if statement in the main loop.

         The above goes on forever or until Solar_Volts drops below 5024

     

    If Solar_Volts < 4521

         Watch dog turned off (Not sure why this wasn't done at beginning of program)

         Set compare register for 1249 (used for setting output)

         set output mode for reset / set

        Set compare register for 500 (used for resetting output)

        Set clock source of Timer A to be SMCLK (1Mhz)  up mode

        Turn led on (This should be P1OUT |= 0x40)

         Falls out of if statement and set compare register to 61439

          Resets timer A to ACLK  up mode.

         Not sure what happens after this, but changing Timer A registers without  first stopping it is not recommended. I don't think you are doing it intentionally but that is what is happening.

     

    It looks to me like you need to break this up into routines. Right now you have a bunch of stuff in the main loop that is all mingled together.  I don't see anything that kicks off the ADC. I don't see anything that would give you a 5 minute interval to kick off the ADC.

    HTH,

    Barry

     

  • Thanks Barry

    Here is the almost complete code, the timer for the sampling has to be on all the time , because it sample every 5 minutes ( do you have a better idea ?) so the PWM only comes on when there is no solar light however the 5 minutes samples has to continue running.

    Thanks

     

    #include  <msp430x20x3.h>

    /* Arrays to store SD16 conversion results */
    /* NOTE: arrays need to be global to       */
    /*       prevent removal by compiler       */
    static unsigned long int Bat_Volts = 0x00;
    static unsigned long int Solar_Volts = 0x00;
    static unsigned long int Solar_Current = 0x00;
    static unsigned int ch_counter=0;
    unsigned int i = 0;
    unsigned int x = 0;
    unsigned int Sample_x = 0;
    unsigned long int Solar_Power = 0;
    unsigned long int Daily_Solar_Power = 0;
    unsigned long int Average_Power = 0;


    void main(void)
    {
     
      volatile unsigned int i;                                                                                      // Use volatile to prevent removal
                                                                                                                                   // by compiler optimization
     
      WDTCTL = WDTPW + WDTHOLD;                                                               // Stop watchdog timer
      CCTL0 = CCIE;                                                                                                 // CCR0  interrupt enable
      DCOCTL = CALDCO_1MHZ;
      BCSCTL1 = CALBC1_1MHZ;                       
     
      SD16CTL = SD16REFON + SD16SSEL_1;                                               // 1.2V ref, SMCLK
      SD16INCTL0 = SD16INCH0;                                                                        // Set channel A0+/-  // SD16INCTL0 = SD16INCH0 + SD16GAIN_2;                
      SD16CCTL0 |= SD16SNGL + SD16UNI + SD16IE;                                 //SD16CCTL0 |= SD16SNGL + SD16UNI + SD16IE;
                                                                                                                                  // Single conv, 256OSR, unipolar,
                                                                                                                                  // enable interrupt
      SD16INCTL0 |= SD16INTDLY_0;                                                                // Interrupt on 4th sample
      SD16AE = SD16AE0;                                                                                     // P1.0 A0+, A0- = VSS
     
      for (i = 0; i < 0x3600; i++);                                                                              // Delay for 1.2V ref startup
     
      P1OUT &= ~ 0X40;                                                                                         // Sets the output to low GPIO
      P1DIR |= 0X40;                                                                                               // Set pin P1.6 to output direction
     
     
     while(1)
     {
       SD16CCTL0 |= SD16SC;                                                                           // Set bit to start conversion
     _BIS_SR(LPM0_bits + GIE);                                                                        // Enter LPM0
     
     //****************************************************************************************************************************************
     //             LED Control  Begins
     //****************************************************************************************************************************************
     if (Solar_Volts >= 5024)                                                                               // If Solar panel is more than  1 Volts turn LED OFF;
           P1OUT &= ~0x40;                                                                                   // Turn LED OFF;
        if ((Solar_Volts >= 15072) && (Bat_Volts >= 25170))                         // If solar  Vp = 3 Volts & battery Vbat = 5.01 Volts, reset the code,
                                                                                                                              // in other words consider battery is above 3 V so wait for dark then turn LED ON;     
           i = 1;                                                                                                          // Reset i = 1;
        if (Bat_Volts <= 25170)                                                                            // If Battery is less than 5.01 Volts;
        {
           i = 0;                                                                                                          // i = 0;
           P1OUT &= ~ 0X40;                                                                                 // Turn LED OFF;
        }
    //*************************************************************************************************************************************
    //  This routine was created to PWM the LED Driver with 100Hz , If solar panel has no light and battery is above 5 V than turns LED 

       
        if ((Solar_Volts <= 4521) && (Bat_Volts >= 25170) && (i))     
        {
        
          WDTCTL = WDTPW + WDTHOLD;                                                       // Stop WDT
          CCR0 = 1250-1;                                                                                       // PWM Period
          CCTL1 = OUTMOD_7;                                                                            // CCR1 reset/set
          CCR1 = 500;                                                                                            // CCR1 PWM duty cycle
          TACTL = TASSEL_2 + MC_1;                                                               // SMCLK, up mode 
          P1SEL |= 0x40;                                                                                        // Turn  LED ON;
        }    
       
     //****************************************************************************************************************************************
     //             LED Control Finish
     //****************************************************************************************************************************************
      
     //***************************************************************************************
     //                       5 MINUTES SAMPLE TIME STARTS
     // Here is the problem , this part of the timer has to be running all the time and sample every 5 minutes, later I will create a routine
     // that gets the result of this counting and do someting with it ( This is not done yet)
     //
       CCR0 =  61439;                                                                                       // CCR1 counts value for 15 seconds
       TACTL = TASSEL_1 + MC_1 + ID_3;                                                   // ACLK UP MODE
     //*************************************************************************************** 
     
     }
    }

    // Timer A0 interrup service routine
      #pragma vector = TIMERA0_VECTOR
    __interrupt  void Timer_A (void)
       {
         x = x + 1;
        if (x == 1)                                                                                                 // every sample is = 15s so count to 18 samples = 300s ( 5 minutes)
        {
          Solar_Power = (((Solar_Volts >> 2) * (Solar_Current >> 2))>>5);
          Sample_x = Sample_x + 1;
          Daily_Solar_Power = Daily_Solar_Power + Solar_Power ;
          Average_Power = (Daily_Solar_Power / Sample_x) ;
          x = 0;
        } 
         }

    #pragma vector = SD16_VECTOR
    __interrupt void SD16ISR(void)
    {
      switch (SD16IV)
      { case 2:                                                                                               // SD16MEM Overflow
        break;
     
      case 4:                                                                                                // SD16MEM0 IFG
           
        switch(ch_counter)
        { 
        case 0:
            Bat_Volts = SD16MEM0;                                                           // Save CH0 results (clears IFG)
            SD16AE &= ~SD16AE0;                                                            // Disable external input A0+, A0
            SD16INCTL0 &= ~SD16INCH_0;                                           // Disable channel A0+/-
            ch_counter++;
           
            SD16INCTL0 |= SD16INCH_1;                                               // Enable channel A1+/-                         
            SD16AE |= SD16AE2;                                                                // Enable external input on A1+
            break;
           
        case 1:
            Solar_Volts = SD16MEM0;                                                       // Save CH1 results (clears IFG)
            SD16AE &= ~SD16AE2;                                                           // Disable external input A1+, A1
            SD16INCTL0 &= ~SD16INCH_1;                                          // Disable channel A1+/-
            ch_counter++;

            SD16INCTL0 |= SD16INCH_2;                                             // Enable channel A2+/-                      
            SD16AE |= SD16AE4;                                                              // Enable external input on A2+
            break;
           
        case 2:
            Solar_Current = SD16MEM0;                                                // Save CH2 results (clears IFG)
            ch_counter = 0;                                                                         // Reset channel count (end of seq)
            SD16AE = SD16AE0;                                                               // Reset external input to A0+/-
            SD16INCTL0 = SD16INCH_0;                                               // Reset channel observed
            break;
        }
       
         _BIC_SR_IRQ(LPM0_bits);                                                        // Exit LPM0   
      }
    }

  • Marcelo,

    It doesn't appear that you are using the watchdog timer for anything, so why not use it for the 5 minute timer, you could then use Timer A to generate the PWM for 100Hz LED output.

     

    marcelo deoliveira said:

    //*************************************************************************************************************************************
    //  This routine was created to PWM the LED Driver with 100Hz , If solar panel has no light and battery is above 5 V than turns LED 

       
        if ((Solar_Volts <= 4521) && (Bat_Volts >= 25170) && (i))     
        {
        
          WDTCTL = WDTPW + WDTHOLD;                                                       // Stop WDT
          CCR0 = 1250-1;                                                                                       // PWM Period
          CCTL1 = OUTMOD_7;                                                                            // CCR1 reset/set
          CCR1 = 500;                                                                                            // CCR1 PWM duty cycle
          TACTL = TASSEL_2 + MC_1;                                                               // SMCLK, up mode 
          P1SEL |= 0x40;                                                                                        // Turn  LED ON;
        }    
       
     //****************************************************************************************************************************************
     //             LED Control Finish
     //****************************************************************************************************************************************
      
     //***************************************************************************************
     //                       5 MINUTES SAMPLE TIME STARTS
     // Here is the problem , this part of the timer has to be running all the time and sample every 5 minutes, later I will create a routine
     // that gets the result of this counting and do someting with it ( This is not done yet)
     //
       CCR0 =  61439;                                                                                       // CCR1 counts value for 15 seconds
       TACTL = TASSEL_1 + MC_1 + ID_3;                                                   // ACLK UP MODE
     //*************************************************************************************** 
     
     }
    }

    This bit of code is not going to generate the PWM signal you want.   You set it up to use the SMCLK but as soon as it falls out of the if statement it is set back to using ACLK and the CCR0 value is changed back to 61439.

    marcelo deoliveira said:

    // Timer A0 interrup service routine

      #pragma vector = TIMERA0_VECTOR
    __interrupt  void Timer_A (void)
       {
         x = x + 1;
        if (x == 1)                                                                                                 // every sample is = 15s so count to 18 samples = 300s ( 5 minutes)
        {
          Solar_Power = (((Solar_Volts >> 2) * (Solar_Current >> 2))>>5);
          Sample_x = Sample_x + 1;
          Daily_Solar_Power = Daily_Solar_Power + Solar_Power ;
          Average_Power = (Daily_Solar_Power / Sample_x) ;
          x = 0;
        } 
         }

    I'm guessing you really meant  "if (x == 18)" in this section.

    Another suggestion I would make is to get the code out of the ISR's and use flags that are processed in the main loop.

    So for instance in your timer_A ISR you could just increment a value called time_tick. In the main loop you could then do something like

    if (time_tick >= 18)

    {

        time_tick = 0;

        (rest of code goes here)

    }

    I would recommend doing the same sort of thing for your SD16 ISR. In the ISR simply set a value such as SD16_data_ready = 1; In the main loop do something like:

    if ( SD16_data_ready)

    {

       SD16_data_ready = 0;

       (rest of code goes here)

    }

    You are starting your conversion in the main loop, which you probably don't want to do. You will be starting conversions all the time. I believe you should start the conversion when you've detected 5 minutes has elapsed (time_tick >= 18). I also think you should start conversions for cases 0 and 1 in your state machine.

    Barry

     

**Attention** This is a public forum