Jump to content
43oh

MSP430G2553 multiple interrupts.


Recommended Posts

So, I have a concern. With the code I have below. I'm using the watchdog timer, an interval upmode timer, and I'm reading from inch5 of the ADC within the program loop. The only peripheral interrupt that I currently have is for TIMER1 A0, and that pretty much sets the pace for the whole program. However, I do need a GPI, and I would really like to use an interrupt to tell when this GPI has been toggled. The problem is, I am not sure how I should deal with that, in the code I have below.

 

Advice would be greatly appreciated. By the way, the Serial stuff is merely for debugging, and will not be staying. If that is important.

#include <msp430.h>
#include <stdlib.h>
#include "hw_serial.h"

using namespace uart;

volatile unsigned int count = 1;

int main(void)
{

        WDTCTL = WDTPW + WDTHOLD;                       // Stop watchdog timer

        UART<9600, 1000000> Serial;                     // Declare Serial object
        
        /* SMCLK */
        DCOCTL = 0;
        DCOCTL = CALDCO_1MHZ;
        BCSCTL1 = CALBC1_1MHZ;
        BCSCTL2 = DIVS_0;

        /* ADC */
        P1SEL |= BIT5;
        ADC10CTL1 = INCH_5 + ADC10DIV_3 ;
        ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON;
        ADC10AE0 |= BIT5;

        /* Timer1 A0 */
        TA1CCR0 = 1250;                                 // Count overflow frequency
        TA1CTL = TASSEL_2 + ID_3 + MC_1;                // SMCLK/8  upmode
                                                        // ( 1000000 / 8 ) / 1250 == 10ms tick
        TA1CCTL0 = CCIE;                                // Enable timer interrupt

        __enable_interrupt();
        WDTCTL = WDTPW | WDTCNTCL;                      // Enable WDT

        Serial.Initialize();                            // Initialize serial

        while(1){
                LPM0;                                   // Enter low power mode 0
                WDTCTL = WDTPW | WDTCNTCL;              // Pet dog
                if (count > 100){                       // ~1 Second
                        count = 1;
                        __delay_cycles(1000);           // Wait for ADC Ref to settle
                        ADC10CTL0 |= ENC + ADC10SC;    // Sampling and conversion start
                        Serial.Write(ADC10MEM, 10);
                        Serial.Write("\r");
                }
        }

        return 0;
}

__attribute__( (interrupt (TIMER1_A0_VECTOR)) )
void TIMER1_A0_ISR(void)
{
        LPM0_EXIT;
        count++;
}

 

Link to post
Share on other sites

Not quite sure what the concern is. Just create the 2nd ISR.

 

The MSP430 will only process one interrupt at a time. If the pin wiggles while you're in the timer ISR, the pin's ISR will be invoked after the timer ISR completes.

I guess I was worried about nested interrupts. But after reading and refreshing my memory I suppose nested interrupts has to be enabled first. I was thinking that I had to disable interrupts every time I was in one . . .

Link to post
Share on other sites

@@chicken Seems to be working fine, thanks for the nod on just using both interrupts no other modifications.

 

To anyone else, heres the code I'm using for a test. I'm not saying it is perfect, but it works, and it's probably not a good idea calling Serial.Write() from within the ISR, but I wanted a quick test . . .

#include <msp430.h>
#include <stdlib.h>
#include "hw_serial.h"

using namespace uart;
UART<9600, 1000000> Serial;

volatile unsigned int count = 1;

int main(void)
{

        WDTCTL = WDTPW + WDTHOLD;                       // Stop watchdog timer

        /* SMCLK */
        DCOCTL = 0;
        DCOCTL = CALDCO_1MHZ;
        BCSCTL1 = CALBC1_1MHZ;
        BCSCTL2 = DIVS_0;

        /* PINS */
        P1OUT &= 0x00;
        P1DIR &= 0x00;
        P1SEL |= BIT5;
        P1REN |= BIT3;
        P1OUT |= BIT3;
        P1IE  |= BIT3;
        P1IES |= BIT3;
        P1IFG &= ~BIT3;


        /* ADC */
        ADC10CTL1 = INCH_5 + ADC10DIV_3 ;
        ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON;
        ADC10AE0 |= BIT5;

        /* Timer1 A0 */
        TA1CCR0 = 1250;                                 // Count overflow frequency
        TA1CTL = TASSEL_2 + ID_3 + MC_1;                // SMCLK/8  upmode
                                                        // ( 1000000 / 8 ) / 1250 == 10ms tick
        TA1CCTL0 = CCIE;                                // Enable timer interrupt

        __enable_interrupt();
        WDTCTL = WDTPW | WDTCNTCL;                      // Enable WDT

        Serial.Initialize();                            // Initialize serial

        while(1){
                LPM0;                                   // Enter low power mode 0
                WDTCTL = WDTPW | WDTCNTCL;              // Pet dog
                if (count > 100){                       // ~1 Second
                        count = 1;
                        __delay_cycles(1000);           // Wait for ADC Ref to settle
                        ADC10CTL0 |= ENC + ADC10SC;    // Sampling and conversion start
                        Serial.Write(ADC10MEM, 10);
                        Serial.Write("\r");
                }
        }

        return 0;
}

__attribute__( (interrupt (TIMER1_A0_VECTOR)) )
void TIMER1_A0_ISR(void)
{
        LPM0_EXIT;
        count++;
}

__attribute__( (interrupt (PORT1_VECTOR)) )
void PORT1_ISR(void)
{
        LPM0_EXIT;
        if(P1IFG & BIT3){
                Serial.Write("Push button 2 pressed\r\n");
                P1IFG &= ~BIT3;
        }
}

 

Link to post
Share on other sites

 

@@chicken Seems to be working fine, thanks for the nod on just using both interrupts no other modifications.

 

To anyone else, heres the code I'm using for a test. I'm not saying it is perfect, but it works, and it's probably not a good idea calling Serial.Write() from within the ISR, but I wanted a quick test . . .

I agree... not good to call function that is not specifically re-entrant, and moreover, uses a shared resource (serial port) from an ISR.

The simplest way is to set some flag in ISR and check those in the main loop:

volatile unsigned int intFlags;
typedef enum {
  ISR1_FLAG = BIT 0, ISR2_FLAG = BIT1, //... and so on
};

void isr1(void) {
  //..do something..
  intFlags |= ISR1_FLAG;
  //:exit low power mode
}

void isr2(void) {
  //..do something..
  intFlags |= ISR2_FLAG;
  //:exit low power mode
}


void main(void) {
  //..
  while(1) {
    //...other code
    //:disable interrupts
    if (intFlags & ISR1_FLAG) {
      //handle isr1
      intFlags &= ~ ISR1_FLAG;
    }
    if (intFlags & ISR2_FLAG) {
      //handle isr2
      intFlags &= ~ ISR2_FLAG;
    }
    //check all other int flags
    //:enable interrupts. 
    //The disable/enable interrupts could be done for each flag 
    //(in case a handler takes time), but I choose not clutter
    //too much this simple example.
  }
}

What could happen if you do it as posted?, occasionally you will find in the serial console something like

568

600

605

59Push button 2 pressed

5

600

Link to post
Share on other sites

I agree... not good to call function that is not specifically re-entrant, and moreover, uses a shared resource (serial port) from an ISR.

The simplest way is to set some flag in ISR and check those in the main loop:

 

Yeap, I would only set a variable, of some type and then leave the ISR. For any ISR  After turning off low power mode of course.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...