DS1307 sqw output freezes after time update..

Hi…I’m trying to make a RTC based on a DS1307, syncronized with a GPS…For this I’m using those libs:

#include "Wire.h"
#include <DS1307RTC.h>
#include <Time.h>       
#include <Timezone.h>   
#include <TinyGPS.h>

I’m using the sqw output, to generate an interrupt which only sets a flag which I’m using to generate a read from DS1307, and display it on the serial monitor…

void loop()
{
  if (interruptComplete)
  {   
    RTC.get();// time from DS1307...
    monitor_out();//print it...
    interruptComplete = false;
  }


  getGPS();// get data from GPS
}

//interrupt vector=============================
void interruptHandler()
{
  
  interruptComplete = true;
  
}

The code works fine until I want to update the time in the DS1307, using the RTC.set function…The time is correctly set in the DS1307 registers,but the sqw output freezes,therefore, all the program stops…
Here is the code where RTC.set happens…

time_t gpsTimeSync()
{ 
  unsigned long age = 0 ;   
  unsigned long date, time;
  gps.get_datetime(NULL, NULL, &age);


  //No time update to DS1307 if GPS signal is lost....
  if (age == TinyGPS::GPS_INVALID_AGE || age >1000 ){//age == TinyGPS::GPS_INVALID_AGE ||
    //Serial.println("GPS lost..");
  }

  else
  {  
    gpsToArduino();//
  }
}

//  GPS to DS1307 local time

time_t gpsToArduino(){
  tmElements_t tm;
  int year;
  gps.crack_datetime(&year, &tm.Month, &tm.Day, &tm.Hour, &tm.Minute, &tm.Second, NULL, NULL);
  tm.Year = year-1970 ; 
  time_t time = makeTime(tm);//GPS data--> time_t....
  utc = time;// time from GPS....
  //printTime(utc, "UTC");//debug only...UTC time...
  local = myTZ.toLocal(utc, &tcr);
  //printTime(local, tcr -> abbrev);//debug only..timezone time output
  time_t t=local;
  RTC.set(t);// after this, the SQW freezes, but the time is set properly to the DS1307
}

Where could be the problem ?Beeing at the start of learning C++, any help from you will be very handfull to see my mistakes…
Best regards…

Post all your code please. Things you have omitted might provide the answer.

How to use this forum

Thanks for your quick answer…Here’s the code i’m using…

// GPS + RTC  FSM clock
//
#include "Wire.h"
#include <DS1307RTC.h>
#include <Time.h>       
#include <Timezone.h> //Jack Christensen's Timezone  
#include <TinyGPS.h>//GPS and NewSoftSerial libraries are the work of Mikal Hart
#define DS1307_ADDRESS 0x68

//Timezone settings..=============================.

TimeChangeRule myDST = {
  "ROM", Last, Sun, Mar, 3, +180};    //Daylight time = UTC +3hours
TimeChangeRule mySTD = {
  "ROM", Last, Sun,Oct, 3, +120};     //Standard time = UTC +2 hours
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr;        //pointer to the time change rule, use to get TZ abbrev
time_t utc, local,t;

//Tiny GPS====================================

TinyGPS gps;
//static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_date(TinyGPS &gps);

//==***********************
boolean interruptComplete = false;
char dateTime[20];

//=========GPS checking=============================================
time_t gpsTimeSync()
{ 
  unsigned long age = 0 ;   
  unsigned long date, time;
  gps.get_datetime(NULL, NULL, &age);


  //No time update to DS1307 if GPS signal is lost....
  if (age == TinyGPS::GPS_INVALID_AGE || age >1000 ){
    //Serial.println("GPS lost..");
  }

  else
  {  
    gpsToArduino();

  }
}

//  GPS to DS1307 local time

time_t gpsToArduino(){
  tmElements_t tm;
  int year;
  gps.crack_datetime(&year, &tm.Month, &tm.Day, &tm.Hour, &tm.Minute, &tm.Second, NULL, NULL);
  tm.Year = year-1970 ; 
  time_t time = makeTime(tm);//GPS data--> time_t....
  utc = time;// time from GPS....
  //printTime(utc, "UTC");//debug only...UTC time...
  local = myTZ.toLocal(utc, &tcr);
  //printTime(local, tcr -> abbrev);//debug only..timezone time output
  time_t t=local;
  RTC.set(t);// after this, the SQW freezes, but the time is set properly to the DS1307
}


//Debug on serial monitor..
void monitor_out(){
  sprintf(dateTime, "%4d-%02d-%02d %02d:%02d:%02d", year(),
  month(), day(), hour(),minute(), second()) ;
  Serial.print(dateTime);
  Serial.print(" - day of week: ");
  Serial.println(dayStr(weekday()));
}

// Timezone debug..
void printTime(time_t t, char *tz)     //, char *tz
{
  sPrintI00(hour(t));
  sPrintDigits(minute(t));
  sPrintDigits(second(t));
  Serial.print(' ');
  Serial.print(dayShortStr(weekday(t)));
  Serial.print(' ');
  sPrintI00(day(t));
  Serial.print(' ');
  Serial.print(monthShortStr(month(t)));
  Serial.print(' ');
  Serial.print(year(t));
  Serial.print(' ');
  Serial.print(tz);
  Serial.println();
  Serial.println(weekday(t));
}
void sPrintI00(int val)
{
  if (val < 10) Serial.print('0');
  Serial.print(val, DEC);
  return;
}

//Print an integer in ":00" format (with leading zero).
//Input value assumed to be between 0 and 99.
void sPrintDigits(int val)
{
  Serial.print(':');
  if(val < 10) Serial.print('0');
  Serial.print(val, DEC);
}


//======================================

void getGPS(){
  bool newdata = false;
  unsigned long start = millis();
  // Every second we print an update
  while (millis() - start < 1000)
  {
    if (feedgps()) newdata = true;

    gpsTimeSync();
  }
}

// ***********************************************
// read GPS serial data and send to tinyGPS
// ***********************************************
static bool feedgps() {
  while (Serial1.available()) {
    if (gps.encode(Serial1.read())) {
      return true;
    }
  }
  return false;
}

//=================================
void setup()
{
  Serial.begin(19200);//monitor
  Serial1.begin(19200); // for GPS
  Serial1.println ("$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28");//RMC only...
  Serial1.println ("$PMTK220,1000*1F");//fix at 1000 ms
  attachInterrupt(0, interruptHandler, FALLING);
  Wire.begin();

  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time"); 

}
void loop()
{
  if (interruptComplete)
  {   
    RTC.get();// time from DS1307...
    monitor_out();//print it...
    interruptComplete = false;
  }


  getGPS();// get data from GPS
}

//interrupt vector=============================
void interruptHandler()
{

  interruptComplete = true;

}

For sure, there is a mistake there…But looking for it so many hours,I’m not able to see it…And another thing to mention here…When I unplugg the GPS from Serial1 pins, the DS1307’s sqw starts running …

boolean interruptComplete = false;

...


//interrupt vector=============================
void interruptHandler()
{

  interruptComplete = true;

}

interruptComplete should be declared volatile.

I did the modification, but no luck..It still freezes...After first update it freezes again....Could this be a DS1307 problem itself ?.. But I'm wondering why if I disconnect the GPS, the sqw reverts to normal operation? Even if the DS was update before ? where is the conflict? I'm trying to figure that , but I still have no answer...

And another thing..The DS continues it's counting in the background, but only the sqw is disabled like something is overwritten on the control register and disables the sqw....Very weird...

Can you turn off the sqw interrupt, update the time, and turn the sqw back on?

Can you change your code so you don't have global and local variables of the same name? Can you change your code to get rid of global variables that are used only in one function?

What RTC library are you using? Your call to RTC.set doesn’t look like the examples I’ve seen. I don’t think that time_t is the right thing to pass the library. I suggest getting the 1307RTC library from David Brown at github and trying it. It has specific calls to set the SQW frequency.

Just to be sure, what is the value of the DS1307 control register before and after the RTC.set command?

Hi and thanks for your replies..Answering in order, now..

@ PaulS..I did what you suggested both with attach and detach interrupt..output still freezing..Tryed then with "cli" and "sei"...The whole program stopped after first RTC.set, but the output didn't freezed..I'd wrote those instructions right before and after RTC.set command...Regarding the variables, I think is my old habit from assembler language..I jumped into Arduino and it's IDE just two weeks ago...

@afremont..All the libraries I'm using are supposed to work in conjunction, one can't work without the other...The DS1307 commands are in the library supplied with the Time library...

@dannable..The things are getting close to black magic...The control register is unchanged...it has 0x10 before ,same after....

Any ideeas about what's happening here?

The things are getting close to black magic

They sell millions of these chips. They work, there isn't any magic involved.

Please post your latest sketch, plus a diagram of your circuit.

I don't understand what you think is supposed to turn on the SQW output when you call RTC.set. A time_t item doesn't contain any information about any SQW output so calling RTC.set with a time_t can't possibly convey any information about how to set the SQW output, one way or the other. So I suspect the library is clearing the field when it sets the time registers, have you looked at the source?

EDIT: After digging around, RTC.set shouldn't be writing to the SQW register. Where did you download your libraries?

Thanks again for your help…
@ Mr.Gammon… That was a joke,about black magic… :)…I used many DS1307 untill now, but the programs who used them were wrote in assembler, for Microchip controllers…They all worked very fine…But, finally I’d decided to jump into Arduino’s IDE world becouse sometimes is very hard to parse 2k of lines wrote in assembler :)…On a scale from 1 to 10 regarding C++, I’m somewhere to -1, I believe…Not even reach the zero… :)…When I saw that a 520 line multiply in assembler, can be written in just one, in C++, the decision was made…And also the hardware developed around this arduino, was an important factor …

@ afremont…Yes, I digged myself in that library, and I saw that the RTC.set, don’t touch the control reg …The only thing it does,it’s stops and starts the oscillator,writting the data between them…The only thing that was possible to happens, it was that call didn’t have enough time to start again the oscillator, therefore no sqw output…In my oppinion is all about handling interrupts here, or the stack management…I think the Serial1 interrupt triggered by GPS is somehow overlapped by the one triggered by the sqw…Or maybe it is the Serial itself used for monitor, to cause some troubles…Therefore, for the moment, i removed the call from that function and putted in the main loop just before the RTC.get call…It seems to work now, but I want to dig and find the real cause, to avoid it in the future…The library I founded it here on the playground section…Here is my new code :

// GPS + RTC  FSM clock
//
#include "Wire.h"
#include <DS1307RTC.h>
#include <Time.h>       
#include <Timezone.h> //Jack Christensen's Timezone  
#include <TinyGPS.h>//GPS and NewSoftSerial libraries are the work of Mikal Hart
#define DS1307_ADDRESS 0x68

//Timezone settings..=============================.

TimeChangeRule myDST = {
  "ROM", Last, Sun, Mar, 3, +180};    //Daylight time = UTC - 4 hours
TimeChangeRule mySTD = {
  "ROM", First, Sun, Nov, 3, +120};     //Standard time = UTC - 5 hours
Timezone myTZ(myDST, mySTD);
TimeChangeRule *tcr;        //pointer to the time change rule, use to get TZ abbrev
time_t utc, local,t;//var that must be seen by others functions

//Tiny GPS====================================

TinyGPS gps;
boolean valid = false;

//***interrupt*********************
volatile boolean interruptComplete = false;


//=========GPS checking=============================================
time_t gpsTimeSync()
{ 
  unsigned long age = 0 ;   
  unsigned long date, time;
  gps.get_datetime(NULL, NULL, &age);

  //No time update to DS1307 if GPS signal is lost....
  if (age == TinyGPS::GPS_INVALID_AGE || age >1500 ){
    Serial.println("GPS lost..");
    valid = false;
  }
  else{
    valid = true ;
    gpsToArduino();
  }
}

//  GPS to DS1307 local time =====================================   
time_t gpsToArduino(){
  tmElements_t tm;
  int year;
  gps.crack_datetime(&year, &tm.Month, &tm.Day, &tm.Hour, &tm.Minute, &tm.Second, NULL, NULL);
  tm.Year = year-1970 ; 
  time_t time = makeTime(tm);//GPS data--> time_t....
  utc = time;// time from GPS....
  local = myTZ.toLocal(utc, &tcr);
  //RTC.set(local);// moved from here to the loop...

}


//Debug on serial monitor..=================================================
void monitor_out(){
  char dateTime[20];
  sprintf(dateTime, "%4d-%02d-%02d %02d:%02d:%02d", year(),
  month(), day(), hour(),minute(), second()) ;
  Serial.print(dateTime);
  Serial.print(" - day of week: ");
  Serial.println(dayStr(weekday()));
}


//======================================

void getGPS(){
  bool newdata = false;
  unsigned long start = millis();
  // Every second we print an update
  while (millis() - start < 1000)
  {
    if (feedgps()) newdata = true;
    gpsTimeSync();
  }
}

// ***********************************************
// read GPS serial data and send to tinyGPS
// ***********************************************
static bool feedgps() {
  while (Serial1.available()) {
    if (gps.encode(Serial1.read())) {
      return true;
    }
  }
  return false;
}

//=================================
void setup()
{
  Serial.begin(19200);//monitor
  Serial1.begin(19200); // for GPS
  Serial1.println ("$PMTK314,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*28");//RMC only...
  Serial1.println ("$PMTK220,1000*1F");//fix at 1000 ms

  attachInterrupt(0, interruptHandler, FALLING);
  Wire.begin();

  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
    Serial.println("Unable to sync with the RTC");
  else
    Serial.println("RTC has set the system time"); 

}
void loop()
{

  if (interruptComplete){

    if (valid){      // If GPS sentence is valid,write the time, if not, skip..
      RTC.set(local);// DS1307 set to the local time from timezone..
    }
    RTC.get();// time from DS1307...
    monitor_out();//print it...
    interruptComplete = false;
  }
  getGPS();// get data from GPS
}


//interrupt vector=============================
void interruptHandler()
{

  interruptComplete = true;

}

This is a little part of what I’m intenting to do…I want also to implement some time alarms, a graphic display,and some buttons or a navpad to set the alarms and other stuff…Seems a little bit complex for my first project in C++, but is more exciting than blinkin’ a led… :slight_smile:

I would bet that something is being written to Register 0x07 and turning off the Square Wave: http://www.maximintegrated.com/datasheet/index.mvp/id/2688 Page 9

07h 7:OUT 6:0 5:0 4:SQWE 3:0 2:0 1:RS1 0:RS0 Square Wave Control Register

(bits 6,5,3,2 are always 0)

Bit 7: Output Control (OUT). This bit controls the output level of the SQW/OUT pin when the square-wave output is disabled. If SQWE = 0, the logic level on the SQW/OUT pin is 1 if OUT = 1 and is 0 if OUT = 0. On initial application of power to the device, this bit is typically set to a 0. Bit 4: Square-Wave Enable (SQWE). This bit, when set to logic 1, enables the oscillator output. The frequency of the square-wave output depends upon the value of the RS0 and RS1 bits. With the square-wave output set to 1Hz, the clock registers update on the falling edge of the square wave. On initial application of power to the device, this bit is typically set to a 0. Bits 1 and 0: Rate Select (RS[1:0]). These bits control the frequency of the square-wave output when the square-wave output has been enabled. The following table lists the square-wave frequencies that can be selected with the RS bits. On initial application of power to the device, these bits are typically set to a 1.

Hi..As far I had tryied printing on serial monitor, nothing is changed in that register..It contains 0x10 before and after that call...The weird thing is when I pull out the gps's tx wire from rx1, everything get back to normal, the sqw outputs it's 1 hz again....

Odd. What does GPS on Rx1 have to do with I2C, and what appears to be a completely independent divide by 32K circuit in the DS1307? I could see maybe GPS is bogging down uC with processing incoming serial and preventing I2C from requesting time updates from the RTC.

Yes, this is my oppinion, too..Somehow, the Serial1 interrupt interfere with the I2C..Anyway,as far I know,the GPS send it's data ,triggering the serial interrupt, during the first 100ms after the time has changed...The sqw of DS1307 triggers the interrupt after 500ms, on it's falling edge...Maybe I must dig to find the proper time windows, so those int's to not overlap....