Jump to content
Sign in to follow this  
mpigsley

While(1) not Executing with Timer Interrupt

Recommended Posts

Hey all,

I've run into a peculiar problem where my main loop doesn't execute. I know my interrupt routine is executing because I can uncomment the led toggle and I can see it blink. From what I've researched thus far, I believe the issue might be that the ISR is starving the main loop from ever executing. If that is the case, I'm not sure what the solution would be. 

 

The reason I have my main loop set up this way is because I am going to need different functions executing at different intervals.

 

I'm still fairly new to MSP430 development, so any help will be appreciated!

#include <msp430g2553.h>

#define MS_TIME 1000

volatile unsigned int s_cnt = 0;
unsigned int last_cnt = 0;

int main(void) {
  WDTCTL = WDTPW + WDTHOLD;            // Stop WDT
  
  P1DIR |= BIT0 + BIT6; 	       // P1.0 and P1.6 are the red+green LEDs	
  P1OUT &= ~(BIT0 + BIT6); 	       // Both LEDs off
  
  TA0CCTL0 = CCIE;                     // Enable Timer A0 interrupts
  TA0CCR0 = 22;                        // Count limit
  TA0CTL = TASSEL_1 + MC_1;            // Timer A0 with ACLK, count UP
  
  _BIS_SR(LPM0_bits + GIE);            // Enable interrupts

  while(1) {
    if (last_cnt != s_cnt) {
      last_cnt = s_cnt;
      if (last_cnt == MS_TIME) {
        P1OUT ^= BIT6;                 // Toggle green LED
        s_cnt = 0;
      }
    }
  }
}

#pragma vector=TIMER0_A0_VECTOR        // Timer0 A0 interrupt service routine
  __interrupt void Timer0_A0 (void) {
  s_cnt++;
  //P1OUT ^= BIT6;
}

Share this post


Link to post
Share on other sites

 _BIS_SR(LPM0_bits + GIE);            // Enable interrupts
You are going in to low power mode 0 and doing nothing to exit - so the main() code just halts right there.

 

try this instead...

 

_enable_interrupts();		// Enable all interrupts

Share this post


Link to post
Share on other sites
_enable_interrupts();

It's not declared in the scope. What header is that defined in? I can't seem to find any documentation on it either.

I've also played around with the low power modes to no avail. Removing it doesn't help.

Share this post


Link to post
Share on other sites

Try using #include <msp430.h> instead of the device specific header file.

 

What compiler are you using? Some early versions of MSPGCC may not support _enable_interrupts().

Share this post


Link to post
Share on other sites
__enable_interrupt();

could be achieved by this

_BIS_SR(GIE);            // Enable interrupts

GIE is your Global Interrupt Enable bit. and now you aren't entering sleep mode, so your code will continue running.

 

 

FWIW, you probably should go to sleep in the while loop instead of spinning continually checking for a count change.

 while(1) {
   LPM0; //enter Low Power mode
      
      if (s_cnt == MS_TIME) {
        P1OUT ^= BIT6;                 // Toggle green LED
        s_cnt = 0;
      }
  }

And then you would need to add a line to your interrupt to tell the processor to stay awake when the interrupt is processed. Place this inside your interrupt.

LPM0_EXIT;

Share this post


Link to post
Share on other sites

@@pabigot The capture compare flag needs to be manually reset after each ISR execution?

 

From the user guide page 11-20:
 

CCIFG0 is automatically reset when the

interrupt request was accepted according to the
interrupt scheme of the MSP430 family

 

@@greeeg Even after removing Low Power Mode I'm still getting that starvation. 

Share this post


Link to post
Share on other sites

@@pabigot The capture compare flag needs to be manually reset after each ISR execution?

Apparently not for CCR0; thanks for correcting me. It does need to be manually reset for the other CCRs, unless using the TAIV register in which case the highest priority flag is cleared on read.

Share this post


Link to post
Share on other sites

I ended up using SMCLK and increasing the capture compare register. Why this suddenly works while the ACLK didn't... I don't know. The updated code is below for reference.

#include <msp430g2553.h>

#define MS_TIME 1000

volatile unsigned int s_cnt = 0;
unsigned int last_cnt = 0;

int main(void) {
  WDTCTL = WDTPW + WDTHOLD;            // Stop WDT
  
  P1DIR |= BIT0 + BIT6; 	       // P1.0 and P1.6 are the red+green LEDs	
  P1OUT &= ~(BIT0 + BIT6); 	       // Both LEDs off
  
  TA0CCTL0 = CCIE;                     // Enable Timer A0 interrupts
  TA0CCR0 = 1000;                      // Count limit
  TA0CTL = TASSEL_2 + MC_1;            // Timer A0 with SMCLK, count UP
  
  _BIS_SR(GIE);                        // Enable interrupts

  while(1) {
    if (last_cnt != s_cnt) {
      last_cnt = s_cnt;
      if (s_cnt >= MS_TIME) {
        P1OUT ^= BIT6;                 // Toggle green LED
        s_cnt = 0;
      }
    }
  }
}

#pragma vector=TIMER0_A0_VECTOR        // Timer0 A0 interrupt service routine
  __interrupt void Timer0_A0 (void) {
  s_cnt++;
}

Share this post


Link to post
Share on other sites

You mentioned that uncommenting the LED toggle in your interrupt routine worked. From your code, the frequency of this will be 1000 times quicker than when you are running it through your ISR.

 

CCR0 is set at 1000, ISR is called every 1000 clocks.

 

s_cnt is incremented once per ISR. So s_cnt will reach 1000 after 1000*1000 clocks.

 

It may have been working, but just slower than you expected, now that you switched to a quicker clock 1000 clocks happen around every second.

 

Compared to about 30 seconds for the 32khz, or if you don't have a crystal attached then ACLK runs from the VLO which runs at 12khz and would take about a minute to toggle the LED.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×