When reading TCNT using a 2-cycle instruction (such as LDS), the simulation behaves differently than the silicone. The following code demonstrates the issue:
void setup() {
unsigned int value = 0;
cli();
TCCR2A = 0;
TCCR2B = 1 << CS10;
/* See the generated assembly code below */
TCNT2 = 0;
asm("nop");
value = TCNT2;
sei();
Serial.begin(115200);
Serial.print("Clock cycles: ");
Serial.println(value - 1);
}
// the loop function runs over and over again forever
void loop() {
}
Running this code in the simulation prints 1, while running it on a physical ATmega328p prints 2.
If you inspect the generated assembly code, you will see that it uses STS to set the value of TCNT2, then executes the NOP instruction, followed by an LDS to read the value of TCNT2:
STS 0x00B2, r1
NOP
LDS r12, 0x00B2
The LDS instruction takes 2 cycles to execute, and it seems like the counter is still incremented on the first cycle, before being copied into the register during the second cycle.
When reading TCNT using a 2-cycle instruction (such as
LDS
), the simulation behaves differently than the silicone. The following code demonstrates the issue:Running this code in the simulation prints
1
, while running it on a physical ATmega328p prints2
.If you inspect the generated assembly code, you will see that it uses
STS
to set the value ofTCNT2
, then executes theNOP
instruction, followed by anLDS
to read the value ofTCNT2
:The LDS instruction takes 2 cycles to execute, and it seems like the counter is still incremented on the first cycle, before being copied into the register during the second cycle.