With apologies for the format of this post if it is incorrect, I am trying...
I'm trying to use an external interrupt on my SAMD21 (Adafruit ItsyBitsy M0 and Arduino Zero) to gather input from a rotary encoder. Actually, I've used two approaches to getting the input (not at the same time of course); polling inside of loop() and attachInterrupt(). I started with polling, and performance was fine, if not perfect. But polling inside of loop() seems rather amateurish when I feel I should be using an interrupt. So I implemented with an interrupt, too. My problem is that the polling approach is actually better than the interrupt; i.e. polling does a better job capturing the input from the rotary encoder. Why?
How can I fix this? I really want to use the interrupt but it seems to be skipping some of the input. I've looked at some of the code that's out on the internet for programming interrupts at the 'bare metal' level, but frankly that code is way over my head. Is there something simple I can do to increase the frequency of the external interrupt trigger? Here's some code (the program itself is over 10,000 lines long, so I can only post some snips):
setup()
#if USE_EXT_INTERRUPTS
attachInterrupt( digitalPinToInterrupt( rotaryPin1 ), pollEncoder, LOW ); // setup the interrupts for the rotary encoder
attachInterrupt( digitalPinToInterrupt( rotaryPin2 ), pollEncoder, LOW ); // polling is more responsive
#endif
loop()
void loop() { // executes forever until reset button is pressed or power is interrupted
#if USE_EXT_INTERRUPTS == 0
pollEncoder(); // tried to use interrupts for the encoder but the results were inconsistent
#endif
ProcessEvent(); // process any events that might have occurred.
}
pollEncoder()
void pollEncoder() {
change = 0;
curModeA = digitalRead(rotaryPin1); // compare the four possible states to figure out what has happened
curModeB = digitalRead(rotaryPin2); // then increment/decrement the current encoder's position
if (curModeA != lastModeA) {
if (curModeA == LOW) {
if (curModeB == LOW) {
encPos--;
} else {
encPos++;
}
} else {
if (curModeB == LOW) {
encPos++;
} else {
encPos--;
}
}
}
if (curModeB != lastModeB) {
if (curModeB == LOW) {
if (curModeA == LOW) {
encPos++;
} else {
encPos--;
}
} else {
if (curModeA == LOW) {
encPos--;
} else {
encPos++;
}
}
}
lastModeA = curModeA; // set the current pin modes (HIGH/LOW) to be the last know pin modes
lastModeB = curModeB; // for the next loop to compare to
if (encPos < encPosLast) { // if this encoder's position changed, flag the change variable so we
if (encPos%4 == 0) { // know about it later
change = 1;
event = EVENT_ROTATE_CW;
}
} else if (encPos > encPosLast) {
if (encPos%4 == 0) {
change = 1;
event = EVENT_ROTATE_CC;
}
}
if (change == 1) {
encPosLast = encPos; // if an encoder has changed set encPosLast
}
}
It occurs to me as I post this that I should have two different pollEncoder methods (and maybe rename them); e.g. rotaryPin1Triggered() and rotaryPin2Triggered(), and that there's no need to read the input again from within the interrupt routine...perhaps this is part of my problem...