# Pin toggle speed

If I use direct port manipulation, what is the average number of clock cycles it takes to flip a pin on the arduino

ie.

``````void loop(){
PORTB |=  0b00010000;
PORTB &= ~0b00010000;
}
``````

So how fast is this generally?

• PINB = 0b00010000; or sbi(PINB, 4); will toggle the pin in a single instruction. Commented May 21, 2016 at 18:29

If you compile the code and examine the results you can see how many instructions it will take, and thus how many clock cycles.

It's slightly more complex because of what else happens in main() to call loop, but basically you have:

``````for (;;) {
loop();
aa:0e 94 49 00 call 0x92; 0x92 <loop>
if (serialEventRun) serialEventRun();
ae:20 97       sbi wr28, 0x00; 0
b0:e1 f3       breq.-8      ; 0xaa <main+0x10>

00000092 <loop>:
92:2c 9a       sbi0x05, 4; 5
94:2c 98       cbi0x05, 4; 5
96:08 95       ret
``````

So you can see there is:

``````Operation                            Cycles
Call loop()                          4
Check if serialEventRun exists       2
Since it doesn't, got start of loop  2
``````

Then in loop:

``````Set bit                              2
Clear bit                            2
Return                               4
``````

So in total you have 16 clock cycles. At 16MHz that gives you a frequency of 1MHz - however that won't be a square wave of 50% duty cycle since there is much less time between set and clear than between clear and set. The full 16 cycles, mapped to the state of the IO pin, would look like this:

``````             _
_ _ _ _ _ |   | _ _ _ _ _ _ _ _
| call  |sbi|cbi|  ret  |chk|bra|
. . . . . . . . . . . . . . . .
``````

You can get a much tighter operation by wrapping the pin manipulation in a `while (1)` loop:

``````void loop(){
while(1) {
PORTB |=  0b00010000;
PORTB &= ~0b00010000;
}
}
``````

That reduces down to just:

``````00000092 <loop>:
92:2c 9a       sbi 0x05, 4; 5
94:2c 98       cbi 0x05, 4; 5
96:fd cf       rjmp .-6      ; 0x92 <loop>
``````

That's `sbi` (2) `cbi` (2) and `rjmp` (2). A total of 6 clock cycles. At 16MHz that's 2.667MHz. Again, though, not a 50% duty cycle, since the `rjmp` takes two extra clock cycles:

``````     _
_ |   | _ _
|sbi|cbi|jmp|
. . . . . .
``````

By inserting a pair of 1-cycle `NOP` instructions you can even out the duty cycle and make it 50%:

``````void loop(){
while(1) {
PORTB |=  0b00010000;
asm volatile("nop");
asm volatile("nop");
PORTB &= ~0b00010000;
}
}

00000092 <loop>:
92:2c 9a       sbi 0x05, 4; 5
94:00 00       nop
96:00 00       nop
98:2c 98       cbi 0x05, 4; 5
9a:fb cf       rjmp.-10     ; 0x92 <loop>

_ _ _
_ |       | _ _
|sbi|n|n|cbi|jmp|
. . . . . . . .
``````

Now, of course, it's 8 clock cycles, so at 16MHz that's 2MHz output, but with 50% duty cycle.

Incidentally, all these instruction timings are available in the Instruction Set Summary chapter of the ATMega328P data sheet.