3
\$\begingroup\$

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 ) {
        }
}
\$\endgroup\$
1
  • \$\begingroup\$ It just occured to me that 16MHz/(256×2) is 32kHz. So Timer1 is clearly not being reset at OCR1A-match. I have to double check why that happens and if it is supported in the first place. \$\endgroup\$
    – jippie
    Dec 23, 2013 at 15:45

1 Answer 1

1
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\begingroup\$ Who added an extra register OCR1C while I was out to the supermarket!? \$\endgroup\$
    – jippie
    Dec 23, 2013 at 16:29
  • \$\begingroup\$ @jippie: At least it's not something utterly insane like using ICPx for CTC instead. \$\endgroup\$ Dec 23, 2013 at 16:31
  • \$\begingroup\$ Verified and works. \$\endgroup\$
    – jippie
    Dec 23, 2013 at 16:35
  • 1
    \$\begingroup\$ Those damned updates to the data sheets happen all the time, especially when out shopping. \$\endgroup\$
    – Andy aka
    Dec 23, 2013 at 17:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.