First off, a bit of a confession: I'm not using an actual Arduino Zero yet, but a homebrew version, so it is possible that I've messed up something there, however the other functions are working as expected so I'm a bit stumped by this one.
I need to use external interrupts to read a rotary encoder, but the interrupts are not working as expected. I've assigned the callbacks using the format used by the Due (a pin number assignment as opposed to an interrupt number such as in the Uno):
I also have an OLED working, and I'm doing some debugging by counting millis(). I can see that the timer is working until I use the encoder, which seems to freeze operation of the microcontroller (the timer stops counting). To be sure that execution is making it to the interrupt handler, I had it toggle the pin 13 LED, which it does before freezing. So it looks like probably that the interrupt is firing but hanging up there.
It has been pointed out to me that the Due suffers from a similar problem, as noted here and here. I've dug around the internals of the CMSIS library a bit and have tried to manually clear the interrupt flags in the handler (EIC->INTFLAG.reg = 0xFF;), but to no avail.
Might this be related to the problem on the Due and perhaps I'm clearing the flags in the wrong way? Any feedback from someone who has actually got external hardware interrupts working correctly on the Arduino Zero would be most appreciated.
Can you print the INTFLAG.reg value to the serial port from inside the ISR?
Is the CPU actually leaving and re-entering the ISR in loop, or is halting somewhere inside the ISR?
(if the LED is your only debug source, you should check it with a scope to see if it is toggling continuously or if it stays steady HIGH).
I will try printing that register to see what I can get from it. It appears that the proc is halting in the ISR from my crude debugging, but I haven't absolutely verified that yet. I've recently acquired an ATMEL-ICE, so I'll buckle down and learn how to use it with gdb to do some proper debugging. Thanks for the tips and I'll report back with what more I can find out.
OK, I think I've figured out the problem. My rotary encoder code was borrowed from code that works well on the Uno and the Leonardo, but as we all know, sometimes this stuff isn't as portable as we would like. I didn't have to get down to gdb debugging, as the use of some SerialUSB.print() statements and judicious use of commenting out lines led me to the cause of the problem.
It turns out that use of delay() inside the ISR was causing the freeze. I haven't dug into the internals to figure out why, but something in the Zero's implementation of delay() was messing with proper execution and return from the ISR. I can probably get away with just burning cycles in a while loop to implement the needed delay, as it doesn't have to be a precise time interval.
On a side note, I encountered an additional hitch that some of you may wish to be aware of. In this project, I am using the Serial1 class to read NMEA sentences from a GPS module at 9600 baud. When spinning the encoder knob quickly, the loop() function seemed to hang. What was odd is that the ISR was still firing, as it was printing SerialUSB debug statements from the ISR, and they would still print in the monitor. I'm not sure of the implications of this yet, but I doubt I'll be the last person bitten by this behavior.