Possible uTimerLib bug (for MKR/SAMD21)

Naguissa/Folks,

I might have uncovered a bug in the (experimental) uTimerLib SAMD21 implementation.

The code below detected occasional callback-invocation intervals of roughly 1000 microseconds too short, with each short interval followed by an interval that is 1000 microseconds too long.

These incorrect interval-pairs occurred 7 or more times per 10,000 intervals.

I’m using the 1.1.2 version of the uTimerLib library… I installed it into the 1.8.9 version of the Arduino IDE, by using the IDE’s Library Manager tool.

Has anyone else seen this and/or developed a solution for avoiding the problem?

Is there a different library (for the MKR ZERO board) that I should try using while I wait for the uTimerLib to mature past its experimental stage?

Here is the code and some sample outputs:

#include "uTimerLib.h"

void setup()
{
  Serial.begin(9600);
  delay(5000);

  TimerLib.setInterval_us(metronome, 1998);  // 998 microseconds results in a 1000 microsecond average. 2 micros of overhead must be hiding somewhere.
 }

//=======================================================================================//
//=======================================================================================//
// Loop()
//=======================================================================================//

void loop()
{
}

//=======================================================================================//
//=======================================================================================//
// Metronome()
//=======================================================================================//

boolean first = true;
int invocationsCount = 0;
unsigned long previous = 0;
void metronome()

{
   unsigned long start = micros();
   if (!first)
   {
      invocationsCount++;
      unsigned long diff = start - previous;
      
      if ((diff <=1900) || (diff >= 2100))
      {
        Serial.print(invocationsCount);
        Serial.print(", ");
        Serial.println(diff);
      }
         

   }
   first = false;
   previous = start;
}

//=======================================================================================//
//=======================================================================================//
1161, 1000
1162, 3001
2661, 1000
2662, 3001
4161, 1000
4162, 3001
5661, 1000
5662, 3001
6927, 1001
6928, 3001
6930, 1001
6931, 3001
8053, 1000
8054, 3001
8058, 1001
8060, 3003
9434, 1000
9436, 3003
10582, 1001
10583, 3000
10591, 1001
10593, 3001
13010, 1001
13011, 3000
14139, 1001
14140, 3002
15215, 1000
15217, 3001
16210, 1001
16211, 3001
17155, 1000
17156, 3003
17159, 1001
17161, 3001
17162, 1001
17163, 3001
18039, 1001
18040, 3001
18863, 1000
18865, 3001
20097, 1000
20098, 3001
21212, 1001
21213, 3000
21217, 1001
21219, 3000
23527, 1001
23529, 3001
24690, 1001
24692, 3003
25785, 1000
25786, 3001
25796, 1000
25797, 3001
26890, 1001
26892, 3003
27987, 1000
27988, 3002
29091, 1000
29093, 3001
31170, 1000
31172, 3003
31177, 1001
31179, 3001
32256, 1000
32259, 3000
33399, 1000
33400, 3001
33404, 1001
33405, 3000
34552, 1001
34553, 3000
35689, 1001
35691, 3001
36729, 1000
36730, 3001
37880, 1000
37883, 3000
38943, 1001
38946, 3001

Is it the "uTimerLib by Naguissa" library that's available via Library Manager?

Metron_Ross:
Naguissa/Folks,
...
I'm using the 1.1.2 version of the uTimerLib library.. I installed it into the 1.8.9 version of the Arduino IDE, by using the IDE's Library Manager tool.
...

Uh, "Yes", that's the one.

Folks

For future readers ...

I think I found my problem. I wouldn't bet a paycheck on it, but I would risk at least a cold beverage.

My ISR (in the code above) calls a routine I called metronome. Inside metronome I call micros() and do some other stuff.

I think that when micros is called from inside an ISR (or from inside a routine called by an ISR) it isn't guaranteed to work.

I think that my ISR should have simply set a volatile boolean flag to notify loop() that an interrupt had occurred; and then loop() should have reset that flag, and then gone on to call metronome, etc. from within loop()'s context.

Information about micros() and ISRs from Arduino's documentation:
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

micros() works initially but will start behaving erratically after 1-2 ms

If your purpose is suggesting that this behavior is properly described, I have to differ - That’s the attachInterrupt() description, that happens to wander off into partially describing ISRs, and in that wandering happens to mention micros(). That’s not micros() documentation.

Why would anyone look under attachInterrupts() to find information about how micros() behaves?

Here is the information about micros(), and it says nothing about micros() failing inside of ISRs
reference/micros.

The description of micros() is one place where info about where the function can/can’t be employed, absolutely should be conveyed; especially since this behavior has tripped up plenty of other people in the past, and because changing the micros() page would be oh-so-simple to do.

I knew when I bought my inexpensive Arduino MKR hardware that bad documentation would be one of the problems I would face. That understanding was part of the compromise I made when I chose it. However knowing I would face it doesn’t make the problem any less frustrating when it affects my work.

YMMV

PS: If you just wanted to tell me that a pseudo-random chunk of the Arduino Reference information confirms what I figured out the hard way. Thanks.