understanding more about interrupts

Hi-

I am using interrupts to read the changes on a rotary encoder and it's all working (yay!) but I want to understand more about how interrupts work so I can identify some issues with timing.

So..

--will an interrupt "interrupt" any function that is running, run the specified function for the interrupt, and then return to the function that was interrupted?

--is this true of for/while loops as well?

--I have a check in 'loop' to see if a motor (encoder) has reached a specified location. It occurred to me tonight that I might better put that check in the interrupt function since that would be closest (in time) to when the position event occurs. It's a simple check: if (encoderX >= targetX) so it won't suck up much time. Do I gain anything with this since 'loop' happens so frequently?

--speedwise, I've always heard that conditional statements are expensive so I am wondering if I can optimize my intrrupt function by reducing the number of conditionals- so there are two tests in the initial statement below (boolean AND). Would it be more optimized to do the first check, and then if that is true, do the additional checks? (the interrupt is set to trigger on CHANGE).

Anyway, details and refinements - but I'd be very interested in any tips (or warnings! ;-) anyone has about interrupts, esp. when driving DC motors.

tx!

--Roy

if ((XAstateLast == HIGH) &&  (XAstate == LOW)){
    //-----CCW
    if (XBstate ==HIGH){
      encoderXPos--;

    } 
    else  if (XBstate ==LOW){
      //-----CW
      encoderXPos++;

    }

  } 
  else if ((XAstateLast == LOW) &&  (XAstate == HIGH)){

    //-----CCW
    if (XBstate ==LOW){
      encoderXPos--;

    } 
    else  if (XBstate ==HIGH){
      //-----CW
      encoderXPos++;

    }
  }

Hi Roy, here are some quick answers to your questions:

will an interrupt "interrupt" any function that is running, run the specified function for the interrupt, and then return to the function that was interrupted? Yes

is this true of for/while loops as well? Yes, it will interrupt anything but another running interrupt handler

I have a check in 'loop'? do I gain anything with this since 'loop' happens so frequently? It depends on what you need to do when the check is satisfied and how much it matters if the check is delayed by a few microseconds. Generally it is best to have only minimal code in the interrupt handler and keep checks like the one you mentioned in loop.

speedwise, ?Would it be more optimized to do the first check, and then if that is true, do the additional checks? The C language the arduino uses is guaranteed to stop checking a conditional and statement when (and if ) any condition fails. Or statment checking will stop when any succeeds. It will do the checks in the order you write them so if there is one that is more likely to fail, put that first so the others won't be unnecessarily checked. Your sample code is probably as efficient as you can get it. Note that the check : else if (XBstate ==LOW){ is unnecessary because if XBstate is not HIGH it must be LOW, but I would guess that the compiler optimizer would recognize this and produce the same code as:

if ((XAstateLast == HIGH) &&  (XAstate == LOW)){
    //-----CCW
    if (XBstate ==HIGH){
      encoderXPos--;
    }
    else { //-----CW
      encoderXPos++;
    }
  }

One thing I came across re the question "will an interrupt 'interrupt' any function that is running?"--an interrupt will apparently not interrupt another interrupt routine. The interrupts do have a priority order but that only seems to apply to simultaneous requests (like when interrupts are enabled and there are more than one pending).

Doesn't sound like you're running more than one interrupt, but this one tripped me up when I wanted to run two timer interrupt routines concurrently. I wanted a "high priority" timer interrupt to keep an accurate clock, but it had to wait for the lower priority (and CPU intensive) interrupt to finish regardless.

Interrupts and CPU intensive really don't go together. If you need to do lots of processing based on an interrupt input, the best way to do it is to let your ISR (interrupt service routine) set a flag, then let your main event loop handle the actual processing based on that flag.

I realize there may be situations where you need to do lots of work in the ISR, but in general if you are doing lots of work in the ISR you need to take a step back and think about your problem again.

I don't know the internals of the AVR, but in general it is possible for an interrupt to interrupt an ISR. For this reason, on some processors it is sometimes practice to mask (ignore) other interrupts while you are servicing one. You especially don't want to have the same interrupt trigger while you're still in the ISR servicing the previous event on that interrupt.

-j

Well, relatively CPU intensive. I had one "high priority" timer interrupt to accurately count 5 usec intervals, and the other timer interrupt going off every 400 usec. The latter ISR took about 15 usec to complete, so while it was going, several 5 usec counts were missed. I was hoping that using a high priority for the 5 usec timer interrupt (timer 2) would cause it to interrupt the other ISR (timer 1), but that doesn't appear to be the way it works.

I don't know the internals of the AVR, but in general it is possible for an interrupt to interrupt an ISR. For this reason, on some processors it is sometimes practice to mask (ignore) other interrupts while you are servicing one. You especially don't want to have the same interrupt trigger while you're still in the ISR servicing the previous event on that interrupt.

On the ATmega168, interrupts are automatically disabled when an interrupt occurs, atlhough it is possible to explicitly enable them in the ISR if desired.

On the ATmega168, interrupts are automatically disabled when an interrupt occurs, atlhough it is possible to explicitly enable them in the ISR if desired.

Thanks everyone - this is all very helpful!

About interrupts being disabled when one is already occurring: my application is an XY plotter type project where I have an encoder on each axis. Since I am moving both axes at the same time, it seems entirely possible that an interrupt on one axis could be blocked because an interrupt on the other axis is occurring.

--does the blocked interrupt get queued or just not get handled at all? I am not doing anything CPU intensive in the interrupt function - just reading encoder pins and tracking changes in position. Is this a situation where I might want to try enabling interrupts to be interrupted? (and how might I do that?). With something like encoders would there be a situation of getting stacked up and something ugly occurring?

tx,

--Roy

--does the blocked interrupt get queued or just not get handled at all? I am not doing anything CPU intensive in the interrupt function - just reading encoder pins and tracking changes in position. Is this a situation where I might want to try enabling interrupts to be interrupted? (and how might I do that?). With something like encoders would there be a situation of getting stacked up and something ugly occurring?

Interrupts are stacked so pending interrupts will be handled in priority order when an existing interrupt routine is exited.

For every Arduino app I have ever read about , including yours, it should be no problem with the way interrupts are currently handled.

It is possible for a handler can set an interrupt bit high (the I-bit) to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine, but this is not something you want to play around with if you don't need to.

Isn't it the case that if two interrupts of a given type occur while another interrupt is processing, the first one will be missed? Good to know that a simple sei() will allow nested interrupts based on priority.

Isn't it the case that if two interrupts of a given type occur while another interrupt is processing, the first one will be missed?

Yes, there is a flag per interrupt type, so if more than one interrupt of the same type occurs, it is only processed once.