External Interrupt Always Running?

I'm tring to implement an external interrupt on D2 on a Nano 3.0/328 that does other things. When the interrupt is triggered, it calls Timer1. When I enable the interrupt to activate on a falling edge, I can no longer get ethernet communication working. Does the external interrupt continuously poll for the D2 pin change state? Is is possible to run other stuff (ethernet, LCD, timer stuff) when the interrupt has not activated?

I assume I just don't know what I'm doing. Any guidence on properly setting up the external interrupt so my other code will run correctly is appreciated.

Interrupt Activation Code (From Nick Gammon's site):

        pinMode(2, INPUT);       // Set Interrupt 0 (Pin 2) To Input Mode
    digitalWrite(2, HIGH);    // Enable pullup resistor     
    sei();                          // Enable global interrupts     

    //Gammon Code
    EICRA &= ~(_BV(ISC00) | _BV (ISC01));  // clear existing flags
    EICRA |= _BV (ISC01);    // set wanted flags (falling level interrupt)
    EIMSK |= _BV (INT0);     // enable it

ISR code:

ISR(EXT_INT0_vect) 
{  

    TCCR1A = 0;        // reset timer 1
    TCCR1B = 0;
    
 // set up Timer 1
  TCNT1 = 0;         // reset counter
  OCR1A =  g_timerCounter;       // compare A register value 
  TIFR1 |= _BV (OCF1A);    // clear interrupt flag
  TIMSK1 = _BV (OCIE1A);   // interrupt on Compare A Match  

}

For pin 2 you should use attachInterrupt.

ISR(EXT_INT0_vect)

I didn't list that interrupt vector on my page.

Does the external interrupt continuously poll for the D2 pin change state?

Not sure what you mean by "continuously poll". The hardware detects the pin change.

Is is possible to run other stuff (ethernet, LCD, timer stuff) when the interrupt has not activated?

Of course. It wouldn't be much use otherwise.

Perhaps show all your code.

Thanks, Nick. I've really been missing you. I didn't mean to accuse you of posting bad code!

I've got the code working with the attachInterrupt() function, so I must be setting up the interrupt incorrectly. Before I go through my code to post, can you tell me how much additional delay I would experience using this higher level C function? I'm scanning continuously moving film, so I want the delay as short as possible.

Nick, I just re-read you reponse and I see you advised the use of attachInterrupt(), so I guess I'm done. Do you know what kind of delay I would expect between the hardware triggering and the execution of the first line of the Interrupt Routine?

It's all documented here:

http://www.gammon.com.au/interrupts

Scroll down to "How long does it take to execute an ISR?".

A simple ISR takes about 1.4 uS to get going but the attachInterrupt ones take a bit longer (about 2.5 uS).

But film (movie film?) goes past about about 24 FPS, doesn't it? That would be 42 mS (not uS) per frame, so you would have plenty of time, surely?

Yes, there is plenty of time. I just need to know the latency for calibration issues. Because the film is continuously moving, any delay in the triggering will result in a small vertical offset of the image, as the LED shuttering will capture it in motion. As long as the delay is consistent, it won’t be a problem.

Does your Interrupt lesson discuss the +/- clock accuracy of multiple iterations of the external interrupt?

You can get perfectly consistent results (within a few nanoseconds) if you put the processor to sleep. Then the time taken to wake (from the interrupt) and start executing the ISR is always going to be a fixed amount.

I did that in this thread to draw to the VGA screen with no jitter between scan lines:

http://www.gammon.com.au/forum/?id=11608

Of course, with the processor asleep, you need to turn off timer interrupts or they might throw things out, but you could work around that.

If you don't do that, I mention in the interrupt thread there will be some jitter because of various factors.

When I enable the interrupt to activate on a falling edge, I can no longer get ethernet communication working.

I'm not sure if trying to do ethernet access and processing film at a precise rate will work, but it might.

Hi,

Unless I am mistaken its only timer0 that is going to cause a clash - a clash being one interrupt triggering while another is already being serviced leading to a lag while the first interrupt finishes before the second interrupt can be serviced.

So if I am correct wouldnt the easiest thing be to set the prescaler of timer0 to 0 effectivley switching it off - you will loose millis and micros but if your not using them, its a very quick and simple work around.

Duane B

rcarduino.blogspot.com

I think Timer0 is the only interrupt that is enabled by the init() function. You could turn off the interrupt (leave the timer running) and periodically check for an overflow. Maybe you don't need a timer. :)

OK, this is good stuff! If I put the Arduino to sleep, I have to figure out how to wake it up when I’m done capturing. I suppose the easiest way would be to create an interrupt on Pin 3, but I don’t have any extra digital pins available. What do you think about using an analog input pin as a flag that I can check at the end of my ISR for Pin 2. If the analog pin is set HIGH, I would not put Arduino back to sleep. That will leave the Arduino available for other code servicing at the end of the capture series. For the first capture, I could put it to sleep directly with an ethernet command.

What do you think?

I’m not sure if trying to do ethernet access and processing film at a precise rate will work, but it might.

Nick, I described that problem before I started using the attachInterrupt() function at your recommendation. Everything works fine now so long as I don’t attempt to make ethernet calls or do any other code servicing while the Arduino is servicing INT0. Since I write the Windows Application that interfaces with the Arduino, I can ensure that there are no extraneous calls.

renniejohnson: I have to figure out how to wake it up when I'm done capturing. I suppose the easiest way would be to create an interrupt on Pin 3, but I don't have any extra digital pins available. What do you think about using an analog input pin as a flag that I can check at the end of my ISR for Pin 2. If the analog pin is set HIGH, I would not put Arduino back to sleep. That will leave the Arduino available for other code servicing at the end of the capture series. For the first capture, I could put it to sleep directly with an ethernet command.

I didn't totally understand that. My visualization of your requirements can't be totally matching reality.

Having said that, you can use analog ports as digital ones if you want, and also you can wake on pin-change interrupts, which can occur on any pin on the 328.

Sorry Nick, articulation isn't my strength.

So, I can wake with analog 0. That solves that. Do I need to download the 'PinChangeInt.h' library, or can I create the PinChange interrupt with the Arduino 1.0 core library?

Thanks, Rennie

void setup() {
     // PCINT8 (pin A0) can trigger interrupt
    PCMSK1 |= _BV(PCINT8);

    // Enable pin change interrupts on PORTC
    PCICR  |= _BV(PCIE1);
}

ISR(PCINT1_vect) {
//....
}

If you want to just have your ISR wake the arduino up you might want to make it empty, so instead of saying ISR(...) you say

EMPTY_INTERRUPT(PCINT1_vect);

Sounds great. Two questions:

1) AmI correct in thinking the new interrupt mask will not defeat my Pin2 external interrupt routine.

2) This interrupt will trigger on a pin state change, right? So if I send 5v to the analog input, then run my INT0 routine, the PCINT8 interrupt will fire and wake the Arduino up when I set the input of analog 0 to 0v?

renniejohnson: Sounds great. Two questions:

1) AmI correct in thinking the new interrupt mask will not defeat my Pin2 external interrupt routine.

2) This interrupt will trigger on a pin state change, right? So if I send 5v to the analog input, then run my INT0 routine, the PCINT8 interrupt will fire and wake the Arduino up when I set the input of analog 0 to 0v?

yes yes. The interrupt will fire again when you go back form 0v to 5v unless you disable it

I'm having trouble getting out of sleep mode after the first iteration of the pin 2 interrupt. The way my film scanning exposures work is as follows:

1) When INT0 on Pin 2 goes low and the INT0 ISR executes, I configure and start Timer1 for a single timed output execution of Pin9 (Timer 1 hardware pin). This Timer 1 setup was primarily designed by Nick Gammon on this forum in response to a prior post of mine.

2) The first time the Timer1 ISR() is called, I stop the timer.

3) Each time that Timer 1 completes its single iteration, I want to put the Arduino to sleep to reduce ISR jitter, as advised by Gammon earlier in this post. However, the Arduino continues to sleep and doesn't respond when the next trigger on INT0 is received. If I comment out the sleep_mode() call, it works fine.

*THE CODE*

This function is called once to put the Arduino into a continuous capture mode on INT0:

int LED_V3::EnableInterruptExposure()
{
    pinMode (2, INPUT); 
    digitalWrite(2,HIGH);

    g_InterruptEnabled = 1;
    attachInterrupt(0, CaptureInterrupt, FALLING);

    //Set Sleep Mode For Continuous Capture
    set_sleep_mode (SLEEP_MODE_IDLE);

    //Put Arduino To Sleep
    sleep_mode ();
}

This is the ISR Function for INT0:

void    CaptureInterrupt()
{
  TCCR1A = 0;        // reset timer 1
  TCCR1B = 0;
  digitalWrite (PIN_EXPOSE, HIGH);   // ready to activate
  pinMode (PIN_EXPOSE, OUTPUT); 
    
 //Configure Timer 1
  TCNT1 = 0;         // reset counter
  OCR1A =  g_timerCounter;       // compare A register value 

  SetTimerMode (4, g_prescale, CLEAR_ON_COMPARE);
  
  TIFR1 |= _BV (OCF1A);    // clear interrupt flag
  TIMSK1 = _BV (OCIE1A);   // interrupt on Compare A Match  
}

Finally, this is the Timer 1 Interrupt Function:

ISR(TIMER1_COMPA_vect)         {
  TCCR1A = 0;        // reset timer 1
  TCCR1B = 0;
  gBusy=0;

  if(g_InterruptEnabled)
    sleep_mode ();
}
ISR(TIMER1_COMPA_vect)         {
  TCCR1A = 0;        // reset timer 1
  TCCR1B = 0;
  gBusy=0;

  if(g_InterruptEnabled)
    sleep_mode ();
}

Inside an ISR interrupts are disabled. Therefore it will never wake up.

Well, that sucks! Can you suggest how I might wake up the processor immediately after The Timer 1 ISR terminates?

Perhaps if you describe in more detail what you are doing? You have a timer, and an external interrupt. What is connected to what? What does the timer do?

Nick, I will compose an articulate response in the morning (California time). Please look for my post after breakfast tomorrow.

I appreciate everyone’s help.