First, a link to the code:
It's a little difficult to explain this. I'm not asking for the forum to just debug my code for me (well, I guess maybe I am), but I've had this issue for a few days now and cannot explain it.
TCC4+C5 are set up to be a 32 bit cascaded counter with capture The C4 clock is DIV1 and the C5 clock is event 4 (the overflow from C4). Event 0 is a PPS rising edge from a GPS module connected to pin C0. On the scope the edges are crisp and sharp. I would not expect any noise issue there. CCA for C5 results in a medium priority interrupt where the capture is read.
Outside the ISR, there is a need to read the current timer value. I have an inline function defined to do this which strobes event channel 1, waits for CCBIF to be set on both C4 and C5 and then reads the value.
Note that both in the capture ISR and in the place where the timer value is read are in ATOMIC_BLOCK(ATOMIC_RESTORESTATE) blocks. I've looked at the resulting assembly code and it's doing the right thing with that regard.
Here's the part I can't figure out. In the ATOMIC_BLOCK in MAIN, I obtain the value of "last_pps_tick" (that variable is declared volatile). That's where the capture ISR stores the captured timer value. That same ATOMIC BLOCK also fetches the current timer value. In some cases, the current timer value ("now") is LESS than the captured value, and the subtraction stored in current_tick winds up being a negative number.
None of that makes the least bit of sense. In the initialization code I set EV_DELAY on timer C5 to account for the overflow propagation delay - just like the Atmel application notes talk about. I've tried everything I can think of. The deltas between adjacent captures in the ISR are sensible - they are showing that the 32 MHz clock is running about 0x1000 ticks slow, which is about 128 ppm - inside of the FLL spec given the 32 kHz internal reference. The delta between adjacent calls to timer_value() show differences of around 0x50, which seems reasonable to me. Swapping capture channels A and B around makes no difference.
The mystery is complete.