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.

How to Proper Call an Interrupt within a Function

Other Parts Discussed in Thread: MSP430F5522

I'm having a problem implementing and interrupt function in my already existing code.  Basically I want the interrupt to trigger either when a certain output is triggered or when the counter that triggers the output reaches the threshold.  

Equipment:

Micro:  MSP430F5522

CCS:  5.5.0.00077

Compiler: TI v4.1.9

The device is supposed to scan for a light, and if the light is detected a certain amount of times in a row, an output is turned on that lights up a green LED.  If it fails a certain amount of times in a row, a red LED is supposed to turn on.  

The problem with this code is that the red LED does not stay on long enough to show that there was a high amount of consecutive misses when scanning for the light.  The solution was to come up with an interrupt function that uses a different clock within the processor so the test cycle is not delayed and the red LED stays on long enough for the operator to know about the misses.  

The RED/GREEN_LED_ON/OFF are bit wise output controllers defined earlier in the file.

This is the original function before I put the interrupt function within it:

#define PASSCOUNTERTHRESHOLD  40//20

   void display( char  event , char test )
	{
		int j,i;

		static int maxConsecPassingCount=0;
		static int consecPassingCount=0; 
		static int passingCount=0; 
		static int timeLimit=0;   // amount of time allowed for non detection before failure is asserted.
		static int consecFails=0;

		if ( event == DETECTED )
		{


			if ( stardata.outputOptions & DUALED )
			{

				if( ++consecPassingCount > 99  && !(EXT_INPUT)) // if no detection for long period , assume no motion and just reset counter
				{
					RED_LED_OFF;
					GREEN_LED_ON;
					return;
				}

				if( timeLimit > 0  && !(EXT_INPUT))
				{
					// evaluate whether the time limit has been violated by stopping timer and reading counter, reset counter for next time. if limit exceeded turn on red led
					// else turn on green led
					TA0CCR0 = 0;
					i=TA0R;

					if ( i  > timeLimit )
					{
						RED_LED_ON;
						GREEN_LED_OFF;
					}
					else
					{
						GREEN_LED_ON;
						RED_LED_OFF;
					}
				}
				else
				{
					RED_LED_OFF;
					GREEN_LED_ON;
					timer_us(50);
					GREEN_LED_OFF;
				}

				consecFails=0;
			}


		}
		else if ( event==NOT_DETECTED)
		{
			passingCount+=consecPassingCount;
			if ( consecPassingCount > maxConsecPassingCount )   // find maximum string of consecutive passing tests out of a group <PASSCOUNTERTHRESHOLD> of tests to estimate the speed.
			{
				maxConsecPassingCount = consecPassingCount;
			}
			consecPassingCount=0;


			if ( passingCount > PASSCOUNTERTHRESHOLD)  // we should have enough data to predict the speed, so now calculate the maximum failing time allowed before we set the fail led.
			{
				passingCount=0;
				timeLimit= maxConsecPassingCount * stardata.starLimits[test].hiTestLimit2; //150;  // amount of time which is allowed between non detect intervals.
				maxConsecPassingCount=0;
			}
			if ( timeLimit > 0 && consecFails == 0 )				// start timer
			{
				TA0R=0;
				TA0CCR0 = 5000;
			}

			if ( consecFails > 100)
			{
				GREEN_LED_OFF;
				RED_LED_ON;
				return;
			}
				//consecFails=0;
			else ++consecFails;
		}


	}

I defined the timer used in the interrupt function in the main.c file as follows:

TA2CCTL0=CCIE;

TA2CTL=TASSEL_2+MC_3+ID__8; 

TA2CCR0=125000;

This is the code with the interrupt function replacing RED_LED_ON output:

   void display( char  event , char test )

{

int j,i;

static int maxConsecPassingCount=0;

static int consecPassingCount=0; //kg 8/16

static int passingCount=0; //kg 8/16

static int timeLimit=0;   // amount of time allowed for non detection before failure is asserted.

static int consecFails=0;

if ( event == DETECTED )

{

if ( stardata.outputOptions & DUALED )

{

if( ++consecPassingCount > 99  && !(EXT_INPUT)) // if no detection for long period , assume no motion and just reset counter

{

RED_LED_OFF;

GREEN_LED_ON;

return;

}

if( timeLimit > 0  && !(EXT_INPUT))

{

// evaluate whether the time limit has been violated by stopping timer and reading counter, reset counter for next time. if limit exceeded turn on red led

// else turn on green led

TA0CCR0 = 0;

i=TA0R;

if ( i  > timeLimit )

{

#pragma vector=TIMER1_A1_VECTOR  //kg

__interrupt void TIMER1_A1ISR (void)

{

RED_LED_ON;

GREEN_LED_OFF;

}

}

else

{

GREEN_LED_ON;

RED_LED_OFF;

}

}

else

{

RED_LED_OFF;

GREEN_LED_ON;

timer_us(50);

GREEN_LED_OFF;

}

consecFails=0;

}

}

else if ( event==NOT_DETECTED)

{

passingCount+=consecPassingCount;

if ( consecPassingCount > maxConsecPassingCount )   // find maximum string of consecutive passing tests out of a group <PASSCOUNTERTHRESHOLD> of tests to estimate the speed.

{

maxConsecPassingCount = consecPassingCount;

}

consecPassingCount=0;

if ( passingCount > PASSCOUNTERTHRESHOLD)  // we should have enough data to predict the speed, so now calculate the maximum failing time allowed before we set the fail led.

{

passingCount=0;

timeLimit= maxConsecPassingCount * stardata.starLimits[test].hiTestLimit2; //150;  // amount of time which is allowed between non detect intervals.

maxConsecPassingCount=0;

}

if ( timeLimit > 0 && consecFails == 0 ) // start timer

{

TA0R=0;

TA0CCR0 = 5000;

}

if ( consecFails > 100)

{

#pragma vector=TIMER1_A1_VECTOR  //kg

__interrupt void TIMER1_A1ISR (void)

{

RED_LED_ON;

GREEN_LED_OFF;

}

}

//consecFails=0;

else ++consecFails;

}

    }

I can't get the code to compile and I can't find a forum that discusses adding interrupts that are controlled in the same way I am using them.  Does anyone have any ideas as to what I am doing wrong?

   void display( char  event , char test ) { int j,i;
static int maxConsecPassingCount=0; static int consecPassingCount=0; //kg 8/16 static int passingCount=0; //kg 8/16 static int timeLimit=0;   // amount of time allowed for non detection before failure is asserted. static int consecFails=0;
if ( event == DETECTED ) {

if ( stardata.outputOptions & DUALED ) {
if( ++consecPassingCount > 99  && !(EXT_INPUT)) // if no detection for long period , assume no motion and just reset counter { RED_LED_OFF; GREEN_LED_ON; return; }
if( timeLimit > 0  && !(EXT_INPUT)) { // evaluate whether the time limit has been violated by stopping timer and reading counter, reset counter for next time. if limit exceeded turn on red led // else turn on green led TA0CCR0 = 0; i=TA0R;
if ( i  > timeLimit ) {
#pragma vector=TIMER1_A1_VECTOR  //kg __interrupt void TIMER1_A1ISR (void) { RED_LED_ON; GREEN_LED_OFF; }
} else { GREEN_LED_ON; RED_LED_OFF; } } else { RED_LED_OFF; GREEN_LED_ON; timer_us(50); GREEN_LED_OFF; }
consecFails=0; }

} else if ( event==NOT_DETECTED) { passingCount+=consecPassingCount; if ( consecPassingCount > maxConsecPassingCount )   // find maximum string of consecutive passing tests out of a group <PASSCOUNTERTHRESHOLD> of tests to estimate the speed. { maxConsecPassingCount = consecPassingCount; } consecPassingCount=0;

if ( passingCount > PASSCOUNTERTHRESHOLD)  // we should have enough data to predict the speed, so now calculate the maximum failing time allowed before we set the fail led. { passingCount=0; timeLimit= maxConsecPassingCount * stardata.starLimits[test].hiTestLimit2; //150;  // amount of time which is allowed between non detect intervals. maxConsecPassingCount=0; } if ( timeLimit > 0 && consecFails == 0 ) // start timer { TA0R=0; TA0CCR0 = 5000; }
if ( consecFails > 100) { #pragma vector=TIMER1_A1_VECTOR  //kg __interrupt void TIMER1_A1ISR (void) { RED_LED_ON; GREEN_LED_OFF; } } //consecFails=0; else ++consecFails; }
    }

  • Kyle,

    First of all, your question is probably too long for a forum, second, to answer your question in the heading and the first two paragraphs, most experienced developers will recommend that you never call an interrupt from a function.  Interrupts are triggered by the hardware, possible approach is to have an interrupt set a global variable to some value than have a normal, "non interrupt" function respond to that value.

  • Thank you for the reply, I'll keep it shorter next time. Can I have the interrupt be triggered by an output? What I am struggling with in other examples and in my code is how the interrupt starts.
  • 1. Think of an interrupt as a function, that runs any  time an event happens regardless of what your program is doing.  The reason your program will not compile is because of this:

                    if (i > timeLimit) {
                        #pragma vector = TIMER1_A1_VECTOR  // kg  <===  cannot define function inside of an if statement
                        __interrupt void TIMER1_A1ISR(void) {
                            RED_LED_ON;
    
                            GREEN_LED_OFF;
                        }
    
                    } else {
                        GREEN_LED_ON;
    
                        RED_LED_OFF;
                    }
    

    Basically each function or an interrupt must be defined in global scope.

    2. I do not believe that an interrupt can be triggered by an output, but it can be triggered by an input.

  • 2. I do not believe that an interrupt can be triggered by an output, but it can be triggered by an input.

    But one can connect the output with an interrupt-capable input externally. (Didn't check if this makes sense in that case at all, though ...).

    1. Think of an interrupt as a function, that runs any  time an event happens regardless of what your program is doing.

    The MCU datasheet, especially the sections dealing with interrupts, are a highly suggested read. A general understanding of such concepts like 'interrupts' are essential for embedded/MCU projects.

  • f.m.

    With regard to your first statement, the question is being asked by someone who is just beginning to code, are you trying to confuse Kyle? Is that a common solution and a good solution for him to consider? Besides, this is not triggering an interrupt by an output, you are chaining an output to an input and still triggering by an input :).
  • With regard to your first statement, the question is being asked by someone who is just beginning to code, are you trying to confuse Kyle?

    At least not intentionally.

    Is that a common solution and a good solution for him to consider?

    I think not. From the somehow vague description, I cannot see where "triggering an interrupt from an output" would have a place.  But in a strict theoretical sense, an output could trigger an interrupt that way.

    One of the projects I had been involved some time ago used this method to measure the period length of a serial output channel, in order to to correct thermal/aging caused deviation at a minimum.

    Besides, this is not triggering an interrupt by an output, you are chaining an output to an input and still triggering by an input :).

    Only indirectly, for sure ...

  • Thank you again for the reply. Can an interrupt be triggered by a global variable? A counter enables the output to the red LED, and I could connect that output to another input pin, but it would make my board layout more complicated. If I define a new global variable to be read from the input pin connected to the red LED output, how does the interrupt trigger from this variable?

    I'll pull this section out of the if statement and put it in main under my definitions:

    TA2CCTL0=CCIE;
    TA2CTL=TASSEL_2+MC_3+ID__8;
    TA2CCR0=125000;
    #pragma vector = TIMER1_A1_VECTOR
    __interrupt void TIMER1_A1ISR(void)
    {

    }

    Where I'm totally lost from other tutorials, examples, and user manuals is how the interrupt function gets called. Where do I include the input pin that triggers the interrupt?
  • Kyle,

    Your program should probably look like this:

    main () {
        // ... configure your hardware here
        while (1) {
            // loop forever
            // check status of input
            // some logic
            if (counter > 50) {  // this is logic example
                P1OUT |= PIN1;
            }
        }
    }


    You probably do not need interrupt, just run that while loop forever and keep checking the logic.

  • Again, thanks for the reply. The section of code that I included is part of a much larger project that nearly uses all available memory. I'm just working on one section for learning purposes/practice. I thought an interrupt would be the right choice because the micro is scanning for the presence of light about once every 150us and I don't want the device to stop scanning while it is flashing a red LED for failure. I was hoping to use a separate asynchronous clock to control the red LED on time in the interrupt so the scanning continues to be counted and other pass/failures will be detected.
  • OK, your logic makes sense, what you say is possible. So the hardware will kick off the ISR, and in the ISR you can have little logic to make it happen. Good luck...

**Attention** This is a public forum