17. Timing and Delays

The following timing and delay functions are designed for the Orangutans and 3pi robot, which run at 20 MHz. They will give different results at other processor frequencies. These functions are not available within the Arduino environment, which has its own delay functions.

The timing functions use a Timer 2 overflow interrupt (TIMER2_OVF), and Timer 2 is automatically configured when any OrangutanTime function is called. This means that the timing code will conflict with other code that uses Timer 2 in an incompatible way. However, the functions here are compatible with the other uses of Timer 2 within the Pololu library.

The Timer 2 overflow ISR is written in assembly to make it as short as possible. When the Timer 2 overflow interrupt occurs, your code will be interrupted for a total span of 2.65 µs (this includes the time it takes to jump into the ISR and the time it takes to return from it) once every 102.4 µs. Once every millisecond, the Timer 2 overflow ISR will take a little bit longer: 3.85 µs instead of the usual 2.65 µs. So in all, maintaining the system timers takes up approximately 2.5% of your available processing time.

General Note about Timers: The functions in Pololu AVR library will conflict with code that tries to reconfigure the hardware timers it is relying upon, so if you want to use a timer for some custom task, you cannot use the portion of the library that relies on that timer. The Pololu AVR library only uses Timer 0 for motor PWM generation, and it is only used for this purpose on the Orangutan LV, SV, Baby Orangutan, and 3pi robot, so the Orangutan SVP and X2 can safely use Timer 0 for any custom task. Timer 1 is used by OrangutanBuzzer for sound generation on all devices, and it is used by OrangutanServos for servo pulse generation on all devices. Timer 2 is used for motor PWM generation on all devices except Orangutan X2, and it is used by OrangutanTime to run the system timer on all devices. Additionally, the Orangutan SVP-1284 has a second 16-bit timer, Timer 3, that can safely be used for any custom task (the Pololu AVR library does not use Timer 3 for anything).

Reference

C++ methods are shown in red.

C/C++ functions are shown in green.

static void OrangutanTime::delayMilliseconds(unsigned int milliseconds)

void delay_ms(unsigned int milliseconds)

void delay(unsigned int milliseconds)

Delays for the specified number of milliseconds. Note that if the supplied argument milliseconds has a value of zero, this function will return execution immediately (unlike delayMicroseconds(0), which will delay for the maximum time possible of 65536 µs). Because this is a loop delay, the presence of interrupts will extend the delay period. For example, the Timer 2 overflow interrupt used by OrangutanTime to maintain the system timers will extend this delay period by approximately 2.5%, so if your system clock is 100% accurate, delay_ms(1000) will actually delay for approximately 1025 ms.

static void OrangutanTime::delayMicroseconds(unsigned int microseconds)

void delayMicroseconds(unsigned int microseconds)

void delay_us(unsigned int microseconds)

Delays for the specified number of microseconds. Note that if the supplied argument microseconds has a value of zero, this function will delay for 65536 us (unlike delayMilliseconds(0), which produces no delay at all). Because this is a loop delay, the presence of interrupts will extend the delay period. For example, the Timer 2 overflow interrupt used by OrangutanTime to maintain the system timers will extend this delay period by approximately 2.5%, so if your system clock is 100% accurate, delay_us(1000) will actually delay for approximately 1025 µs.

static void OrangutanTime::reset()

void time_reset()

Resets the system millisecond timer, but does not reset the system tick counter.

static unsigned long OrangutanTime::ms()

unsigned long get_ms()

unsigned long millis()

Returns the number of elapsed milliseconds since the first time an OrangutanTime function was called or the last time_reset() call, whichever is shorter. The value can be as high as the maximum value stored in an unsigned long, 4,294,967,295 ms, which corresponds to a little more than 49 days, after which it starts over at 0. Because the millisecond counter overflows on an even data boundary, differential millisecond calculations will produce correct results across the millisecond counter overflow.

static unsigned long OrangutanTime::ticks()

unsigned long get_ticks()

Returns the number of elapsed ticks (in units of 0.4 µs) since the first time an OrangutanTime function was called. The tick counter is not reset by time_reset(). get_ticks() can be used as a high-resolution system timer that will overflow back to zero after approximately 28.6 minutes of counting. Because the tick counter overflows on an even data boundary, differential tick calculations will produce correct results across the tick counter overflow. In order to take advantage of this property, it is important to always perform tick-to-microsecond conversions of the differential result, not the individual arguments of the differential calculation.

Example

// if the tick counter has overflowed once since we called prev_ticks = get_ticks(),
// the following call will result in a CORRECT measure of the elapsed time in us
unsigned long elapsed_time_us = ticks_to_microseconds(get_ticks() - prev_ticks);

// and the following call will result in an INCORRECT measure of the elapsed time in us
elapsed_time_us = ticks_to_microseconds(get_ticks()) - ticks_to_microseconds(prev_ticks);

static unsigned long OrangutanTime::ticksToMicroseconds(unsigned long num_ticks)

unsigned long ticks_to_microseconds(unsigned long num_ticks)

Returns the number of microseconds corresponding to the supplied number of ticks, num_ticks. One tick equals 0.4 µs, so 2.5 ticks equals one microsecond.