2
\$\begingroup\$

I wrote this blink program for my ATtiny13A and tried to measure the accuracy with an Arduino Uno but the timer seems to be quite inaccurate. On the ATtiny I am running on the internal 128KHz clock and using timers to make pin0 high and low at a frequency of 1Hz.

Here is the ATtiny code:

int main(void){

  DDRB = 0;
  TCCR0A = 0;
  PORTB = 0;

  DDRB |= (1 << DDB0);      // pin0 output

  TCCR0A |= (1 << WGM01);   //CTC mode
  TCCR0A |= (1 << COM0A0);  //toggle OC0A on compare match

  TCCR0B |= (1 << CS02) | (1 << CS00); //1024 prescalar
  OCR0A = 124;              //1Hz @ 128KHz internal clock

  while(1){ 
  }

  return 0;
}

On the Arduino, I am using interrupts to measure the time between each high/low signal. It's a standard Uno with an external 16Mhz crystal. Here is the Arduino code:

unsigned long lastHigh = 0;

void setup() {
  Serial.begin(9600);
  const byte interruptPin = 2;
  attachInterrupt(digitalPinToInterrupt(interruptPin), myISR, CHANGE);
}

void loop() {
}

void myISR(){
  unsigned long temp = micros();    //store it ASAP to minimize delay
  Serial.println(temp - lastHigh);
  lastHigh = temp;
}

I have pulled the pin 2 on the Arduino to ground with a 1K resistor, and connected it to pin 0 of the ATtiny13A.

I was expecting to read a perfect 1s between each blink but here are my readings (in microseconds):

1063616 1062696 1063608 1062696 1063636 1062692 1063608 1062680 1063576 1062580 1063512 1062676 1063576 1062660 1063584 1062680 1063580 1062672 1063596 1062700 1063596 1062688 1063604 1062680 1063596 1062612 1063528 1062668 1063580 1062680 1063588 1062684

As you can see, the timer is not only ~60 milliseconds off, but it also jitters a lot.

I read on the internet that the internal clock is inaccurate but I'm not sure if ~60ms is too inaccurate or not.

Other than being off, the timings are also very jittery. They go from as low as 1062580 to as high as 1063680 microseconds.

I'm quite inexperienced and am really curious if this level of inaccuracy is considered normal or not. I found it odd because 1000us jitters make the micros() or _delay_us() functions quite useless.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Maybe your debug output causes that jitter. Serial.println() involves another ISR, which does the serial communication. Store the calculated difference value somewhere and do the serial communication in the main loop. That way you may loose some data points but the measurement itself isn't influenced by the serial communication. \$\endgroup\$
    – Janka
    Commented Oct 19, 2017 at 16:53

2 Answers 2

3
\$\begingroup\$

So, you're seeing about +6% deviation, and ±0.05% jitter.

The devation.

I couldn't find anything on the internal 128kHz oscillator, but the 4.8/9.6 MHz internal oscillator has a default accuracy of ±10% at a specified voltage and temperature. See section 18.4.1 (page 119) of the datasheet:

Table with oscillator calibration info

I suspect the 128kHz oscillator to be similar, so I suspect +6% is in-spec to me. You can calibrate the internal oscillator to get better accuracy, see Atmel appnote AVR053: Internal RC Oscillator Calibration for tinyAVR and megaAVR Devices.

You should also look at the way you're using the timer; You have no interrupt handler defined, so I believe you're causing a soft-reset of the tiny when the timer expires. This means any avr-glibc initialization code is re-run, as is your timer setup code. This will take some cycles and increase your cycle time, causing a positive deviation.

Try setting up an ISR which does the blinking, and see if that makes a difference. Or even try a calibrated delay loop instead of the timer.

The jitter.

As for the jitter, ±0.05% sounds like quite a lot to me. But to be honest, I'm not sure exactly how stable those RC oscillators are.

A significant suspect is your println() and serial transmit. println() has to do a fair bit of work converting your number to base-10, and the exact amount of work depends on the number being printed. Also, the serial transmit has to sync up with your computer and this may cause delays that are semi-random to your Arduino.

Try storing 20 or so measurements in memory and only using Serial.println() on them after all measurements are finished.

Also, I'm not entirely sure how accurate Arduino's micros() is. Maybe there's an accuracy problem there. If you have access to an oscilloscope, you could use that to measure the tiny's output frequency instead, cutting out the Arduino as a possible source of errors.

Update! LED power draw influences RC oscillator?

Aha, I noticed a pattern in your jitter! You are measuring 10636xx and 10626xx in an alternating fashion. So most of your jitter is a 1ms variation between even and odd cycles.

I suspect this may be because you're turning on an LED, which draws current, which affects the resonance in the RC tank used for the internal oscillator. That would be interesting.

Can you try repeating your original measurement run two more times, once without the LED, and once with?

If removing the LED makes the problem go away, you might want to use lots of decoupling on the tiny, and avoid having the tiny drive loads directly but always buffer outputs with transistors. If the clock accuracy is important enough for the situation, anyway.

\$\endgroup\$
4
  • \$\begingroup\$ Thank you @marcelm. I have tried defining an ISR but I've had the same result. I posted this example because it had the least amount of code. Regarding the println() issue, the Arduino is running at 16MHz and has 1 second between each blink of the ATtiny. Will the time required for println() still be relevant? \$\endgroup\$
    – Pouria P
    Commented Oct 19, 2017 at 17:18
  • \$\begingroup\$ @PouriaP Be sure to check the update to my answer (the third section), I might have found the problem ;) \$\endgroup\$
    – marcelm
    Commented Oct 19, 2017 at 17:23
  • \$\begingroup\$ @PouriaP Printing a number involves converting it to base-10, which requires repeated divisions by 10. Since the AVRs have no hardware divide, this has to be done in software, using many instructions. It may be relevant. \$\endgroup\$
    – marcelm
    Commented Oct 19, 2017 at 17:24
  • 1
    \$\begingroup\$ Yes! I removed the LED and the jitter went down to ~100us from ~1000. And after adding a capacitor between VCC and GND it went further down to about 50us(sorry I had forgotten to add it sooner). Though there is still a pattern just like the one you noticed, only smaller. It's unstable too. Like if I even move the breadboard slightly the jitter goes back to being bad. Maybe it's just extremely sensitive? \$\endgroup\$
    – Pouria P
    Commented Oct 19, 2017 at 18:46
1
\$\begingroup\$

6% error sounds reasonable for an uncalibrated on-chip oscillator.

In fact, Figures 19-65 and 19-66 on page 157 of the datasheet indicate that the frequency of the "128 kHz Watchdog oscillator" is not in fact anywhere close to 128 kHz!

If you want higher precision, you should at a minimum use the 4.8/9.6 "calibrated" oscillator, and perhaps do your on calibration on each unit. Once calibrated, it will stay within ±2% over temperature and voltage (see Table 18-2 on p. 119), and you can do much better if you can regulate one or both of those parameters.

\$\endgroup\$

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