Interrupt returning to top of loop

Hi all,

I’ve gotten my code to work but wondered if there was more efficient way of doing it? Basically at the end of the ISR I have called loop() to ensure that when the interrupt completes it returns back to the top of the loop rather than back to where it left off.

The purpose of the code is to have a button press change the mode / color of a strip of neopixels.

Any suggestions would be most welcome. Thanks in advance.

#include <Adafruit_NeoPixel.h>

#define neoPin 3
#define interruptPin 2
volatile uint8_t state = 1;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(35, neoPin, NEO_GRB + NEO_KHZ800);

void setup() {
  // put your setup code here, to run once:
  strip.begin();
  strip.show();
  Serial.begin(9600);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), stateChange, LOW);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("Top of loop");
  Serial.print("Case state = ");
  Serial.println(state);
  strip.clear();
  while (state == 1) {
    for (uint8_t i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, strip.Color(255, 0, 0));
      strip.show();
      delay(100);
    }
    strip.clear();
  }
  while (state == 2) {
    for (uint8_t i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, strip.Color(0, 0, 255));
      strip.show();
      delay(100);
    }
    strip.clear();
  }
}

void stateChange() {
  delayMicroseconds(50);
  Serial.println("Interrupt triggered");
  while (digitalRead(interruptPin) == LOW) {} // do nothing debounce
  if (state == 2) {
    state = 1;
  }
  else {
    state++;
  }
  Serial.print("State changed to ");
  Serial.println(state);
  loop();
}

Basically at the end of the ISR I have called loop() to ensure that when the interrupt completes it returns back to the top of the loop rather than back to where it left off.

Very bad idea. Your loop is not constructed to be called in interrupt context. But your interrupt handler has the same problem. You might end in a dead lock. Never call Serial.print() inside interrupt context as it's execution depends on interrupts being active and in interrupt context interrupts are disabled.

Also have a delayMicroseconds() call as the first thing in an interrupt handler shows you didn't understand yet, what interrupts are and how to use them. An interrupt handler must be as short as possible. Any delay call is not allowed (the exceptions from this rule should be left to people knowing exactly what they do).

Button press detection is so slow that you can do that in the loop without any need for interrupts. You just have to omit all delay calls there too (see example BlinkWithoutDelay).

And calling loop at the end of your interrupt doesn't do what you wrote but simply executes loop() once completely and then returns to where it left off.

The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Have a look at Using millis() for timing. A beginners guide if you need more explanation.

...R

Robin2:
The demo Several Things at a Time is an extended example of BWoD and illustrates the use of millis() to manage timing without blocking. It may help with understanding the technique.

Thanks very much. I'll take a look