Adafruit Industries, Essential service and business: NYC – Executive Order 202.6 - Read more.
0

RTC on Data logger shield not very accurate
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

RTC on Data logger shield not very accurate

by stevenvh on Thu Apr 16, 2015 12:41 pm

While digital watches often are accurate to a couple of seconds per month, the RTC on my data logger shield has an error of more than a second a day. Can the oscillator be trimmed to run slower? I notice there aren't any load capacitors on the PCB.

stevenvh
 
Posts: 29
Joined: Thu Jan 29, 2015 9:28 am

Re: RTC on Data logger shield not very accurate

by adafruit_support_bill on Thu Apr 16, 2015 1:10 pm

I don't know of any hardware tuning, but there are some software solutions:
http://forum.arduino.cc/index.php?topic=119054.0

adafruit_support_bill
 
Posts: 76615
Joined: Sat Feb 07, 2009 10:11 am

Re: RTC on Data logger shield not very accurate

by jboyton on Fri Apr 17, 2015 12:42 pm

I got one of these recently and it is a little disappointing. I hadn't looked at the specifications before I purchased. It seems that most crystals are around ±20ppm which is about 1 second per day. Any mismatch in capacitance would exacerbate this. If it's running slow I wonder if you could add a tiny capacitor? It's probably easier to just make a software patch.

If you really want to hack you could substitute a temperature compensated oscillator for the crystal but it's not exactly a drop in replacement. For that matter you could replace the DS1307 with a DS3231. The latter has an internal temperature compensated oscillator and 10X the accuracy of the DS1307. But again, it isn't a drop in replacement. The whole point of these shields is that the work is already done for you, allowing you to focus on a higher level problem.

Oh well, a software patch will have to do...

Some bedtime reading, if you're interested: http://www.emesystems.com/pdfs/parts/DS1307_xtal.pdf

jboyton
 
Posts: 111
Joined: Tue Sep 16, 2014 2:52 pm

Re: RTC on Data logger shield not very accurate

by adafruit_support_mike on Fri Apr 17, 2015 2:43 pm

The standard circuit for digital applications is a simple Pierce oscillator:

pierce.jpg
pierce.jpg (12.47 KiB) Viewed 1430 times
The resistor and inverter make a primitive inverting op amp, the crystal sets the resonant frequency, and the capacitors provide enough phase shift to support oscillation.

The capacitors do have a small effect on frequency, and tuning the frequency by changing their value is called 'pulling' the frequency. In most cases, you just change the value of C1, either replacing it with a varicap or putting it in parallel with one.

adafruit_support_mike
 
Posts: 61014
Joined: Thu Feb 11, 2010 2:51 pm

Re: RTC on Data logger shield not very accurate

by jboyton on Fri Apr 17, 2015 3:17 pm

That's what they describe in that app note I posted a link to:

Image

The thing is, the capacitors are internal to the RTC so if there is too much capacitance you can't reduce it. But if there is too little, maybe you have a way to tweak the frequency.

There is a temperature effect as well, something on the order of 1 sec/day per 10°C (roughly).

jboyton
 
Posts: 111
Joined: Tue Sep 16, 2014 2:52 pm

Re: RTC on Data logger shield not very accurate

by adafruit_support_mike on Fri Apr 17, 2015 11:18 pm

You could compensate some of the capacitance by putting a small inductor in parallel with the cap, but it wouldn't be a task for the faint-hearted.

You can also change the speed of a Pierce oscillator (or any oscillator, really) by tweaking the supply voltage up or down. In most cases, raising the supply voltage will pull the frequency higher because it makes the inverter/op-amp respond a little faster. The effects of that are in the 100ppm range.

Temperature control/compensation is the next adjustment after you've fixed the supply voltage and made sure it's stable.

adafruit_support_mike
 
Posts: 61014
Joined: Thu Feb 11, 2010 2:51 pm

Re: RTC on Data logger shield not very accurate

by jbenedetto84 on Mon Apr 20, 2015 3:27 pm

stevenvh wrote:While digital watches often are accurate to a couple of seconds per month, the RTC on my data logger shield has an error of more than a second a day. Can the oscillator be trimmed to run slower? I notice there aren't any load capacitors on the PCB.


actually +-1 second per day is actually pretty good. i've purchased ds1307's from other manufacturers and they've been as bad as 17-18 seconds a day +-. if you need accuracy, you need a RTC with TCXO (temperature-compensated crystal oscillator). the ambient temperature is essentially the reason for your 1 second discrepancy. look into a DS3231 --> extremely accurate.

jbenedetto84
 
Posts: 19
Joined: Mon Sep 23, 2013 10:40 am

Re: RTC on Data logger shield not very accurate

by jbenedetto84 on Mon Apr 20, 2015 3:29 pm

ALSO - one simple solution - if your ambient temperature doesn't really change, and you can run the program for a few days to see that the 1 second is consistent, you can set a line of code that says

when the time reaches 12:00:01am , rtc.adjust(subtract one second)

i've done a few versions of this on some simple projects - before i discovered the DS3231 of course. =)

jbenedetto84
 
Posts: 19
Joined: Mon Sep 23, 2013 10:40 am

Re: RTC on Data logger shield not very accurate

by stevenvh on Tue Apr 21, 2015 4:13 am

Perhaps Adafruit should redesign the data logger shield for the DS3231 instead of the DS1307. After all data logging can be very long term.

Alternatively, @Adafruit, take a look at the NXP PCF8583. It doesn't have the accuracy of the DS3231, but it has a hundredths-of-a-second register, so that adjustment of the clock doesn't require an abrupt 1 second jump. Also, the PCF8583 doesn't have a separate battery voltage input (Vdd and battery must be wired-ORed), so that it doesn't need the battery to operate. Which means you can change the battery in-system.
The PCF8583 also has alarm registers, and more RAM. Despite requiring the external double diode (with the BAT54C you only need 1 component) I think the PCF8583 is superior to the DS1307. And it's cheaper!
Adafruit, what are you waiting for? :-)
Last edited by stevenvh on Tue Apr 21, 2015 5:00 am, edited 2 times in total.

stevenvh
 
Posts: 29
Joined: Thu Jan 29, 2015 9:28 am

Re: RTC on Data logger shield not very accurate

by stevenvh on Tue Apr 21, 2015 4:33 am

@jbenedetto84 - Thanks for the suggestion. Actually that's the only way to adjust the clock, add or subtract 1 second at a time (though not necessarily at a fixed time), since you don't have control over fractions of a second. If I read the datasheet correctly the fractions counter gets reset when you write to the seconds register.

stevenvh
 
Posts: 29
Joined: Thu Jan 29, 2015 9:28 am

Re: RTC on Data logger shield not very accurate

by adafruit_support_bill on Tue Apr 21, 2015 6:49 am

Thanks for the suggestion. I will refer it to the design team.

adafruit_support_bill
 
Posts: 76615
Joined: Sat Feb 07, 2009 10:11 am

Re: RTC on Data logger shield not very accurate

by stevenvh on Tue Apr 21, 2015 8:45 am

Thanks Bill. Make sure they don't forget to add a small trimming capacitor, so that when the clock is a bit fast, it can be slowed down a bit. (Or at least provide a PCB pattern for it.) I miss that on the current shield.

Update:
The PCF85263A, also by NXP, may be even better! Down to less than 40 cents in quantities, and it features a watchdog timer and stopwatch mode. Spread the word! :-)

http://www.nxp.com/parametrics/71250/28 ... c=,so=,es=

For a comparison between DS1307 and PCF85263A, see http://nenya.me/electronics/rtc.php. (N.B.: the DS1307 costs more than 3 times as much)

stevenvh
 
Posts: 29
Joined: Thu Jan 29, 2015 9:28 am

Re: RTC on Data logger shield not very accurate

by jboyton on Thu Jul 09, 2015 4:38 pm

The DS1307 on my data logging shield was running a bit fast, about 79ppm at room temperature. That's close to 7 seconds per day. Or 3 1/2 minutes per month.

I have no idea what crystal is on the board so I bought a couple that matched Maxim's criteria and tried them. The better fit of the two (CFS-20632768EZBB) resulted in an error of +14ppm, about 1.2 second/day. Not bad.

Then I replaced the DS1307 with the pin compatible PCF85263A. It required a few simple commands to enable it's clock output so that I could measure it's frequency. And without any adjustment it was just a tiny bit slow, -4ppm, less than half a second per day. The load capacitance is adjustable with this chip, but the default of 7pF proved to be the best match for my crystal (6pF).

It also has an offset register which corrects the time by a user specified increment. I set it to add 4ppm which should make it quite accurate as long as we don't have a heat wave.

Since it's not temperature compensated, if I wanted it to work over a wider range of temperatures I'd have to add a sensor as well as code to dynamically update the offset register. But it's a nice, compact IC, inexpensive and it looks like it will be easy to use. I especially like the fact that it provides resolution down to 1/100 second.

Thanks for the suggestion, Steve.

jboyton
 
Posts: 111
Joined: Tue Sep 16, 2014 2:52 pm

Re: RTC on Data logger shield not very accurate

by CybJaffe on Tue Sep 22, 2015 1:16 pm

They need not any capacitor, i am talking about the RTC. New RTC do not require any capacitor for its operation. If it is going slow, then it is sure the problem will be there in the oscillator. Replace your oscillator if it will work then its okay otherwise go for the replacement of the RTC.

kitted pcb assembly

CybJaffe
 
Posts: 1
Joined: Tue Sep 22, 2015 12:52 pm

Re: RTC on Data logger shield not very accurate

by MikkelD on Thu Nov 09, 2017 7:44 pm

Hi,

I know this is an old topic, but I hope some one sees this. I got the new datalogger-shield with the PCF8523 RTC. And it is running to fast. Like 7 per day to fast. :(
Is there any way to adjust it? I am making an long term logger, hopefully running for years if I get it to work. So I would like it to be accurate, at least more accurate than 7 sec/day.
Some photos of the time.
20171109_234230_small.jpg
20171109_234230_small.jpg (267.93 KiB) Viewed 488 times
20171109_003714_small.jpg
20171109_003714_small.jpg (214.52 KiB) Viewed 488 times

And my code:
Code: Select all | TOGGLE FULL SIZE
#include <SPI.h>
#include <SD.h>
#include <Wire.h>           // I2C bibliotek
#include <RTClib.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <Adafruit_GFX.h>
#include <Adafruit_HX8357.h>

// The display uses hardware SPI
#define TFT_RST 2  // dont use a reset pin, tie to arduino RST if you like
#define TFT_DC 9

#define log_int  10 // seconds between logging

// Defining all the ChipSelect's:
const int chipSelect_SD = 10;
const int chipSelect_tft = 8;
const int chipSelect_BME = 4;

Adafruit_HX8357 tft = Adafruit_HX8357(chipSelect_tft, TFT_DC, TFT_RST);
Adafruit_BME280 bme(chipSelect_BME); // hardware SPI
RTC_PCF8523 RTC; // define the Real Time Clock object

File logfile;
DateTime now;
char filename[] = "20161123.CSV";
int sek2;
int dag;
int linjer = 0;

void P_failed();
void P_line();
void P_0(int val);
void create_file();
void BME_Read();

void setup(void) {
  pinMode(chipSelect_SD, OUTPUT); // Setter CS til SD som utgang.
  pinMode(chipSelect_tft, OUTPUT); // Setter CS til tft som utgang.
 
  tft.begin(HX8357D);
  tft.fillScreen(HX8357_BLACK);
  tft.setRotation(1);

  if (!SD.begin(chipSelect_SD)) {
    tft.print("SD");
    P_failed();
  }
 
  Wire.begin();  // connect to RTC
  if (!RTC.begin()) {
    tft.print("RTC");
    P_failed();
  }
//    RTC.adjust(DateTime(F(__DATE__), F(__TIME__))); // Un-comment this to sett date and time same as PC.
 
  if (!bme.begin()) {
    tft.print("BME");
    P_failed();
  }
 
  create_file();
}
 
void loop(){
 
  bool logg = false;

  while(!logg){
    delay(100);
   
    int Hour = now.hour();
    int Minute = now.minute();
    int Second = now.second();
   
    now = RTC.now();
   
    if(Hour != now.hour()){
      if(Hour < 10){
        tft.setCursor(106, 0);
      }else{
        tft.setCursor(100, 0);
      }
      tft.setTextColor(HX8357_BLACK);
      tft.print(Hour);
      if(now.hour() < 10){
        tft.setCursor(106, 0);
      }else{
        tft.setCursor(100, 0);
      }
      tft.setTextColor(HX8357_WHITE);
      tft.print(now.hour());
    }
   
    if(Minute != now.minute()){
        tft.setCursor(118, 0);
      tft.setTextColor(HX8357_BLACK);
      if(Minute < 10) tft.print("0");
      tft.print(Minute);
        tft.setCursor(118, 0);
      tft.setTextColor(HX8357_WHITE);
      if(now.minute() < 10) tft.print("0");
      tft.print(now.minute());
    }
   
    if(Second != now.second()){
      tft.setCursor(136, 0);
      tft.setTextColor(HX8357_BLACK);
      if(Second < 10) tft.print("0");
      tft.print(Second);
      tft.setCursor(136, 0);
      tft.setTextColor(HX8357_WHITE);
      if(now.second() < 10) tft.print("0");
      tft.print(now.second());
    }

    if(dag == 0){
      tft.setTextColor(HX8357_WHITE);
      tft.setCursor(112, 0); tft.print(":"); tft.setCursor(130, 0); tft.print(":");
    }
   
    if(dag == 0){
      dag = now.day(); // set the currant day in the variable, only first scan.
      tft.setCursor(0, 0);
      tft.print(now.year()); tft.print("/"); tft.print(now.month()); tft.print("/"); tft.println(now.day());
      tft.println("   Time:   Temp:   Humid: Pressure:");
      for(int i = 0; i < 35; i++){
        tft.print("-");
      }
        tft.println("-");
    }

    if(dag != now.day()){         // Create new logfile at midnight.
      tft.setCursor(0, 0);
      tft.setTextColor(HX8357_BLACK);
      tft.print(now.year()); tft.print("/"); tft.print(now.month()); tft.print("/"); tft.println(dag);
      tft.setTextColor(HX8357_WHITE);
      tft.setCursor(0, 0);
      tft.print(now.year()); tft.print("/"); tft.print(now.month()); tft.print("/"); tft.println(now.day());
      tft.setCursor(0, 24);
      create_file();
      dag = now.day();
    }
    int sek = now.second();       // Check if it is time for a new loging sample.
    if(sek % log_int == 0 && !(sek == sek2)){
      logg = true;
      sek2 = sek;
    }
  }

  if(linjer > 36){
    tft.fillRect(0, 24, 220, 320-24, HX8357_BLACK);
    tft.setCursor(0, 24);
    linjer = 0;
  }

  tft.setCursor(0, 24+(linjer*8));
  logfile = SD.open(filename, FILE_WRITE);
  P_0(now.hour());
  tft.print(now.hour());
  logfile.print(now.hour(), DEC);
  tft.print(":");
  logfile.print(":");
  P_0(now.minute());
  tft.print(now.minute());
  logfile.print(now.minute(), DEC);
  tft.print(":");
  logfile.print(":");
  P_0(now.second());
  tft.print(now.second(), DEC);
  logfile.print(now.second(), DEC);
  logfile.print(";");
  P_line();
  logfile.close();
 
  BME_Read();
  linjer++;
}

void P_failed(){
  tft.setTextColor(HX8357_RED);
  tft.println(" Failed!");
  tft.setTextColor(HX8357_WHITE);
}

void P_line(){
  tft.print(" | ");
}

void P_0(int val){
  if(val < 10){
    logfile.print("0");
    tft.print("0");
  }
//  tft.print(val);
//  logfile.print(val, DEC);
}

void create_file(){    // create a new file, if it does not exist.
  int i = now.year();
  filename[0] = i/1000 + '0';
  filename[1] = (i-((i/1000)*1000))/100 + '0';
  filename[2] = (i-((i/100)*100))/10 + '0';
  filename[3] = i%10 + '0';
  i = now.month();
  filename[4] = i/10 + '0';
  filename[5] = i%10 + '0';
  i = now.day();
  filename[6] = i/10 + '0';
  filename[7] = i%10 + '0';
  if (! SD.exists(filename)) {
    // only open a new file if it doesn't exist
    logfile = SD.open(filename, FILE_WRITE);
    if (logfile) {
      logfile.println("Time;Temparature;humidity;pressure");
      logfile.close();
    }
  }
}

void BME_Read(){  // fetch data from sensors
  float temp = bme.readTemperature();
  float humid = bme.readHumidity();
  float pres = bme.readPressure() / 100.0F;
  // log data from sensors
  logfile = SD.open(filename, FILE_WRITE);
  if (logfile) {
    tft.print(temp); P_line();
    logfile.print(temp); logfile.print("C;");
    tft.print(humid); P_line();
    logfile.print(humid); logfile.print(";");
    if(pres < 1000){
      tft.print(" ");
      logfile.print(0);
    }
    logfile.println(pres);
    tft.print(pres);
    P_line();
    tft.println();
  }
  logfile.close();
}


It's a little messy, as it's not finished yet. And some of the few comments I have is in norwegian. I have had some problems with initialization of the SD card with this code as well. I think maybe it tryed to use the SD card on the display, insted of the SD card on the logger shield. But that is working right now.

Hope some one sees this. :)


Kind regards
Mikkel
Love from Norway! :-)

MikkelD
 
Posts: 6
Joined: Fri Jun 16, 2017 5:55 pm

Please be positive and constructive with your questions and comments.