1
\$\begingroup\$

I have recently started programming an ATtiny85 microcontroller, which as per the datasheet runs at 10Mhz given 3v3 supply. So, to experiment, I have created a small program, as shown below.

#include <avr/io.h>

int main(void) {
    DDRB |= 8;
    while(1) {
        for(int i = 0; i < 1000; i++)
            for(int j = 0; j < 1000; j++)
                asm volatile("nop");
        PORTB ^= 8;
    }
}

As per documentation, each nop will take exactly one clock cycle to complete. Now, I have compiled this program using Atmel-Studio-7, and programmed the tiny using a usbasp clone and avrdude. As a side-note, the power supply jumper on usbasp is set to 3v3.

The programming worked fine, and I started looking at the blinking LED at pin-2 and it looked quite slow to me. When I measured the delay between LED toggles using a stop-watch, I could measure it to be exactly 5 seconds. As per my code, each time, 1000000 nops are executed before each toggle. By a simple calculation, it looks like my tiny could execute only 200000 nops per second, meaning it is running at 200Khz, which does not make any sense.

What could be the contributing factors to this error? How to estimate any microcontroller's clock speed by its output?

\$\endgroup\$
3
  • 1
    \$\begingroup\$ You are starting from a faulty assumption. Review the data sheet and you will see that default fuse settings enable a clock divider. \$\endgroup\$ – Chris Stratton Feb 8 '18 at 16:32
  • 3
    \$\begingroup\$ You know that not only you execute nops but also the code that takes care of the loop? unroll it or figure out if there is a cycle counter in your chip \$\endgroup\$ – PlasmaHH Feb 8 '18 at 16:36
  • 1
    \$\begingroup\$ The for loops actually generate branch instructions, and you have an increment instruction for j and i. Try to unroll the loop, you should get closer results. You should try to look at the disassembly to see the instructions generated, you would be surprised about how many clock cycles are wasted by your code. \$\endgroup\$ – lucas92 Feb 8 '18 at 16:47
10
\$\begingroup\$

Take a look at the compiler output here https://godbolt.org/g/TxZSgt. Notice that the inner for loop and the asm("nop") lines correspond to 3 assembly instructions, two of which (sbiw and brne) take two cycles (for brne when taken). So instead of taking one cycle per inner loop like you predicted, it takes 5.

And actually, if you multiply your measured clock frequency by 5, it comes out to 1MHz, which is the ATTiny default clock speed as per the datasheet.

The device is shipped with CKSEL = “0010”, SUT = “10”, and CKDIV8 programmed. The default clock source setting is therefore the Internal RC Oscillator running at 8 MHz with longest start-up time and an initial system clock prescaling of 8, resulting in 1.0 MHz system clock

\$\endgroup\$
2
  • \$\begingroup\$ This answer explains exactly what is happening. \$\endgroup\$ – Subin Sebastian Feb 8 '18 at 16:49
  • \$\begingroup\$ Thanks for the edit, couldn't find exactly where it was in the datasheet \$\endgroup\$ – C_Elegans Feb 8 '18 at 16:55
5
\$\begingroup\$

You can't test the speed of a microcontroller by measuring how long it takes to execute unknown numbers of instruction.

There is no guarantee what exact instructions the compiler generates from your code. Either look in some kind of machine code output listing, or write your test in assembler. Either way, you need to know exactly what instructions are being executed.

Once you know the instructions, add up how many cycles in the loop, and therefore how long each iteration should take. Only then can you make any conclusions about the instruction rate and clock frequency.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.