Examination of the Arduino micros() Function

us clock

Background

To fully understand the micros() function, you first need to understand the Timer #0 overflow interrupt handler which was covered in this post.

Recall the typical Ardiuno runs on a 16MHz oscillator. Both the millis() and micros() functions base their calculations on the Arduino Timer #0, which is running with a prescale of 64. This results in the timer ticking at 64*1/16,000,000th of a second (which is 0.000004 seconds or evey 4 µs). Its important to take note of this because the resolution of micros() is therefore 4 µs.

Also recall that since the Timer #0 counter (TCNT0) is 8-bit, it “rolls over” or “overflows” after every 256 ticks. This means an overflow occurs every 1/16,000,000(oscillator) * 64(prescale) * 256(roll over) = 0.001024 seconds, or 1.024 ms, or 1024 µs.

Expand a Macro

Now, let’s do some additional math so we can substitute a number in the place of the following macro (this macro is embedded inside an Arduino hardware file):

#define clockCyclesPerMicrosecond () ( F_CPU / 1000000L )

F_CPU is the oscillator frequency, and is defined during compilation. We already know this is 16,000,000, which makes:

clockCyclesPerMicrosecond = 16,000,000/1,000,000 = 16

micros() Simplified

I’ve removed some housekeeping steps which check for the potential rare instance of an interrupt occurring during the micros() function call and substituted the expanded macro from above. What is left is simply the meat of the function, which calculates the elapsed microseconds:

unsigned long micros() {
  return((timer0_overflow_count << 8) + TCNT0)*(64/16);
}

Knowing all this boils the micros() calculation down to:

micros = (Timer #0 counter + (number of times timer #0 has overflowed * 256)) * 4

Actual Arduino micros() Function:

unsigned long micros() {
	unsigned long m;
	uint8_t oldSREG = SREG, t;
	
	cli();
	m = timer0_overflow_count;
#if defined(TCNT0)
	t = TCNT0;
#elif defined(TCNT0L)
	t = TCNT0L;
#else
	#error TIMER 0 not defined
#endif

  
#ifdef TIFR0
	if ((TIFR0 & _BV(TOV0)) && (t & 255))
		m++;
#else
	if ((TIFR & _BV(TOV0)) && (t & 255))
		m++;
#endif

	SREG = oldSREG;
	
	return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}

Do you wish you could read and write inline assembly code for the Arduino? Check out the book with greatly expanded coverage!

BookCover
[click on the image]

Advertisements

About Jim Eli

µC experimenter
This entry was posted in Uncategorized and tagged , , , , , , . Bookmark the permalink.

3 Responses to Examination of the Arduino micros() Function

  1. So the ‘micros()’ function itself already spoils the accuracy of the measurement? What’s the point then? (see my other post on FIXED POINT issue)

  2. Teo says:

    Hi. Is there any way I can modify this code to generate the number of nanoseconds since the arduino has started? Like an “nanos()” function…

    • Control says:

      Since a clock cycle will take 1/16.000.000 = 63 nanoseconds , the accuracy of your nanos function would be just 63 nanoseconds. I recommend to code your own functions with Timer0.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s