multiple handlers for same interrupt

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi
is it possible to have multiple interrupt functions for the same interrupt? I'm working on an ap where I need all the speed I can get. So I'm trying to write a few different functions that use the same timer interrupt and use some sort of mechanism to select which one gets used during the initial setup. my best guess is that i have to change the interrupt vector during runtime somehow but I'm not sure if this is even possible.
Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Possible (I think) if your app supports the SPM instruction. You might be able to change the Interrupt vector in the flash via a routine in the bootloader, but doing so would wear out the flash very quickly.

Your best bet is to store the required ISR "state" as a mask in a GPIOR register or similar, then use masks or a switch case to choose the right handler code at runtime.

EDIT: What about having one lot of ISRs in the bootloader section, and the other in the app section? You could then use the flag in one of the MCU control registers to switch between the tables at runtime. Downside would be that you'd have to link the non-changing ISRs in the bootloader code to the ISRs in you app section somehow.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

i like the GPIOR idea not in the least because ive already got a flag variable.Is it quicker to access one of the general purpose registers than it is SRAM? If so how do i make sure my variable lives in one of those?
which is faster : an if else construct or a switch construct or would assembly give me better speed? my thinking is that its just a lookup table of functions.iI have roughly 12 clock cycles to play with idealy.I have no problem with jamming all the different operating modes into one isr but i have to make it select what its doing realy fast.
Dean ,I'm not sure i understand the edit think its a bit over my head. could you maybe elaborate a bit on that ?
thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Some of the more modern AVRs contain special registers named GPIOR0, GPIOR1, etc. which live in the IO space - thus you can use the same single cycle instructions to manipulate them as you would a port register. By assigning a different mask (so that only one bit is set) for each state you can then get your tests down to a single clock cycle per test.

To use the GPIORx registers in your code, just use them as you would an unsigned char. If you want a more app-specific symbollic name for them, use a #define:

#define FlagVar GPIOR0

Some AVRs also have the ability to contain a bootloader, a section of flash which can repogram the other section (to make a self-updating AVR for example). These AVRs then usually have a flag in one of the control registers (MCUCSR?) which can "move" the interrupt table from the application section to the bootloader section. While I've never really paid much attention to it, it may be possible to have two tables - one in your bootloader section and one in your app section - which can be swapped on the fly by setting or clearing the vector table location flag.

I can look into this further tonight when I get home from school. I'd say with such tight timing requirements and the fact that you need multiple ISR operations means you might need to go for a faster AVR.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I might be missing something here .. but why not just use a function pointer, which is called from the ISR, and make it point to another function as required ?

Something like :

void (*pFunc)(void); // function pointer

void func1(void)
{
  blabla
}

void func2(void)
{
  bleble
}

int main(void)
{
  pFunc = NULL;

  ...
  cli();
  pFunc = &func1;
  sei();
  ...
}

ISR(SOME_SIGNAL)
{
 if (pFunc)
   pFunc();
}

Warning: Untested code!

"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's not a bad idea, although you'd have the problem of the compiler then pushing and poping the entire register set, as it is unable to determine at compile time the used registers. No matter what approach the OP uses I strongly suspect a faster AVR will be required.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I suppose i should have mentioned this earlier :oops: but I'm running a mega16 at 16MHz, and using all of the I/O pins. At the time that the board was sent to the boardhouse i wasn't aware of anything with both enough pins and a higher clock rate. If i go into a second itteration of this project design I'll probably switch to a '644 which i believe goes to 20MHz.
From the register summary it doesnt look like i have a GPIORx register on the mega16.
how do i make program execution jump to wherever the function pointer is pointing?
i assume code should look something like this:

uint8_t *func1 ;
uint8_t *func2;
uint8_t func;
void func1(void);
void func2(void);

int main(void)
{
func1 = &func1();
func2 = &func2();
if (stuff)
    func = func1;
else
   func = func2;
//more code here
}

ISR(SOME_SIGNAL)
{
goto func;//this is pseudo code for assembly instruction i dont know yet
return;
} 

right?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This should work when using a function pointer, but I haven't tested it. (No assembly code needed.)

void (*cur_isr)(void);

void func1(void);
void func2(void);

int main(void)
{
    if (stuff)
        cur_isr = func1;
    else
       cur_isr = func2;
    //more code here
}

ISR(SOME_SIGNAL)
{
    cur_isr();
    return;
} 

I might be more inclined to use a switch statement in my ISR, however, since you've got some kind of timing constraints, and saving all the registers at the start of the ISR and restoring them at the end will eat a fair amount of cycles, as abcminiuser said. I'd try something like this:


enum { YELLOW, BLUE } cur_mode = YELLOW;

int main(void)
{
    if (stuff)
        cur_mode = YELLOW;
    else
        cur_mode = BLUE;
    //more code here
} 

ISR(SOME_SIGNAL) 
{
    switch ( cur_mode ) {
    case YELLOW:
        // this how we respond when yellow
        break;
    case BLUE:
        // this is blue code
        break;
    default:
        // uh oh
    }
}