Electronic – ATtiny45 Timer1 clock misconfiguration

attinyavrctroubleshooting

I am overlooking something with a very simple program for my ATtiny45. A program that divides the 16MHz system clock by 16 and outputs that on pin 5 (OC0A) using Timer0 and on pin 6 (OC1A) using Timer1.

Pin 5 (Timer0) works as expected, I measure 1MHz.

Timer1 should be configured in a similar way, making pin 6 (OC1A) toggle at the same 1MHz frequency, but somehow this doesn't work as intended.

Pin 6 (Timer1) carries 32kHz. Even when I change the value for OCR1A, the frequency stays at 32kHz.

I know I'm overlooking something here, but I can't figure it out.

Here is the source code I use:

#include <avr/io.h>

#define _BS(bit) ( 1 << ( bit ) )
#define _BC(bit) ( 0 << ( bit ) )

/*
 * 1 PB5 !RESET
 * 2 PB3 XTAL1
 * 3 PB4 XTAL2
 * 4 GND
 *
 * 8 VCC
 * 7 PB2      SCK
 * 6 PB1 OC1A MISO
 * 5 PB0 OC0A MOSI
 */

void setup( void ) {
        /*
         * Setup timer0 for divide by 16 from system clock
         */
        TCCR0A =                                                // Timer/Counter Control Register A
                _BC( COM0A1 ) | _BS( COM0A0 ) |                 // COM0A[1:0]  = 01   - Toggle output pin on every match.
                _BS( WGM01 )  | _BC( WGM00 );                   // WGM0[1:0]   = 10   - Clear timer on Compare Match (Auto Reload)
        TCCR0B =                                                // Timer/Counter Control Register B
                _BC( WGM02 )  |                                 // WGM0[2]     =  0   - Clear timer on Compare Match (Auto Reload)
                _BC( CS02 )   | _BC( CS01 )  | _BS( CS00 );     // CS0[2:0]    = 001  - System clock, no prescaler.
        OCR0A  =                                                // Timer/Counter0 Output Compare Register A
                ( 16 >> 1 ) - 1;                                // System clock divider. The OC pin toggles on each match introducing an extra factor 2.
        TCNT0  =                                                // Timer/Counter0 
                0;                                              // Initialize counter to 0.

        /*
         * Setup timer1 for divide by 16 from system clock
         */
        TCCR1 =                                                 // Timer/Counter Control Register
                _BS( CTC1 )   |                                 // Clear Timer on Compare match
                _BC( COM1A1 ) | _BS( COM1A0 ) |                 // COM1A[1:0]  = 01   - Toggle output pin on every match.
                _BC( CS13 )   | _BC( CS12 )   |                 // CS1[3:0]    = 0001 - System clock, no prescaler.
                _BC( CS11 )   | _BS( CS10 );
        OCR1A =                                                 // Timer/Counter1 Output Compare Register A
                ( 16 >> 1 ) - 1;                                // System clock divider. The OC pin toggles on each match introducing an extra factor 2.
        TCNT1 =                                                 // Timer/Counter1
                0;                                              // Initialize couter to 0.
        /*
         * Enable output drivers
         */
        DDRB =                                                  // Data Direction Register B
                _BS( PB1 ) |                                    // Enable output driver for PB1/OC1A
                _BS( PB0 );                                     // Enable output driver for PB0/OC0A
}

int main( void ) {
        setup();
        while ( 1 ) {
        }
}

Best Answer

You need to configure timer 1 for CTC, set OCR1C to the max value you want for it, and then set OCR1A to the match value.

TCCR1 |= (
  _BV(CTC1) |   // CTC on OCR1C,
  _BV(CS12)     // System clock/8
); 
OCR1C = 2;      // Clear every 2 periods
OCR1A = 1;      // Match every 1st period

Set other bits as required for the application.