EM506 & DS3234 Sync

Hello-

I would like to sync my DS3234 RTC with GPS time from a EM506 every 6 hours. I have both devices working independently, but can't figure out how to only update the time every 6 hours.

Any guidance would be very appreciated.

Why would you need to do this?

The DS3234 is quite accurate ♦ Accuracy ±2ppm from 0°C to +40°C ♦ Accuracy ±3.5ppm from -40°C to +85°C

Even if it were out of spec and loosing 5ppm its still only abut 100ms per six hour period.

Hi Cattledog,

This is just for a home project; there’s no ‘need’ to do it aside from wanting to correct whatever drift does exist. I thought about using this method when I used the GPS to set the initial time on the DS3234. That’s all. I’m not familiar with the Arduino language enough to write the loop.

used the GPS to set the initial time on the DS3234

From this statement, I am going to assume that you know how to read the time from the GPS and how to use that time to set the RTC

but can't figure out how to only update the time every 6 hours.

You basically have three ways to determine a time period using data from the GPS, the RTC or the arduino and its millis() timer. I will demonstrate how to use the millis() timer, but the approach is similar which ever time source you use.

You read the time, determine how much time has passed since you last set the RTC, and if that time period is long enough, you take action. The important thing is to use some sort of continuous time like the running millis() timer, or actual "Unix time", rather than the more easily human readable form of hours, minutes, seconds.

This is the approach of "Blink without Delay" sketch in the 02 Digital examples included with the IDE, or in the tutorial sketch ("Demonstration Code for Several Things at the Same Time") which heads up the Project Guidance section of the forum.

Here's a sketch using the millis() timer. I've set it up as a demonstration with the 6 hr sync period shortened to 21.6 seconds.

unsigned long lastGpsSyncTime;
//unsigned long interval = 21600000UL; //6 hours =6x60x60 = 21600 seconds

unsigned long interval = 21600UL; //21.6 second test code

void setup() {
  Serial.begin(9600);
  Serial.println("starting...");
}

void loop() {
  if (millis() - lastGpsSyncTime >= interval)
  {
    lastGpsSyncTime  += interval;
    syncRTC();
  }
}

void syncRTC() {
  //get the GPS time, and set the RTC with GPS time values
  Serial.print("update   ");
  Serial.println(millis());
}

If you want to use the RTC or the GPS to provide the sync time, then replace the call to millis() with the call for time from the RTC or the GPS. It may take some manipulation (or use of the time library) to get the time from human readable time to something continuous like unix time. You could also use the 1 pulse per second available from the RTC to count up the interval time.

You could also use the internal alarm functions of the DS3432 to control the sync. If you are using a library for the RTC it might have commands for the alarms, otherwise you will need to refer to the data sheet for the alarm registers and the SPI commands.

Hi Cattledog,

Wow! That's an awesome reply, containing everything I hoped for and more. I'm going to play around with some of the different methods you shared with me (millis() and alarm registers). I've got a lot to learn, but with the help that you provided, I can move forward again.

Thanks again!!

  • Karma added -

Here is an example which uses the 1Hz square wave from the RTC to drive the sync process. The square wave output requires a pull up resistor, but it may (should) be built into your module.
You could also use the 1pps signal from the gps, but it may be lost if you loose the fix.

I am using a DS3231 with I2C so the communication protocol will be different for you with SPI. I think the register setup may be the same but check the data sheet.

#include <Wire.h>

//unsigned long interval = 21600UL; //6 hours =6x60x60 = 21600 seconds
unsigned long interval = 10;//test code 10 seconds

volatile boolean syncNow = false;
volatile unsigned long tick;

void setup() {
  Serial.begin(9600);
  Serial.println("starting...");
  
  Wire.begin();
  enable1HzTick();
  
  attachInterrupt(0, addTick, RISING);//jumper sqw out to pin 2
   
}

void loop() {
  if (syncNow == true) {
    syncRTC();
    syncNow = false;
  }
}

void enable1HzTick() {
  Wire.beginTransmission(0x68); //RTC addrress
  Wire.write(0x0E);//register for square wave output
  Wire.write(B00000000);//enable 1hz see data sheet
  Wire.endTransmission();
}

void addTick() {
  tick++;
  if (tick >= interval) {
    syncNow = true;
    tick = 0;
  }
}

void syncRTC() {
  //set RTC with GPS time values
  Serial.print("update   ");
  Serial.println(millis());
}

Hi Cattledog,

Thank you for sharing your example code which uses the 1hz square wave from the RTC. I will implement this for testing and study the concept a little better. This is perfect for the helping me learn a new concept.

I can't say thanks enough. You've been a real help.