[solved] ATtiny85 with 16MHz crystal: inaccurate timing

Dear all,

I want to turn my ATtiny85 into a little clock. I connected it to a 16MHz quartz crystal oscillator (with two 22 pF caps to ground). I connected an LED (with resistor) to PB1. I wrote AVR-C code that makes an LED turn on for 1 sec, every 60 seconds. I'll put the code below.

#define F_CPU 16000000

#include <avr/io.h>
#include <avr/interrupt.h>

uint8_t tickCounter = 0;
volatile uint16_t seconds = 0;


int main(void)
{
    uint8_t ledPin = ( 1 << 1);

    DDRB |= ledPin;                         // Set PB1 to OUTPUT

    TCCR0A = (1 << WGM01);                  // Set CTC (Clear Timer on Compare)
    OCR0A = 125;                            // Set No. of Ticks.
    TIMSK = (1 << OCIE0A);                  // Enable comparing with OCIE0A
    sei();
    TCCR0B = (1 << CS02) | (1 << CS00);     // start at 1024 Prescaler


    while(1)
    {
        if( seconds == 60 )                 // After a minute
        {
            seconds = 0;
            PORTB |= ledPin;                // Turn on ledPin
        }

        if( seconds == 1 && (PORTB & ledPin))   // if still on, one second later
        {
            PORTB &= ~ledPin;                   // turn ledPin off again
        }
    }
}

ISR(TIMER0_COMPA_vect)
{
    tickCounter++;
    if( tickCounter == 125)
    {
        seconds++;
        tickCounter = 0;
    }
}

I used a stopwatch to check the device. The LED should blink exactly once a minute. However, after some time, the LED was visibly lagging behind. I connected PB1 of the ATtiny85 to an arduino nano, and using a python script, I measured the time between the led blinks.

22:30:50.238706
22:31:50.723718
22:32:51.208745
22:33:51.693768
22:34:52.178787
22:35:52.663817
22:36:53.148838
22:37:53.632866
22:38:54.117888
22:39:54.602911
22:40:55.087935
22:41:55.572962
22:42:56.057985
22:43:56.543009
22:44:57.027030
22:45:57.512055
22:46:57.997080
22:47:58.482100
22:48:58.967125
22:49:59.452150
22:50:59.936176
22:52:00.421197
22:53:00.906221
22:54:01.391246
22:55:01.876270
22:56:02.361294
22:57:02.846319
22:58:03.330341
22:59:03.815367
23:00:04.300389
23:01:04.785417

Power source: 5V, Arduino nano
Temperature: 25.7 *C

The timer appears to be approximately 0.8% off. Interestingly, the internal oscillator of the ATtiny85 was also off with a similar percentage.

Of course, I could edit the code (eg: change the number of ticks) to make the clock more accurate. But I'm really curious why the timing appears to be off. Is there an error in the code? Is the hardware inaccurate? Do you guys have a hypothesis?

What is the low fuse set to?

I suspect it's set to use the pll clock (16 mhz derived from internal osc), not the crystal.

Either that or your code is messing up, but I didn't feel like reading it carefully enough to tell

DrAzzy:
What is the low fuse set to?

I set the fuses on the ATtiny85 by clicking "Burn bootloader" in the Arduino IDE. I didn't set them manually.

I tried to read the value of the low fuse using avrdude. I used the command

[color=grey]user@ubuntu~$[/color] avrdude -c stk500v1 -p t85 -P /dev/ttyACM0 -b 19200 -U lfuse:r:lowFusevalue:i

And then:

[color=grey]user@ubuntu~$[/color]cat lowFusevalue 
:01000000FE01
:00000001FF

I think this means the low fuse is set to 0xFE01 but I'm not completely sure.

The timer/counters are zero-based, so if you want to count 125 ticks, set (for example) OCR0A to 124.
Setting it to 125 results in somewhat less than 1% error. See the data sheet.

On the other hand, unless you use a precision crystal, even the most carefully coded example will probably gain or lose many seconds a day.

It means the value is FE

That's correct.

Problem is in you're code as jremmington said.

Your "second" is actually given by 125 * (1024 * (125 + 1)) / (16*10^6). So your crystal is off by about 84ppm. You could improve on that by selecting different capacitors (a little less capacitance). Or do it in software.

Bedtime reading: Gammon Forum : Electronics : Microprocessors : Timers and counters

Thank you guys! I changed OCR0A to 124 and now the clock is running a lot more accurately:

11:21:55.676366
11:22:55.681384
11:23:55.686407
11:24:55.689426
11:25:55.694453
11:26:55.699473
11:27:55.704499
11:28:55.709522
11:29:55.713547
11:30:55.718573
11:31:55.723596
11:32:55.728617
11:33:55.733642
11:34:55.737665
11:35:55.742691
11:36:55.747712
11:37:55.752733

As someone already foresaw, the minutes are not perfect yet (I calculated it would be off 7 seconds per day). But for now that is okay.

I appreciate you guys taking time to find the errors my code. Have some karma and thanks again :slight_smile: