Close

Measuring the unreliability of the ATTiny85's internal clock

A project log for TIRO Vibrating Watch

TIRO (Time is Running Out) is a watch that vibrates every few minutes to remind the user that time in this world is quickly running out.

accidentalrebelAccidentalRebel 03/07/2019 at 14:530 Comments

I've read it countless of times: the internal clock on the ATTiny85 is very unreliable. It's said that it's accuracy vary wildly depending on various factors like temperature and voltage.

I still wanted to test it out for myself. I wanted to find out just how unreliable it is. And if it is possible at all to do some hacks to it to increase the accuracy. What followed was a lot of lessons learned mixed with frustrations.

First, a brief overview of what my project is about. TIRO (Time is Running Out) is a simple wearable that vibrates every 5 minutes to remind the user of the passage of time. I don't need exact intervals between vibrations, since the timing does not need to be exact (The user won't be able to tell if the vibrations were late or early, anyway),

Before I began the experiments, I wanted to do some baseline tests. Note that the experiments were done multiple times but I've only picked out datasets that are important to us.

Legends: T1-T3 are the times when the vibrations started running. Tn is when the timing was already off by around 1 second. And Tx is the longest time I've let the circuit run for that trial.

This first iteration runs a motor for a duration of 0.5 seconds, waits 10 seconds using delay(), and then repeats.

Watchdog?Voltage Source
Trial No.
T1T2T3TnTx
No3.072 V
100:1000:2000:3002:3112:44
No3.072 V
200:1000:2000:3002:2102:41

The results are not showing too much promise as there is already a noticeable one second offset at around the 2 minute mark. The times as to when the offset happens also vary per trial which forced me to do multiple tries.

Later on I learned that the delay() function is not really suited for measuring delicate timings as it is a blocking function. I then updated my code to make use of millis() to determine how much time has passed before running the motor. The results were a bit more promising this time.

Watchdog?Voltage Source
Trial No.
T1T2T3TnTx
No3.072 V
100:1000:2000:3005:09-
No3.072 V
200:1000:2000:3004:39-

It's promising but still not enough. Plus, the offset is now negative instead of positive (05:09 instead of 05:11). I later figured out that maybe millis() was not granular enough so I made use of micros(), which showed a huge improvement.

Watchdog?Voltage Source
Trial No.
T1T2T3TnTx
No3.072 V
100:1000:2000:3026:41
36:51
No3.072 V
200:1000:2000:3021:4923:59

Now this makes sense. micros() is just more precise but it surprised me just how big the improvement was. I did these tests a couple more times and they have been somewhat consistent.

These results can already be considered good for my purposes. There would only be a noticeable offset of one second by around the 20 minute mark. By this time, a lot of time has already passed for the user to care.

The experiments does not stop here though. The current setup consumes a lot of power and it's not ideal especially since we'll be running it off a 3V CR2032 Lithium Ion battery. The answer is to use a watchdog timer as the delay when the circuit is not running the motor (The power savings are huge, from 0.97mA to 4uA. More here).

This part took a lot of tests from me that played around with different settings of the watchdog timer (i.e. Using 8s to 16us) the table below shows the most promising results out of the whole series of tests.

Watchdog?Voltage Source
Trial No.
T1T2T3TnTx
Yes
3.180 V
100:1000:2000:3006:01
24:02
Yes
3.180 V
200:1000:2000:3006:0123:02

You could say that the results got worse, but this is actually the best outcome out of all the iterations that I did. The reason for this is that the watchdog timer, in itself, is not really meant to be used this way. It definitely lessens the power consumption, but at the expense of the accuracy as it fires inconsistently. It's a classic catch-22 of accuracy vs lifespan.

I tried to do some tricks and hacks on the software side to try to make it as accurate as possible but all of them have failed. Different chips also show different results too which added more to the frustrations. It was at this point that I have accepted the fact that if I want accuracy, I have no choice but to use an external clock. Or I could just let it be.

The important thing for me is that I was able to test out personally just how unreliable the ATTiny85 internal clock can be. I might test out a circuit with an external clock in the future and compare the results. And after that, finally decide if my project is okay without it.

Discussions