Problem with micros() on Nano 33 BLE

It seems, that micros() on Nano 33 BLE does not refresh the underlying capture register inside loop(). I tested it with this program:

#include "Arduino.h"

void setup()
{
  SerialUSB.begin(115200);
}

int   incs;

#define PROGREP 1000000

void loop()
{
  unsigned long loopTime = micros();
  delay(1000);

  //------------------------------------------
    unsigned long startTime = micros();
    for(int i = 0; i < PROGREP; i++)
    {
      incs++;
      incs++;
      incs++;
      incs++;
      incs++;
      incs++;
      incs++;
      incs++;
      incs++;
      incs++;
    }
    unsigned long endTime = micros();
    unsigned long diffTime = endTime - startTime;
  //------------------------------------------

  SerialUSB.print(incs);
  SerialUSB.print(' ');
  SerialUSB.print(diffTime);
  SerialUSB.print(' ');
  SerialUSB.print(startTime);
  SerialUSB.print(' ');
  SerialUSB.println(loopTime);
}

I wanted to measure the run time of some code in a library and I did not get plausible results, always unexpected short times. So I made this test program with some simple code.
The result is, that diffTime does not depend on the code run time changed with PROGREP (loop of for...).
The only explanation I have: micros() is updated only outside loop() or in a function leaving loop()-area like delay().

A part of the output is:

...
255163520 11 2186469681 2185464000
265163520 11 2187476084 2186470464
275163520 11 2188482638 2187476937
285163520 11 2189488773 2188483489
...

diffTime always is 11 (or 12), independent from PROGREP (variations from 10 to 1000000).

Now I tried to access direct the registers of Timer1 (I found this timer is running on the board). It is the same effect. This is plausible, because you have to capture the counter value of the timer via a task-register before you can read the value out of the capture-register and if micros is "refreshed" outside loop(), that may be also the fact with using the task-register.

But strange is, that I have the same effect, if I do the capture by myself (writing 1 to the accordingly task-register) for another capture-register (I've chosen CC[2] because the content was always 0 before). The capture works, I can read the counter value out of CC[2], but it is the same value before and after my program under test. And this I do not understand.

The compiler is smart enough to know that the for loop can be replaced with a single incs += 10 * PROGREP statement which can be optimized to an addition of a constant value to incs. The addition operation and the calls to micros() probably adds up to somewhere between 11 and 12 microseconds.

1 Like

Yes, the call of micros() takes about 10 microseconds. But my original program under test was more complex. I will change this example accordingly.
Thank You for the hint.

A few minutes later:
Thanks a lot. I was wrong, though my original program under test was indeed more complex, there was the same "mistake" of the for-loop. With simply replacing the unsigned int by double and doing some extra calculations, the influence of PROGREP is as expected. And the world is OK again.
(So much to learn ... :blush: )

Next day
I did some investigations to measure the CPU speed: The shown routine does the task rather good if you us volatile int incs instead of just int incs.