ATMega System Clock Counter

Hi all,

in Teensy 4 there is a counter/register named ARM_DWT_CYCCNT which increases on the count of each system clock tick. This can be read and reset to 0. It also rolls over on it's own. I think it is 32 bits long.

Is there something similar for the atmega chips that allows me to count system clock ticks without having to resort to using the timers to do it?

Cheers

NM

Not system clock ticks but millis() or micros() might be what you are looking for.

The millis() is used for that. Since Timer0 does not run at 1kHz, there is a correction for millis(). The resulting millis() value is just as accurate as the 16MHz crystal or resonator, but with a little jitter because of the correction.

Arduino uses only Timer0 for millis(), the other timers can be used for precise timing.

Do you want a precise delay in clock cycles ? Some use a inline assembly "NOP" for a clock delay. There is also a function __builtin_avr_delay_cycles() to make the compiler generate "NOP" instructions (the compiler uses other instructions and loops for longer delays).

It's definitely system clock ticks i am looking for.

Where does millis() and micros() get their clock ticks from?

Cheers

NM

@Koepel

Ah, it uses Timer0. I guess i will just have to use a timer as well. I was hoping there might already be a system clock counter somewhere in the ATMega chips which i wasn't aware of yet.

Cheers

NM

Can you tell what your project is and what you need the timer for ?

We all use millis() in every situation.
It can calculate time up to 50 days.

If you have a board with a crystal (instead of a resonator) that is 1 minute inaccurate after a year, then you can make a clock with millis() and it will have exactly the same accuracy as the crystal.

Is this a XY problem ? There is a website for that: https://xyproblem.info/

Hi Koepel,

i want to test the time it takes (in clock ticks) for a particular piece of code to run. Partly as a way to refine the speed of my code but also to learn how long it takes for some common pieces of code to run. E.g. is an IF/ELSE statement faster than using a SWITCH/CASE statement. How much slower is it to divide than multiply etc

Thanks

NM

A timer can count the system clock, and the input capture pin can be used to timestamp events. See https://gammon.com.au/timers

It is the only way to do what you want on a AVR-based Arduino.

Thanks @jremington.

Will just use a timer then.

NM

How about toggling a spare pin to take timing measurements in your code?

Say we use pin 3 as a test-point, and allow 3 cycles to toggle using PORTD ^= (1 << PD3); then here we should measure 6.25μs and 62.5μs respectively...

void setup() {
  pinMode(3, OUTPUT);
}

void loop() {
PORTD ^= (1 << PD3);
__builtin_avr_delay_cycles(97);
PORTD ^= (1 << PD3);
__builtin_avr_delay_cycles(997);
PORTD ^= (1 << PD3);
}

The impulse is where the loop re-iterates (7-cycles) ...

Measurements...

WOKWi simulation

@nuttymonk Why would you need a hardware timer ? I don't get it.

@dlloyd That is not the single clock cycle pin toggle command.

The micros() is accurate at 4µs on a Arduino Uno.
I prefer to use millis() to measure time. If the function is very short, then I let it run thousand times.

unsigned long t1 = millis();
... piece of code ...
unsigned long t2 = millis();
unsigned long elapsed time = t2 - t1;

See my millis_measure_time.ino example, which can be tested in Wokwi: https://wokwi.com/projects/299335057012687368

[UPDATE]

This is the single clock cycle pin toggle command:

// This is only for ATmega microcontrollers.
// They have a pin toggle command that uses a single clock cycle.
//
// In Wokwi:
//   Right click this text for Command Pallette or press F1.
//   then search for 'assembly' en click to View the generate assembly code.
//   A new tab was created with "sketch.lst" with the assembly code.

void setup() 
{
  pinMode(3, OUTPUT);
}

void loop() 
{
  PIND = bit(PD3);                   // or (1 << PD3);
  __builtin_avr_delay_cycles(99);
  PIND = bit(PD3);
  __builtin_avr_delay_cycles(999);
  PIND = bit(PD3);
}

The sketch in Wokwi: https://wokwi.com/projects/337051554389426770.

The __builtin_avr_delay_cycles() does not always generate "NOP" instructions as the assembly code shows:

 __builtin_avr_delay_cycles(99);
 224:	81 e2       	ldi	r24, 0x21	; 33
 226:	8a 95       	dec	r24
 228:	f1 f7       	brne	.-4      	; 0x226 <main+0xc6>

Yeah, I know (I didn't say that) ... it toggles correctly and I allowed for the cycles. It embeds the bit location in the test-point width (in 62.5ns increments) which might be handy to identify multiple test points on a logic trace.

Timing:

I like micros() for the improved resolution (4μs) which doesn't have the jitter of millis().
When measuring time, millis() skips a beat at the meaning of life (42).

No. You can do it with a Timer but not without.

From Timer0.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.