Calibrating the internal oscillator (on an ATMega8)

I'm fairly new to microcontrollers, so forgive me if I should know where to look (or how to read the data sheet!) to find this out.

I bought a couple of cheap ATMega8s (ATMega8-PU16s to be exact) of vague provenience that I believe have never been used. I'd like to put them to use. I'm trying to use them with the 8MHz internal clock, without an external crystal or oscillator. I'd like to calibrate the clock; it's /really/ off at the moment. Serial communication doesn't work at all, and I believe bad calibration of the clock is the cause.

I know that buying a crystal would be cheap, I'm intellectually curious though (and besides, I always like to be efficient with resources :slight_smile:

I can load the blink sketch using an arduino-as-an-ISP (http://arduino.cc/en/Hacking/Programmer). If I then wire up the chip in a breadboard and watch its blinking LED in comparison with a real crystal-timed Arduino sitting next to it, it drifts noticeably within in about 10 seconds. The drift is certainly not enough that the clock rate is 'wrong' - it's not 4MHz or anything orders of magnitude out like that, it's obviously /about/ right, but it still seems like a lot of drift, and is surely what's causing my serial communication errors.

How can I calibrate the oscillator? I understand I need to set the clock calibration fuse bits, but I'm having trouble working out how. I'm 'comfortable' using avrdude, if that's the route to doing it.

History:
I've got an optiboot built to use the 8MHz internal oscillator burnt onto them with ArduinoISP, and an appropriate boards.txt (thanks to these posts: [SOLVED] Bootloader for ATmega8 with internal oscillator doesn't work. - Microcontrollers - Arduino Forum)

I'm quite sure this has worked correctly - in a breadboard Arduino setup they start up and blink the LED three times, and reset themselves when I start programming (I know this is just controlled by the pin, not the bootloader, but it at least means that they should be ready to receive the program, right?).

I can't, however, communicate with them over serial to upload sketches. I get the "stk500_recv(): programmer is not responding" error. I know I'm using the correct baud rate, because I built the bootloader with the settings that I've also placed in boards.txt.

th_in_gs:
I'd like to calibrate the clock; it's /really/ off at the moment. Serial communication doesn't work at all, and I believe bad calibration of the clock is the cause.

unless you got some culled rejects i suspect there may be more to the serial problem than off frequency internal clk. they spec 10% error but in my experience nearly all of them are close enough out of the tube.

regarding calibration there are some atmel app notes for that. i dont have links handy but google is your friend. for my own uses which are majority internal clk i calibrate by hitting return at 9600 and storing the value in ee. in actual fact results in far better reliability than with a crystal.

How can I calibrate the oscillator?

Poor Man's Tiny Tuner... Poor Man's Tiny Tuner - Exhibition - Arduino Forum (uses a TTL serial adapter; any Arduino will work)

I can load the blink sketch using an arduino-as-an-ISP...

Then allow me to introduce you to the recently released version 2 of Tiny Tuner... Google Code Archive - Long-term storage for Google Code Project Hosting. (uses TinyISP - a replacement for ArduinoISP)

Some information here...
http://forum.arduino.cc/index.php?topic=173408.0
http://forum.arduino.cc/index.php/topic,127690.0.html

Do you actually need to use a bootloader? If you have Arduino-as-an-ISP working, why not continue using it?

john1993, I fear you're telling me something useful, but I don't have enough domain knowledge to know what it means. "i calibrate by hitting return at 9600 and storing the value in ee" - I'm not sure what 'hitting return' refers to here.

Coding Badly though - thanks, that was really useful! I started out trying Tiny Tuner 2, but it looks like it relies quite heavily on TinyCore, which doesn't seem to be ported to the ATmega8? I therefore looked at Tiny Tuner (1). It also wasn't ported, but being self-contained, it was pretty easy to get it working with the help of a data sheet. An extra:

#elif defined( __AVR_ATmega8__ )
    typedef TinyTunerTemplate<0x10,0> Mega8Tuner;
    typedef Mega8Tuner TinyTuner;
#else

in TinyTuner2.h, and a #if defined( CLKPR ) around the references to CLKPR were all it took, IIRC. I then modified the "Save_to_EEPROM" sketch (the serial communication broke down so early that it didn't even get through the headers on the interactive ones!) as so:

/*==============================================================================

  Copyright 2010 Rowdy Dog Software.

  This file is part of TinyTuner.

  TinyTuner is free software: you can redistribute it and/or modify it under
  the terms of the GNU Lesser General Public License as published by the Free
  Software Foundation, either version 3 of the License, or (at your option)
  any later version.

  TinyTuner is distributed in the hope that it will be useful, but WITHOUT 
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
  License for more details.

  You should have received a copy of the GNU Lesser General Public License 
  along with TinyTuner.  If not, see <http://www.gnu.org/licenses/>.

  Inspired by the work of oPossum (Kevin Timmerman)...
  http://forums.adafruit.com/viewtopic.php?t=5078

==============================================================================*/

/*==============================================================================

  The purpose of this example is to determine the optimal calibration register 
  value based on input from a serial port and store the value at EEPROM 
  address zero.

================================================================================  

  ATtiny84 Instructions...
  
  - Select the correct board / serial port
  
  - Upload this Sketch to the processor
  
  - Connect PB1 / Pin 1 to transmit on the serial converter
  
  - Connect an LED + resistor --> ground on PA6 / Pin 4
  
  - Start your favorite terminal program, open the correct serial port, change
    the baud rate to 9600
    
  - Reset the processor
  
  - Continue sending single 'x' characters (no carriage-return; no line-feed)
    until the LED glows solid.  As each 'x' is sent, the LED should blink.
    
  - The calibration register value is stored at EEPROM address zero

================================================================================  
    
  ATtiny85 / ATtiny45 Instructions...
  
  - Select the correct board / serial port
  
  - Upload this Sketch to the processor
  
  - Connect PB4 / Pin 4 to transmit on the serial converter
  
  - Connect an LED + resistor --> ground on PB0 / Pin 0
  
  - Start your favorite terminal program, open the correct serial port, change
    the baud rate to 9600
    
  - Reset the processor
  
  - Continue sending single 'x' characters (no carriage-return; no line-feed)
    until the LED glows solid.  As each 'x' is sent, the LED should blink.
    
  - The calibration register value is stored at EEPROM address zero
  
==============================================================================*/

#include <EEPROM.h>
#include <TinyTuner.h>
#include "s2eLed.h"

#define PinLED 13

void setup( void )
{
  pinMode( PinLED, OUTPUT );
}

void loop( void )
{
  TinyTuner tt;
  bool KeepGoing = true;

  digitalWrite( PinLED, HIGH );

  while ( KeepGoing )
  {
    KeepGoing = tt.update();

    digitalWrite( PinLED, LOW );
    delay( 100 );
    digitalWrite( PinLED, HIGH );
    delay( 100 );
  }
  uint8_t Temp = OSCCAL;
  EEPROM.write( 0, Temp );
  
  Serial.begin( 9600 );
    

  
  if ( EEPROM.read(0) == Temp )
  {
    digitalWrite( PinLED, HIGH );
    
    while(1) {
      Serial.print( "OSCAL = " );
      Serial.print( OSCCAL, HEX );
      Serial.print( "\r\n" );
      delay(1000);
    }
  }
  else
  {
    digitalWrite( PinLED, LOW );
  }
  while ( 1 );
}

connected up on a breadboard in the usual arduino-like circuit, and I got a calibration value out - and stable serial communication at last!

That brings up some more questions though. It looks to me from the data sheets that the calibration value in the "signature row" is not re-writable, even with avrdude? Which means that OSCCAL must be re-written manually after startup?

If I'm correct here, I guess I'd need to modify the bootloader to be able to have stable serial communication with the Arduino IDE?

In that case, I think you're right and I may as well just continue to use Arduino-as-an-ISP. My application isn't even that timing sensitive, so I suppose I don't even actually need to calibrate the oscillator if that's the case!

Still, I've learned a lot - thanks for all your help!

th_in_gs:
I started out trying Tiny Tuner 2, but it looks like it relies quite heavily on TinyCore, which doesn't seem to be ported to the ATmega8?

Correct. Sorry about that.

You are the second person who uses Tiny Tuner on "unsupported" processors. I will have to take a stab at keeping version 2 independent.

I therefore looked at Tiny Tuner (1). It also wasn't ported, but being self-contained, it was pretty easy to get it working with the help of a data sheet.

Good job! And thank you for the follow-up.

connected up on a breadboard in the usual arduino-like circuit, and I got a calibration value out - and stable serial communication at last!

Excellent.

It looks to me from the data sheets that the calibration value in the "signature row" is not re-writable, even with avrdude?

Correct.

Which means that OSCCAL must be re-written manually after startup?

Also correct.

If I'm correct here, I guess I'd need to modify the bootloader to be able to have stable serial communication with the Arduino IDE?

Yes.

Still, I've learned a lot - thanks for all your help!

You are welcome!

th_in_gs:
john1993, I fear you're telling me something useful, but I don't have enough domain knowledge to know what it means. "i calibrate by hitting return at 9600 and storing the value in ee" - I'm not sure what 'hitting return' refers to here.

probably same thing as the 'x' in tuner from badly. only start bit is measured instead of the whole character. couple dozen lines of asm but i wish i knew about tuner and arduino back then. would probably have saved me hours of pecking away and debigging.