10 years ago.

KL25Z Interrupt Problem, interrupt's stop working

I have this code which interrupts twice when operating the switches then the interrupt stops working. Not sure what I'm doing wrong. This is only a test program that I put together for another issue I have using an interrupt. What I actually want to do is have a switch interrupt my program at any time to call a menu function and this is where I hit this issue. I assumed by using a NULL the interrupt would be stopped and I could re-enable it again. I also noticed that no other interrupts on different pins would work after. I'm thinking it's due to the while(1) loops but not sure.

I may have to approach this in another way perhaps using Timeout.

I have not tried this on the LPC1768, but I' sure I'm doing this wrong.

If anyone can help.

Many thanks

KL25Z interrupt test

#include "mbed.h"

DigitalIn switch1(PTA1);
DigitalIn switch2(PTE30);

InterruptIn switch3(PTA2);

DigitalOut red(LED1);
DigitalOut green(LED2);
DigitalOut blue(LED3);


void menu();
void test1();
void test2();
void test3();

int main()
{    
    red=1;green=1;blue=1; // switch off led's
    switch3.fall(menu);
    menu();
}   

void menu()
{
    switch3.fall(NULL); // dissable IRQ   
    wait(1);   
        while(1){  // wait until switch pressed
                
            if (switch1==0) {test1();}
            if (switch2==0) {test2();}
            if (switch3==0) {test3();}
            
            wait(.1);    
        } 
} 

void test1()
{
    switch3.fall(menu); // enable IRQ
        while(1){
            red=!red;
            wait(.2);
        }   
}      

void test2()
{    
    switch3.fall(menu); // enable IRQ    
        while(1){
            green=!green;
            wait(.2);
        } 
}      

void test3()
{
    switch3.fall(menu); // enable IRQ   
        while(1){
            blue=!blue;
            wait(.2);
        } 
}      

Thanks guys, I have changed the code to use the interrupt to set a flag that allows the while() loops to break. I don't think I can make my ISR code much smaller :) This works, but I will look at using Timeout to look if switch3 is pressed, may be a better way to do this.

Interrupt test 2 working

#include "mbed.h"

DigitalIn switch1(PTA1);
DigitalIn switch2(PTD4);

InterruptIn switch3(PTA2);

DigitalOut red(LED1);
DigitalOut green(LED2);
DigitalOut blue(LED3);


void menu();
void test1();
void test2();
void test3();

int IRQ;

void IRQ_callback(void)

    {
      IRQ=1;        
    }    



int main()
{     
    menu();
}   


void menu()
{
    switch3.fall(NULL); // dissable IRQ we need switch3 to be non-interrupt durring menu routine
    red=1;green=1;blue=1; // switch off led's
    IRQ=0; //reset IRQ flag
      
    wait(1);   
        
        while(1){  // wait for switch function
                
            if (switch1==0) {test1();}
            if (switch2==0) {test2();}
            if (switch3==0) {test3();}  
        } 
} 

void test1()
{    
        switch3.fall(IRQ_callback); //enable IRQ on switch3 only
        
        while(IRQ==0){
            red=!red;
            wait(.2);
        }
        menu();   
}      

void test2()
{    
        switch3.fall(IRQ_callback); // enable IRQ on switch3 only
        
        while(IRQ==0){
            green=!green;
            wait(.2);
        }
        menu(); 
}      

void test3()
{      
        wait(.5); // delay just to allow for switch3 de-bounce befor enable IRQ
        
        switch3.fall(IRQ_callback); //enable IRQ on switch3 only
        
        while(IRQ==0){
            blue=!blue;
            wait(.2);
        }
        menu(); 
}      

Okay, this now works as before, but now returns to the main loop that breaks when IRQ==1, so we are left with no loops running. I then call menu() to restart the routine, is this the correct and/or simplest way to re-enter the menu routine? I have implemented these changes to my project program that runs as expected.

interrupt test3

#include "mbed.h"

DigitalIn switch1(PTA1);
DigitalIn switch2(PTD4);

InterruptIn switch3(PTA2);

DigitalOut red(LED1);
DigitalOut green(LED2);
DigitalOut blue(LED3);

void menu();
void test1();
void test2();
void test3();

int IRQ;

void IRQ_callback(void)
    {
      IRQ=1;        
    }
    
int main()
{     
    menu();
}

void menu()
{
    switch3.fall(NULL); // dissable IRQ we need switch3 to be non-interrupt durring menu routine
    red=1;green=1;blue=1; // switch off led's
    IRQ=0; //reset IRQ flag        
        while(IRQ==0){  // wait for switch function, now ends while loop when IRQ==1                
            if (switch1==0) {test1();}
            if (switch2==0) {test2();}
            if (switch3==0) {test3();}  
        }
/*

This works as well, but which is the preferred method, or does it matter?

         while(1){  // wait for switch function, breaks while loop when IRQ=1                
            if (switch1==0) {test1();}
            if (switch2==0) {test2();}
            if (switch3==0) {test3();}
            if (IRQ==1) break;  
        }
*/

      wait(.5); // allow for switch3 de-bounce 
      menu(); // resart menu() routine         
}
void test1()
{    
        switch3.fall(IRQ_callback); //enable IRQ on switch3 only        
        while(IRQ==0){
            red=!red;
            wait(.2);
        }          
}
void test2()
{  
        switch3.fall(IRQ_callback); // enable IRQ on switch3 only        
        while(IRQ==0){
            green=!green;
            wait(.2);
        }         
}
void test3()
{      
        wait(.5); // delay just to allow for switch3 de-bounce befor enable IRQ        
        switch3.fall(IRQ_callback); //enable IRQ on switch3 only        
        while(IRQ==0){
            blue=!blue;
            wait(.2);
        }        
}      


Code version 3 will still recursively call menu() and run out of memory at some point in time.

Right now the while loops of flashing LEDs are governed by the wait(0.2) anyhow and the loop does not get interrupted until the next 0.2s interval ends. You will need a different approach when the operations in the while run longer and you want to abort them immediately. In the current setup you dont even need interrupts. Here is a solution using only the switch test:

#include "mbed.h"
 
DigitalIn switch1(PTA1);
DigitalIn switch2(PTD4);
DigitalIn switch3(PTA2);
 
DigitalOut red(LED1);
DigitalOut green(LED2);
DigitalOut blue(LED3);
 
void menu();
void test1();
void test2();
void test3();
 
int main()
{     
    red=1;green=1;blue=1; // switch off led's

    while(1) {  // assuming this needs to run forever
        if (switch1==0) {test1();}
        if (switch2==0) {test2();}
        if (switch3==0) {test3();}  
    }
}

void test1()
{    
        wait(.5); // delay just to allow for switch1 to debounce

        while (switch3==1) {  // wait for switch3 pressed
            red=!red;
            wait(.2);
        }          
        wait(.5); // delay just to allow for switch3 to debounce
}
void test2()
{  
        wait(.5); // delay just to allow for switch2 to debounce

        while (switch3==1) {  // wait for switch3 pressed
            green=!green;
            wait(.2);
        }         

        wait(.5); // delay just to allow for switch3 to debounce
}
void test3()
{      
        wait(.5); // delay just to allow for switch3 to debounce
        while (switch3==0) {};  // wait for switch3 released because we want to use it again
        wait(.5); // delay just to allow for switch3 to debounce

        while (switch3==1) {  // wait for switch3 pressed
            blue=!blue;
            wait(.2);
        }        

        wait(.5); // delay just to allow for switch3 to debounce
}      
 
posted by Wim Huiskamp 07 Apr 2014

Thanks for the example Wim. In this test I'm trying to establish if I can end or break the while loop and restart it again when the menu function is needed later without keep stacking up loops and using more memory. I need to use interrupt in my project program to end a function and return to menu so I can select another function. But I think the answer is to have the endless loop in 'main' and break any other loops as the program runs so the program ultimately ends up back at 'main' where the menu function is recalled. I'm assuming that correctly 'breaking' a loop in one of my functions and ultimately ending back to the endless loop in 'main' will not stack up loops and consume memory. If I call a loop that has been previously broken using 'break' will that loop reuse the same memory. My Project program runs many individual functions that do not need to be run simultaneously, so I end each process with an interrupt to return to menu when I need to.

posted by Paul Staron 07 Apr 2014

2 Answers

10 years ago.

It starts a bit strange, with the main function enabling the interrupt, then calling menu() itself, which disabled it immediatly. In practise it is unlikely the interrupt is called in that very short timespan, so what happens is that menu() is executed just like it was in main() itself.

Once you press the button, one of the other functions is called, still just like it would be in main(). However these set the interrupt again, and wait until menu() is called by the interrupt. Once this happens, menu() runs again, but this time it runs as interrupt routine. It checks which switch is 0 (of course you only have one now), and runs the functions belonging to that switch, and it still runs as an interrupt. Now it sets the interrupt again, but an interrupt cannot interrupt itself. And it is now stuck in a while(1) loop as interrupt routine, where it will never be able to break out of.

Generally you also want your interrupt routine to be very short. You can lessen this issue by using a low priority interrupt, so others can interrupt the interrupt, but still. Another problem with doing it like this is that if your program is writing the display, and it gets interrupted and starts to write something else on the display, it probably does not end up like you want it to end up. You could consider RTOS, but you can also just let the interrupt set a flag, which is every time in the main loop checked.

I just add a comment .

Paul, I believe you have to find another approach to your goal. Your interrupt invokes menu() which has an infinitive loop, means it won't be interrupted by the equal/lower priority any more.

posted by Martin Kojtal 07 Apr 2014

Thanks for the explanation.

Yes it did start a bit strange Erik, I'm not sure what the adverse effect will be if any if I NULL the ISR before actually enabling it, perhaps none at all. Whilst this does now do the job, I'm still in two minds whether to try a different approach as Martin suggests, perhaps by using Timeout to call an ISR to test the swtich3 state, but that means more code in the ISR and I don't want to break printf functions half way through.

There is one other confusion I have with while() loops, if I jump out of while(1) loop to another routine, does the compiler see this as an End of loop? I have been doing this with most of my code with no problems encountered. But logically the while(1) loop effectively means indefinite so why does it not effect the program flow? I assume that because I have jumped out of the function or routine that contains the loop, the compiler sees this a break.

posted by Paul Staron 07 Apr 2014

When the interrupt ends, it will continue with the while(1) loop. Depending on how it is written it might start new loops until it runs out of memory. The only way to really leave a while(1) loop is calling break;.

posted by Erik - 07 Apr 2014
10 years ago.

The code is not correct and results in infinite jumps and memory issues:

snip

int main()
{     
    menu();
}   
 
 
void menu()
{
    switch3.fall(NULL); // dissable IRQ we need switch3 to be non-interrupt durring menu routine
    red=1;green=1;blue=1; // switch off led's
    IRQ=0; //reset IRQ flag
      
    wait(1);   
        
        while(1){  // wait for switch function
                
            if (switch1==0) {test1();}
            if (switch2==0) {test2();}
            if (switch3==0) {test3();}  
        } 
} 
 
void test1()
{    
        switch3.fall(IRQ_callback); //enable IRQ on switch3 only
        
        while(IRQ==0){
            red=!red;
            wait(.2);
        }
        menu();   
}      
 
snip

  1. main starts menu().
  2. menu runs in infinite loop and tests switches.
  3. when (switch1==0) it calls test1() but menu() REMAINS in its loop...
  4. normally, when test1() completes it will return to menu() and which continues in this infinite loop testing switches.
  5. However, at the end of test1() you call menu() AGAIN, which will start a new instance rather then return to the existing one..
  6. This goes on forever until you run out of memory (stack, return addresses..)

You should at least delete the renewed calls of menu() in your tests. They will automatically return to the still ongoing instance of menu() that called them to begin with.