HELP! Bizarre clock problem driving me nuts

Hi there

I'm having real difficulty with a clock project I've built, based on an Atmel 328. It's my first arduino project, so my inclination is to blame myself for any mistakes, but I am running out of ideas.

I'm using a DS1307 and the Wire library, and I'm able to set a time and read it back. The battery-backed standby function of the DS1307 is working fine, so it continues keeping time while the rest of the board is powered down.

In every way, the system is behaving as expected, except that, while the clock seems fairly stable, it is losing 3 seconds every minute!

This seems outside the range of normal accuracy problems due to things like excessive capacitance reported by others using the same setup, which are generally reported as seconds per day, or at most per hour.

Things I've already tried:

  • swapping the DS1307 with another from the same supplier
  • swapping the crystal with another from the same supplier
  • running the setup and time-polling sketch on an arduino 2009
  • running the setup and time-polling sketch on breadboard (with a separate 16MHz clock for the atmel)
  • powering it from the arduino
  • powering it from a separate power adapter fed through a 7805 Voltage regulator
  • checking the backup-battery voltage (3.3V measured vs 3V specified, but below the 3.6V limit listed on the datasheet)
  • soldering the components directly to each other (rather than using a breadboard) to avoid introducing capacitance
  • rewiring the circuit so that no other wires go near the crystal

The only remaining thing I can think is that the crystals are not putting out 32768 Hz. Losing 3 seconds per minute means the clock is running 5% slow, and 5% off of 32768 is about 30000.

Is there such a thing as a 30kHz crystal freely available?

I checked and these are the parts I ordered from SK Pang:

3 x 32.768kHz Crystal (XT32KHZ)
5 x Atmega328 IC (ATMEGA328)
3 x DS1307 I2C Bus RTC (DS1307)

The actual crystal is pretty non-descript, it's a tiny 7mm x 2mm silver "canister" with two very fine wires coming out, with the code JB01 printed on the side.

When I swapped out the components, I used the other ones from the same order since that's all I have to hand.

Does this sound like a plausible explanation? Is there any easy way to verify the clock rate (although I suppose that's what my circuit is doing anyway)?

The DS1307 part of the circuit is absolutely minimal, it has the crystal connected across pins 1 and 2, +3V battery input on 3, battery and Atmel ground on 4, data on 5 and 6, pin 7 is unused, Atmel +5V on pin 8. Not even any resistors, Wire activates the internal pullups (comms is working fine).

The code I'm using is as follows (includes the method I originally used to set the time):

#include "Wire.h"

#define DS1307_I2C_ADDRESS 0x68

// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}
  
void setup()
{
  Serial.begin(9600);
  Wire.begin();
}

// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
          byte *iminute,
          byte *hour,
          byte *dayOfWeek,
          byte *dayOfMonth,
          byte *month,
          byte *year)
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.send(0);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  *second     = bcdToDec(Wire.receive() & 0x7f);
  *iminute     = bcdToDec(Wire.receive());
  *hour       = bcdToDec(Wire.receive() & 0x3f);  // Need to change this if 12 hour am/pm
  *dayOfWeek  = bcdToDec(Wire.receive());
  *dayOfMonth = bcdToDec(Wire.receive());
  *month      = bcdToDec(Wire.receive());
  *year       = bcdToDec(Wire.receive());
}


// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second,        // 0-59
                   byte minute,        // 0-59
                   byte hour,          // 1-23
                   byte dayOfWeek,     // 1-7
                   byte dayOfMonth,    // 1-28/29/30/31
                   byte month,         // 1-12
                   byte year)          // 0-99
{
   Wire.beginTransmission(DS1307_I2C_ADDRESS);
   Wire.send(0);
   Wire.send(decToBcd(second));    // 0 to bit 7 starts the clock
   Wire.send(decToBcd(minute));
   Wire.send(decToBcd(hour));      // If you want 12 hour am/pm you need to set
                                   // bit 6 (also need to change readDateDs1307)
   Wire.send(decToBcd(dayOfWeek));
   Wire.send(decToBcd(dayOfMonth));
   Wire.send(decToBcd(month));
   Wire.send(decToBcd(year));
   Wire.endTransmission();
}

void loop()
{ 
  byte isecond, iminute, ihour, idayOfWeek, idayOfMonth, imonth, iyear;
  
  getDateDs1307 (&isecond, &iminute, &ihour, &idayOfWeek, &idayOfMonth, &imonth, &iyear);
  
  Serial.print("Time is ");
  Serial.print((int)ihour);
  Serial.print(":");
  Serial.print((int)iminute);
  Serial.print(":");
  Serial.print((int)isecond);
  Serial.println("");
}

void set()
{
   byte isecond, iminute, ihour, idayOfWeek, idayOfMonth, imonth, iyear;
 
  iminute = 24;
  ihour=21;
  isecond=0;
  idayOfWeek=4;
  idayOfMonth=23;
  imonth=9;
  iyear=10;

  setDateDs1307(isecond, iminute, ihour, idayOfWeek, idayOfMonth, imonth, iyear);
 
}

Any other ideas?

All suggestions appreciated.

Do you have pictures or schematic of your setup?

Yeah sorry, I should have posted this before. Wiring colour is just what I had to hand.

Grey-taped wires to the left are 7.5V input from old phone charger.

Red & black are 3.3V from a camera battery.

I should add that in the picture it looks like the atmel clock is touching the legs, in real life it does not but I've re-arranged the components now so that it is not adjoining.

Also forgot to mention that the output wiring is omitted, it connects some LEDs to the atmel output pins via resistors as usual when running as a clock.

The attached code is the debug version I run when the clock subcircuit is connected to the arduino - the real code has an additional method to light the leds, but the clock runs the same slow rate in both cases.

How often are you polling the clock?

I experienced the same issue, but noticed that it kept time correctly when the arduino was powered off (and hence not polling) and the clock was running on backup battery.

What happens if you try something like the following?

byte oldsecond = 0;
void loop()
{
  byte isecond, iminute, ihour, idayOfWeek, idayOfMonth, imonth, iyear;
  
  getDateDs1307 (&isecond, &iminute, &ihour, &idayOfWeek, &idayOfMonth, &imonth, &iyear);
  
  if (isecond != oldsecond) {
    oldsecond = isecond;
    Serial.print("Time is ");
    Serial.print((int)ihour);
    Serial.print(":");
    Serial.print((int)iminute);
    Serial.print(":");
    Serial.print((int)isecond);
    Serial.println();
  }
  delay(200);
}

Regards,

Dave

Thanks a lot for your responses, I will try them out this evening (newborn son permitting!).

I did test running on battery only, and it didn't seem to make any difference, but it's possible I wasn't paying enough attention (I was more concerned about the clock not resetting itself on battery). I'll repeat the test again.

As far as polling repeatedly is concerned, I did consider that what I was doing on the atmel might affect the DS1307, but then I read another thread about timing where the person was polling it as fast as possible with no effect on time keeping.

If I understand correctly, the code you have posted would prevent the slow serial output from the atmel taking up time from other events on the atmel itelf - I saw something similar with heavy serial logging noticeably dimming LEDs being powered from the atmel in a round robin.

I don't understand how it would affect the DS1307 itself though, if that is running independently? The "real" project, (versus the debugging testcase I posted here) does not do any serial logging and has the same problem. Unless it creates an excessive current draw or something?

Anyway, I'll try it out this evening also, it will definitely make the logging easier to read if nothing else!

So ultimately it turned out to be the clock crystal.

SK Pang sent me 30kHz crystals (3 of them) instead of what I ordered, which was 32.3268 ones. Given all the head scratching it's caused, I'm not sure I'll use them again in a hurry. I might drop them a line and see what they say.

I got some replacements today from a different vendor, swapped one out, and now my project keeps perfect time.

It did seem the only logical explanation before, but I still find it incredible.

Thanks for your suggestions, it's always good to know there's people willing to help out.

Jason