Electronic – Help understanding AVR execution timing

avrclocktiming

I am working with an Atmel ATMEGA32U4 microcontroller – datasheet here with a 16 MHz crystal for system clock.

From my understanding, this chip has a 'Divide clock by 8' fuse programmed from the factory, effectively making my system clock 2 MHz. (Page 348 of datasheet. CKDIV8 (bit 7) default value is 0, programmed).

I would like to confirm my system clock speed, so I wrote some code to output a pin low, delay one clock cycle, and then put the pin high again. Measuring the time the pin is low should equal one clock cycle.

Here is the code I used to accomplish this:

//Set PORT E as output
DDRE = 0xFF;

asm volatile("nop\n\t"::); 
PORTE |= 1<<2;  

asm volatile("nop\n\t"::); 
PORTE &=~ (1<<2);   

asm volatile("nop\n\t"::); 
PORTE |= 1<<2;  

asm volatile("nop\n\t"::); 
PORTE &=~ (1<<2);

A 'nop' is equal to one clock cycle, according to the AVR instruction set manual, page 108.

Based on this information, I would assume a 'nop' instruction to take 500 nanoseconds.
Is this assumption correct? (16 MHz/8 = 2 MHz. \$\frac1{2MHz}\$ = 500ns)

Here is a scope plot of my findings:
enter image description here

It would appear a 'nop' execution time is only 200ns (5 MHz)
I would expect there to be some additional overhead using C to set the port high/low, so 500ns is actually the minimum time I would expect the pin to be low. But as you can see from my measurement cursors 'a' and 'b', its not even close to 500ns.

Can anyone explain whats going on?
Is there an error in my method?
Am I missing something 'face-palming-ly' stupid? :p
Thanks for any help!

Best Answer

This is a bad approach. Ideally you would measure a very large number of NOP commands - say, one million - instead of just one. I think that's the first foolish thing I can find. I would not be very surprised if your number changes right after you implement that change.

Also, can you view the disassembly of your C code? I wouldn't even try to judge the timing without seeing exactly what assembly code was generated from my C code. I would try to work backwards from the assembly to calculate what the execution time should be (via the instruction set manual you found). That way you can see if the scope measurement is off by a little or by a lot. A little might mean you made a math error. A lot might mean one of your assumptions is wrong.