Timer 1 on ATtiny25/45/85 (CTC mode)

I'm currently trying to make a simple ISR that counts how many seconds have passed. I have to use Timer1 because Timer0 is used for PWM on my project and I can't swap pins that easily. For some reason Timer1 on the ATtinyX5 chips is really weird. This is my implementation but it doesn't work and I can't figure why. Has anyone experience on this?

The system is running at 16.5MHz (with V-USB -- disabled it for testing just in case). I used http://www.et06.dk/atmega_timers/ to calculate timer values.

DDRB |= (1 << PB0); // output
PORTB |= (1 << PB0); // high

OCR1A = 64453;            // compare match register
TCCR1 |= (1 << CTC1);   // CTC mode
TCCR1 |= (1 << CS13);    // 256 prescaler 
TCCR1 |= (1 << CS10);    // 256 prescaler 
TIMSK |= (1 << OCIE1A);
ISR(TIM1_COMPA_vect) { // also tried TIMER1_COMPA_vect
  PORTB ^= (1 << PB0);
}

Thanks!

Core?

I believe the ATtiny25/45/85 timer1 is an 8 bit timer. In CTC mode you don't use OCR1A as the top. Here's what the spec sheet says:

• Bit 7 – CTC1 : Clear Timer/Counter on Compare Match
When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00 in the CPU clock cycle after a compare
match with OCR1C register value. If the control bit is cleared, Timer/Counter1 continues counting and is unaffected
by a compare match.

Maybe you should try using OCR1C instead of OCR1A. And use a value that is less than 256.

For this testing I'm not using a core just to be sure nothing is messing with the Timers! I'm aware some cores use Timer1 for millis() and similar functions.

TanHadron:
I believe the ATtiny25/45/85 timer1 is an 8 bit timer. In CTC mode you don't use OCR1A as the top. Here's what the spec sheet says:

• Bit 7 – CTC1 : Clear Timer/Counter on Compare Match
When the CTC1 control bit is set (one), Timer/Counter1 is reset to $00 in the CPU clock cycle after a compare
match with OCR1C register value. If the control bit is cleared, Timer/Counter1 continues counting and is unaffected
by a compare match.

Maybe you should try using OCR1C instead of OCR1A. And use a value that is less than 256.

Yes. You are absolutely correct! I tried various values but nothing changed. I'm trying to make the ISR run at 1s intervals.

Should I just cheat and see how the ATtiny cores handle millis() etc using Timer1 or figure it myself? :stuck_out_tongue:

Abfahrt:
The system is running at 16.5MHz (with V-USB -- disabled it for testing just in case). I used http://www.et06.dk/atmega_timers/ to calculate timer values.

Abfahrt:
I'm trying to make the ISR run at 1s intervals.

Without actually trying it, I'm not sure this is possible. The largest clock prescaler is 16384, so with a 16.5 MHz system clock and using the overflow interrupt, the slowest the ISR could run would be

16,500,000 / 16,384 / 256 = 3.934 Hz

I might not use a web page that calculates ATmega timer values for an ATtiny.

Well, you probably can't get the hardware to call your ISR at one second intervals, but you could set up a counter in your ISR that calculates when a one second interval is, and calls your code accordingly.

I think the standard 328 core uses a FRACT calculation because it uses the standard 256 top and prescaler of 64. That doesn't divide evenly into 16,000,000. It's close to a millisecond, but not exact. So they have to calculate how far off it is every time so there isn't any drift.

If all you want is one second timer, you could set up your timer interrupt with a top of 250 and a prescaler of 8. Then you could count down to 20625 and your code would be called at exact one second intervals.

Yes you are correct.

TanHadron:
Well, you probably can't get the hardware to call your ISR at one second intervals, but you could set up a counter in your ISR that calculates when a one second interval is, and calls your code accordingly.

I think the standard 328 core uses a FRACT calculation because it uses the standard 256 top and prescaler of 64. That doesn't divide evenly into 16,000,000. It's close to a millisecond, but not exact. So they have to calculate how far off it is every time so there isn't any drift.

If all you want is one second timer, you could set up your timer interrupt with a top of 250 and a prescaler of 8. Then you could count down to 20625 and your code would be called at exact one second intervals.

Thanks! I'll try to implement this and post results.

TanHadron:
If all you want is one second timer, you could set up your timer interrupt with a top of 250 and a prescaler of 8. Then you could count down to 20625 and your code would be called at exact one second intervals.

I have setup the timer as you suggested. Prescaler 8, top 250. This is my ISR routine:

ISR(TIMER1_COMPA_vect) {
  if (counter == 0) {
	counter = 20625;
	PORTB ^= (1 << PB0);
  }
  counter--;
}

It seems that the LED is flashing with periods longer than ~2.5s (I'll have to get my multimeter to be sure). Can you please explain how you calculated 20625? 16500000/8 equals 2062500

EDIT: I got it! The ISR needs to count to 8250. That's 16500000/8/250! Thanks everyone :grin: