Why does the 16-bit timer reset at ~250?

Timer 1 (TCNT1) seems to reset at ~250 for some reason. Here's a graph showing TCNT1 plotted against the builtin LED's output (which toggles at TOP):

I have an Uno R3. I have timer 1 set to CTC mode with OCR1A being used for TOP. OCR1A = 0xFFFF. The prescaler is set to 1024. OCR1B = 0x7FFF and the interrupt bit for it is set. When its interrupt triggers, the LED gets toggled.

Here's my code:

ISR(TIMER1_COMPB_vect) { PORTB ^= bit(PB5); }

void setup()
{
   cli();
   TCCR1B = bit(WGM12) | bit(CS12) | bit(CS10); // CTC, clkio/1024
   TIMSK1 = bit(OCIE1B);                     // Compare B match interrupt enable
   
   TCNT1 = 0;
   OCR1A = 0xFFFF; // TOP
   OCR1B = 0x7FFF; // COMP B
   sei();

   DDRB |= bit(PB5); // Pin 5 output
   DDRC &= ~bit(PC0); // Pin A0 input

   Serial.begin(2'000'000);

   for (int x{ 500 }; x >= 0; --x)
   {
      Serial.print(analogRead(A0));
      Serial.print(' ');
      Serial.println(TCNT1);
   }
}

void loop(){}

Your code doesn't compile!

TCNT1 is the same IO address as TCNT1L so it prints just the lower byte of the counter. If you first assign the value to an uint16_t typed variable you probably get better results.

It looks as if the high byte is printed.

You're right, but that doesn't make sense to me.
But as the posted code doesn't compile it may be that OP changed other stuff too before posting.

It's this that keeps it from doing:

   Serial.begin(2'000'000);

change it to 2000000 and you good to go.

@glibg10b this

seems to reset at ~250

is a bit vague. Shouldn't be a matter of "seeming" and might it be 255 exactly?

a7

You still have bits set in TCCR1A from the Arduino timer presets for analogWrite().

You need to set TCCR1A to a defined value like you do with TCCR1B.

I know that but I expect posted code to compile unchanged, otherwise I assume the posted code wasn't used for actual tests.

Yes, prudence is not one of my stronger personality traits. :expressionless:

a7

The code does compile in C++14 and after (cppreference).

Turns out that init() (which is called by main()) sets bit 0 of TCCR1A. Because I set bit 3 in setup(), timer 1's mode is set to Fast PWM with TOP at 0x00FF. This explains why it clears at 255. Setting TCCR1A to 0 fixes the issue. I'll be writing my own main() from now on.

The compiler automatically deals with accessing TCNT1 in C/C++ code. From the datasheet:

Note that when using “C”, the compiler handles the 16-bit access.

And here's the assembly when setting it to 0:

sts     0x0085, r1
sts     0x0084, r1

Thanks @cattledog

Feel free to repeat errors that have been found by many other coders before you.
Feel free to ignore the great Arduino framework and examples and bypass it by your own buggy code.

I wonder what bug you invent next :wink:

@DrDiettrich Thankfully I only write code for my Arduino as a hobby and to learn more about electronics.

Besides, all main() does is set up the timers, ADC and disconnect the USART pins which get reconnected by Serial.begin() anyway.

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