Trouble with both DS1307 and DS3231 RTCs and time slowing down

It's good news that there is no problem with the RTC and the slowing of timekeeping is somewhere in your code.

I'm not clear about how you handle the "storedTime".

// the function to get the time from the RTC
  // I have changed to using a DS3231
  setSyncProvider(RTC.get); 
  setSyncInterval(3600); // resyn interval (3600 = seconds in one hour, 86400 = seconds in one day)
  //to help with showing the time on the LED display
  storedTime.Hour = hour();
  storedTime.Minute = minute();

Then there is more code before

RTC.write(storedTime);

Was this RTC.write or the section in between commented out in your test?

I don't understand why you are resetting the RTC at this point.

cattledog:
It's good news that there is no problem with the RTC and the slowing of timekeeping is somewhere in your code.

I'm not clear about how you handle the "storedTime".

// the function to get the time from the RTC

// I have changed to using a DS3231
 setSyncProvider(RTC.get);
 setSyncInterval(3600); // resyn interval (3600 = seconds in one hour, 86400 = seconds in one day)
 //to help with showing the time on the LED display
 storedTime.Hour = hour();
 storedTime.Minute = minute();




Then there is more code before



RTC.write(storedTime);




Was this RTC.write or the section in between commented out in your test? 

I don't understand why you are resetting the RTC at this point.

Lets see.

The variable "storedTime" is used to see if the time has changed (minute-wise), so that the 4 digit 7-segment LED can be informed to update to the new time.

There are two instances of RTC.write in the code. The first is always commented out as it is only used if I want to set the time on reseting the Arduino. The second instance is used when you want to manually set the RTC time via the buttons on the clock.

Cheers for your input though

Hi all,

so I have been running my modified program with no I2C code in-place for 2 months now, and the time on my clock has been perfect. However, today, after having time to myself after moving house and revising for exams (now over thankfully) I have introduced the I2C code again, and straight away the clock is 7 seconds slow. Very strange. So I still need to fix the issue of using I2C and this affecting the time. Any ideas?

Also, I read elsewhere, a few months back, that Nick Gammon wrote an alternative I2C library. However, I cannot find it again. Could someone point me in the right direction?

Regards

Which RTC library you are using right now? Please share the link.
It is a very strange behavior as 3231 has temperature compensated crystal and is very accurate.

irishcream24:
I have introduced the I2C code again, and straight away the clock is 7 seconds slow. Very strange. So I still need to fix the issue of using I2C and this affecting the time. Any ideas?

This is confusing to me, because I am not aware of a way to communicate with a DS3231 (I think this is the RTC being used) without using I2C. That being the case, please explain what you really mean, and also how was the RTC interfaced before "introducing the I2C code again"?

Also, I read elsewhere, a few months back, that Nick Gammon wrote an alternative I2C library. However, I cannot find it again. Could someone point me in the right direction?

Maybe Nick will comment, I am not aware whether he wrote an alternate I2C library. I am aware that he linked an alternate library:

Having said that, I can't say that I've ever experienced the issues mentioned with the Wire library, and I use RTCs and I2C a fair amount. Also not sure how easy it is to lose an interrupt, seems like that should be exceedingly rare.

Didn't we have past discussion where it was shown that if the RTC was being accessed too frequently it would lose time because all the responding was keeping it from updating its time correctly? Any chance that is happening here?
I have this RTC I2C test (DS1307) that only use Wire.h library, give it a try and see if you still lose time:

/*
Test of RTC DS1307 via I2C.
 Counts 
 Seconds, 
 Minutes, 
 Hours, 
 Date of the Month, 
 Month, 
 Day of the week, and 
 Year with Leap-Year
 
 56 bytes battery backed RAM
 Square Wave Output
 
 11/17/2012- Updated for Wire.write & Wire.read commands
 1/18/13 - fixed unclear reference to 0x00
 */

/*
Modified to Run thru IDE Serial port
*/
#include <Wire.h>

//variables
byte zeroByte = 0;
byte seconds_address = 0x00;
byte seconds; // bit 7 = Clock Halt, Enabled = 0, Halt = 1
// bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9

byte minutes_address = 0x01;
byte minutes;  // bits 6-5-4 = tens of minutes, bits 3-2-1-0 = units of minutes

byte hours_address = 0x02; 
byte hours;  // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
// bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
// bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

byte day_week_address = 0x03; 
byte day_week = 0; // range 01-07

byte date_month_address = 0x04;
byte date_month = 0; // range 01-31

byte month_address = 0x05;
byte month = 0; // range 01-12

byte year_address = 0x06;
int year = 0; // upper byte 0-9, lower byte 0-9

byte square_address = 0x07;
byte sqwe = 0;  // square wave enable
// Out-0-0-Sqwe-0-0-RS1-RS0
// Out, Sqwe = 0/0 - Square wave output = 0
// Out, Sqwe = 1/0 - Square wave output = 1
// Out, Sqwe = 0/1 or 1/1 - Square wave output per RS1/RS0
// RS1/RS0 = 00 = 1 Hz
// RS1/RS0 = 01 = 4 KHz
// RS1/RS0 = 10 = 8 KHz
// RS1/RS0 = 11 = 32 KHz

byte RTC_ram_address = 0x08; //range = 08-63, 0x08-0x3F

int RTC_address = 0x68; // 1101 000 

byte incomingCommand = 0;
byte RTC_write_command = 0;
byte RTC_read_command = 0;
byte RTC_ram_command = 0;

// use F0xx, F1xx,F2xx, F3xx, F4xx, F5xx, F6xx, F7xx
// to send one register write commands
// use E0xx to read registers back - not coded yet
// use C0xx to read RAM back - not coded yet

byte incomingRegister = 0;
byte RTC_register = 0;
byte incomingData1 = 0;
byte incomingData2 = 0;
byte new_data = 0;
byte outgoingData = 0;
int delay_time = 100;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long duration = 5000;

void setup() {
  Wire.begin(); // no address, we are master
  Serial.begin (57600);  
  // Serial.flush();
  currentMillis = millis();  
}

void loop() {

  if (Serial.available() >3){
    incomingCommand = Serial.read();
    incomingRegister = Serial.read();
    incomingData1 = Serial.read();
    incomingData1 = incomingData1 - 0x30; // convert ASCII to HEX
    incomingData2 = Serial.read();
    incomingData2 = incomingData2 - 0x30;  // convert ASCII to HEX
    new_data = (incomingData1 << 4) + incomingData2;  // put the Upper/Lower nibbles together
    Serial.print ("command ");
    Serial.println (incomingCommand);
    Serial.print ("register ");
    Serial.println(incomingRegister);
    Serial.print ("data1 ");
    Serial.println (incomingData1, HEX);
    Serial.print ("data2 ");
    Serial.println (incomingData2, HEX);
    Serial.print ("combined data ");    
    Serial.println (new_data, HEX);
    
  }
  // *******************************************
//  RTC_write_command = incomingCommand & 0xF0;  // mask off high byte
//  if (RTC_write_command == 0xF0){  // check for Write command
if ((incomingCommand == 'F') | (incomingCommand == 'f')){
  incomingCommand = 0;  // reset for next pass
//    RTC_register = incomingCommand & 0x0F;  // mask off low btye
//    incomingCommand = 0;
//    new_data = incomingData;
    Serial.println (" Sending a command ");
//    switch (RTC_register){
switch (incomingRegister){
  case '0': // write seconds
        Serial.println ("Seconds ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(seconds_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '1': // write minutes
    Serial.println ("Minutes ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(minutes_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
      delay (delay_time);
      break;
    case '2': // write hours
        Serial.println ("Hours ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(hours_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '3': // write day
        Serial.println ("Day ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(day_week_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '4': // write date of month
        Serial.println ("Day of Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(date_month_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '5': // write month
        Serial.println ("Month ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(month_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '6': // write year
        Serial.println ("Year ");
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(year_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '7': // write square wave
        Serial.println ("Square Wave ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(square_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
    case '8': // write RAM
        Serial.print ("RAM ");
    Serial.println (RTC_register, HEX);
      Wire.beginTransmission(RTC_address); // select device
      Wire.write(RTC_ram_address);          // queue the register
      Wire.write(new_data);                  // queue data
      Wire.endTransmission();            // send it
     delay (delay_time);
      break;
      // all others,do nothing
      Serial.println ("Invalid command ");
    }  // end Switch
  } // end if command == 'F'
  // ************************************

  currentMillis = millis();
  if ( (currentMillis - previousMillis) >= duration){
    previousMillis = currentMillis;  
    // Reset the register pointer  
    Wire.beginTransmission(RTC_address);  
    Wire.write(zeroByte);  
    Wire.endTransmission();   

    Wire.requestFrom(RTC_address,8 );  
    seconds = Wire.read();  
    minutes = Wire.read();  
    hours = Wire.read();  
    day_week = Wire.read();  
    date_month = Wire.read();  
    month = Wire.read();  
    year = Wire.read();  
    sqwe = Wire.read();

    // Seconds 
    // bit 7 = Clock Halt, Enabled = 0, Halt = 1
    // bits 6-5-3 = tens of seconds 0-6,  bits 3-2-1-0 = units of seconds, 0-9 

    // Hours
    // 7=0. 6 = 1 for 12 hr, 0 for 24 hr.
    // bit 5: 12 hr mode = AM(0)/PM(1). 24 hr mode = upper tens of hrs
    // bit 4 =  lower tens of hrs, bits 3-2-1-0 = units of hours (0-9)

    Serial.print ("Hrs " );
    Serial.print (hours, HEX);
    Serial.print (" Mins ");
    Serial.print (minutes, HEX);
    Serial.print (" Secs ");
    Serial.print (seconds, HEX);
    Serial.print (" Day ");
    Serial.print (day_week, HEX);
    Serial.print (" Date ");
    Serial.print (date_month, HEX);
    Serial.print (" Month ");
    Serial.print (month, HEX);
    Serial.print (" Year 20");
    Serial.print (year, HEX);
    Serial.print (" Square Wave ");
    Serial.println (sqwe, HEX);

  }
}

To Amitgaur06, Jack Christensen and CrossRoads,

thanks all for your posts.

Amitgaur06, I was using the DS1307 and DS3231 libraries. I cannot remember where I got the DS1307 library, but the DS3231 library was from GitHub - JChristensen/DS3232RTC: Arduino Library for Maxim Integrated DS3232 and DS3231 Real-Time Clocks (written by Jack actually).

Jack, I was still using the DS3231 library (which has I2C code embedded in it), but not initialising a "Wire.begin()" statement nor writing any code for I2C communication to my other slave arduino modules (lamp and audio) in my main code. I did however manage to find Nick's alternative "I2C.h" library and use it in my code.

Thanks CrossRoads for your test code, I did not need to use it as I fix my problem in the end.

So how did I fix it?

Well, I am not sure if this the "best way", but it did it.

I swapped all of the "Wire.h" code to Nick's "I2C.h" code. I got rid of the DS1037.h and DS3231.h code and I have written I2C code to directly access the time from the RTC. Problem solved. Perfect time now. And I have now gotten so used to looking through libraries, that I wrote a few of my own. So I have attached the program code if any ones want look at it (with libraries).

Cheers

Complete_Alarm_Clock_V5_2_with_SparkfunMP3.ino (29.1 KB)

TimeOwn.cpp (3.92 KB)

TimeOwn.h (1.03 KB)

And the other files

LampShieldOwn.cpp (1.06 KB)

LampShieldOwn.h (470 Bytes)

MP3ShieldOwn.cpp (1.12 KB)

MP3ShieldOwn.h (513 Bytes)

@irishcream24, glad to hear things are working. Do you have a theory as to what the specific problem was?

CrossRoads:
Didn't we have past discussion where it was shown that if the RTC was being accessed too frequently it would lose time because all the responding was keeping it from updating its time correctly?

Yes, that was a theory someone had. Thought I remembered testing it too, but couldn't remember the outcome. So I left a DS3232 running overnight, reading it as fast as possible (over 1400 times per second using 400kHz bus speed), and it's right on this morning. The test used the standard Arduino Wire library and my DS3232RTC library. A single read takes about 0.67ms, so it's not really being hit all that frequently. I'd think the RTC hardware would still have plenty of time to keep things updated internally. Mind you, I'm not suggesting that reading the RTC too often will affect timekeeping. In fact I rather doubt it as I have no evidence to support such a theory.

I have no real theories of why the RTC was not running properly before. Something to do with the "wire.h"library (or DS3231/DS1307 libraries), but I am not sure what. Sorry

CrossRoads:
Didn't we have past discussion where it was shown that if the RTC was being accessed too frequently it would lose time because all the responding was keeping it from updating its time correctly? Any chance that is happening here?

Did some more testing on this. I cannot see that reading the Maxim RTCs (DS1307, DS3231, DS3232) as fast as possible (at 400kHz bus speed for DS3231/2 and 100kHz for DS1307) affects them at all. Interestingly, I tried the same thing with an MCP79411 RTC and found that it ran fast, about 440ppm when using 400kHz bus speed, and about 230ppm at 100kHz. Quite noticeable as this equates to about 0.84 - 1.6 sec/hr fast.

I'm only leaving a note that I'm observing similar problem.

In my case I have Arduino Nano and module with RTC DS3231 and EEPROM AT24C32. To save power I have VCC of this RTC/EEPROM module connected to digital output of Arduino and I power it on only when I need to know time or when I want to read/write EEPROM. Actually I'm doing it only once after reboot, then the module sleeps.

For communication I use pure Wire.h library because the protocol is really simple.

And I have noticed that when I upload my sketch into Arduino then the RTC time delays for a while. When I upload sketch cca 5 times then the RTC time is delayed totally about 5 seconds. And this happens only during uploading. When I was doing only rebooting or pluging RTC module in and out then the time was perfect.

When I have time I will do more tests, like uploading with or without connected I2C pins, etc...