Thursday, February 07, 2013

Stopping Timer A on MSP430

Coding a microcontroller like MSP430 is a lot more difficult (at least for me) than Arduino but since I have a few around, I really want to learn. An important aspect of working with these are interrupts. I looked over the examples and they are all great but I wanted to do something a little bit more yet still simple. The idea: start a timer when the interrupt on a button fires, then stop it after a few seconds, if the button is not pushed again; if it is, restart the timer so it always stops the same time after the last button push. Pretty simple in theory; well, in practice as well after I figured it out. The most difficult task was to restart the timer with each button push. I tried to find info on the web and by reading the MSP430x2xx Family User's Guide but couldn't get anywhere: no matter what I tried the timer was stopping after what seemed like random times (after a lot of debugging I realized it wasn't random, the timer was always stopping after the right time measured since the first button push).

I tried several things but mainly:
  • set TACCR0=0 - I hoped this will reset the counter to 0 which is not true, and this was spelled out in the doc I mentioned

  • set TACTL = MC_0 - I hoped that stopping the timer means resetting the counter but it seems that the timer just stopped and when I re-enabled it it continued counting from where it left off.

  • In the end, re-reading the user's guide for the nth time, I noticed a paragraph in which it says that the register holding the current count (TAR) is writable (I was sure until then that is read only) and this was the key: when I want to reset the counter, I just write 0 in this register; just to make sure all is well, I also reset TACTL just to make sure the timer restarts - this may not be needed but it works so I left the code in there. Another thing is stopping the timer in the timer ISR by doing TACTL = MC_0 because I want the timer to shut down after the given time, and not keep counting - this makes the mcu go back to sleep mode.

    The final version I ended up with is here: I am sure it can be improved but again, it works now and exactly the way I wanted it so I'll keep it this way.

    Next thing: play with external interrupts.

    [Edit] Now that I figured out how to reset the timer, I changed the code to use a variable to handle the restart and stop of the timer: reset it to 0 when the button interrupt fires, increment it in the timer ISR and stop the timer after a few iterations. This is much more flexible because a) I can stop the timer at the exact time I want (not being dependent on the timer counter and the clock frequency and dividers) and b) I can reuse the timer for other things, changing the behavior based on the TAIV vector. Next step in developing my little app will use this approach.

    3 comments:

    1. This comment has been removed by the author.

      ReplyDelete
    2. WELL PLEASE HAVE A LOOK ON MY CODE ARE YOU SAYING THAT I SHOULD I DO.


      if((!(P2IN & BIT0))&& (value>0))
      {
      value --;
      TA1CCR0 = 105;
      TA1CCR2 = wave[value];
      TA1CCTL2 = OUTMOD_7;
      TA1CTL = TASSEL_2 + MC_1;
      P2IFG &=~BIT5;
      TACTL = MC_0;
      }

      ReplyDelete
    3. I am using msp4630G2553.
      I want to find the time for which an adc value>511 and interpret this time to blink either red or green led.
      This is my code.

      #include
      unsigned int value=0;

      void ConfigureAdc(void);

      void main(void)
      {
      {
      int t;
      WDTCTL = WDTPW + WDTHOLD; // Stop WDT
      BCSCTL1 = CALBC1_1MHZ;
      BCSCTL2 &= ~(DIVS_3);
      P1DIR|=BIT0+BIT6;

      P1SEL|=BIT1;
      P1SEL |= BIT3;
      TACTL=TASSEL_2+ID_0+MC_2;
      ConfigureAdc(); // ADC set-up function call
      __enable_interrupt(); // Enable interrupts.

      while(1)
      {
      __delay_cycles(1000); ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
      __bis_SR_register(CPUOFF + GIE); // LPM0 with interrupts enabled// Low Power Mode 0 with interrupts enabled
      value = ADC10MEM;
      if(value>511)
      TA1R=0;
      else
      {
      t=TA1R;

      if(t<3000000)
      {P1OUT&=~(BIT0+BIT6);
      P1OUT|=BIT6;
      }
      else
      {P1OUT&=~(BIT0+BIT6);
      P1OUT|=BIT0;

      }

      }


      }

      }
      }

      // ADC10 interrupt service routine
      #pragma vector=ADC10_VECTOR

      __interrupt void ADC10_ISR (void)

      {

      __bic_SR_register_on_exit(CPUOFF); // Return to active mode

      }


      // Function containing ADC set-up
      void ConfigureAdc(void)
      {

      ADC10CTL1 = INCH_3 + ADC10DIV_3 ;
      ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE;
      ADC10AE0 |= BIT3; // ADC input enable P1.3
      }

      ReplyDelete