[Solved] Issues writing to DS1307 RTC

I made a related post in the programming section, but as I’ve gone through debugging I’m thinking this may be more of an i2c issue so I’m posting here…

I have a DS1307 RTC that I’ve been having trouble setting. In the course of trying to figure out the issue, I’ve discovered that if there is not a Wire.endTransmission() statement immediately before the Wire.write statement, it will not accept data. Is this a known issue with the i2c interface? Most of the examples I’ve seen don’t have it, so I tend to think not. The only explanation I can come up with is a buggy chip, but it seems to work as expected otherwise.

Below is the code I was using; the statement in question is at line 66. The issue appears to be timing-related; I put a delayMicroseconds() statement after the endTransmission statement and if the delay is more than about 935 µsecs, the clock won’t set. Less than that and it seems to set fine.

#include <Wire.h>
#define DS1307 0x68  //i2c address of DS1307

byte setTime1[] = {
  1, 2, 3, 4, 5, 6, 7}; // sec, min, hr, day, date, mo, yr
byte setTime2[] = {
  9, 8, 7, 6, 5, 4, 3};
byte time[7];

void setup(){
  Wire.begin();
  Serial.begin(115200);
  delay(1000);    //delay to open serial monitor
  Serial.println();
}

void loop(){
  readTime();
  printTime();
  delay(1000);  // delay to space out readings

  setTime(&setTime1[0]);  // set clock with first time
  readTime();             // read it back
  printTime();
  delay(1000);

  setTime(&setTime2[0]);  // set clock with another time
  readTime();
  printTime();
  Serial.println();
  delay(4000);
}

void printTime(){
  Serial.print("200");
  Serial.print(time[6]); // yr
  Serial.print("  ");
  Serial.print(time[5]); //month
  Serial.print("/");
  Serial.print(time[4]); //date
  Serial.print("  day ");
  Serial.print(time[3]); // day
  Serial.print("  ");
  if(time[2] < 10) Serial.print("0");
  Serial.print(time[2]);  // hr
  Serial.print(":");
  if(time[1] < 10) Serial.print("0");
  Serial.print(time[1]);  // min
  Serial.print(":");
  if(time[0] < 10) Serial.print("0");
  Serial.println(time[0]);// sec
}

void readTime(){
  Wire.beginTransmission(DS1307);  // open to RTC clock
  Wire.write(0);                   // set address to start reading from
  Wire.endTransmission();          
  Wire.requestFrom(DS1307,7);      // request 7 bytes
  while (!Wire.available());       // wait for bus to be available
  for(int i = 0; i<7; i++){        // read 7 bytes into time array
    time[i] = BCDtoDEC(Wire.read());  
  }
}

void setTime(byte* timeArray){
  Wire.endTransmission();      // if this is removed it the time won't set
  delayMicroseconds(935);      // if this is more than 935 µsec the time won't set
  Wire.beginTransmission(DS1307);      // open to RTC clock
  Wire.write(0);                       // set address to write to
  for (int i = 0; i < 7; i++){
    Wire.write(DECtoBCD(timeArray[i]));// write 7 bytes
  }
  Wire.endTransmission();
}

// routines to convert between BCD & decimal
byte BCDtoDEC(byte val){
  return ((val/16 * 10) + (val%16));
}
byte DECtoBCD(byte val){
  return ((val/10 * 16) + (val%10));
}

In the course of trying to figure out the issue, I've discovered that if there is not a Wire.endTransmission() statement immediately before the Wire.write statement, it will not accept data.

The Wire.endTransmission() call must be after the Wire.write() call because data will not be sent until the Wire.endTransmission() is called.

My guess is you have to search for the problem somewhere else. How do you power your setup? Measure the voltage from 5V to GND pin. The DS1307 reacts with a communication refusal to low voltages even if they are temporary.

pylon:
The Wire.endTransmission() call must be after the Wire.write() call because data will not be sent until the Wire.endTransmission() is called.

My guess is you have to search for the problem somewhere else. How do you power your setup? Measure the voltage from 5V to GND pin. The DS1307 reacts with a communication refusal to low voltages even if they are temporary.

That's what's confusing. The setTime routine appears to be properly written and is ended by the Wire.endTransmission() call, as you can see in the code, but it doesn't work unless it is also preceded by the Wire.endTransmission() call as well. From what I can tell, Arduino automatically sends a stop command after a read command has completed, but I tried putting a Wire.endTransmission() call at the end of the Read routine anyway. It didn't matter. As I said, it appears to be a timing issue; there has to be a Wire.endTransmission() call within ~930 µsecs of the write command.

I don't have an oscilloscope, so I can't look at what the SDA/SCL lines are doing in real time, but since I haven't had any problems with other i2c devices, I have to assume that the board is functioning properly. The board is plugged into my computer via a USB cable and the DS1307 powered from the 5V pin on the board. I measured and the pin appears to be a steady 5V (although I have no way of measuring in real time.) According to the data sheet, the device shuts down at 1.25*Vbat, or about 4V. Since there are no other devices hooked up to the board, it would be unlikely for the voltage to drop that much unless the voltage regulator is completely shot.

Ok - well, I think I may have found the answer, or at least part of it.

Working off of pylon's question about the voltage, I started measuring voltages and discovered that the pin connecting Arduino ground to the battery negative terminal and the RTC chip ground pin. That being the case, there's no way to know what the actual voltage is between Vbat & Vcc (or anything else)

I'm still not convinced that this is the only issue, because if it were, I wouldn't expect it to work as well as it has. Regardless, there's not much point looking at the code until the hardware is working. Time to talk to Sparkfun about getting a new board.

The board is plugged into my computer via a USB cable

and

Sleepydoc:
Time to talk to Sparkfun about getting a new board.

It probably isn't. At least not before the possibilities at home are properly addressed. I think those DS1307 boards get very particular about the power, and the USB supply is not necessarily that kosher. It can be so marginal that I had a DS1307 clock project work fine and then go belly-up when I changed the motherboard in the desktop, so you might find using a proper 9v supply will fix it all. Sparkfun might tell you the same thing.

Nick_Pyner:
It probably isn’t. At least not before the possibilities at home are properly addressed. I think those DS1307 boards get very particular about the power, and the USB supply is not necessarily that kosher. It can be so marginal that I had a DS1307 clock project work fine and then go belly-up when I changed the motherboard in the desktop, so you might find using a proper 9v supply will fix it all. Sparkfun might tell you the same thing.

Thanks for sharing your experience. Doesn’t seem like a very robust design… I Tried using a 9V battery and a wall wart with no change. Threw a voltmeter on and checked voltages and the ground pin on the chip is actually at +4.9 V relative to the arduino ground on the header pin. The 5V pin is a steady 5V whether powered off of USB, 9V battery or wall power, but that’s just DC voltage with a slow voltmeter, so it doesn’t rule out a brown-out.

I’m going to verify with Sparkfun that the grounds should all be connected. If that’s the case I think I should fix that first.

Sleepydoc:
the ground pin on the chip is actually at +4.9 V relative to the arduino ground on the header pin.

That doesn't sound very good at all. Clearly, all grounds for all devices should be at the same potential - off-board or on. I assumed that you were using the same sort of thing as me -a Tiny RTC module soldered into a shield or the like, with GND securely connected to GND. I now think you are doing something else.

I'm using this: SparkFun Real Time Clock Module - BOB-12708 - SparkFun Electronics

As near as I can tell from the schematic, all the grounds should be connected (I can't imagine why they wouldn't be). All the contacts that should be at ground are connected (RTC chip pin, Battery negative, capacitor neg) except the header pin that connects to Arduino ground. We'll see what spark fun has to say. Thinking I may just ditch the whole thing and get one of these ChronoDot - Ultra-precise Real Time Clock [v2.1] : ID 255 : $17.50 : Adafruit Industries, Unique & fun DIY electronics and kits from Adafruit.

Sleepydoc:
(I can't imagine why they wouldn't be).

Indeed

I have several DS1307 from here, and all are fine

http://www.ebay.com.au/itm/1PCS-for-arduino-AVR-PIC-51-ARM-I2C-RTC-DS1307-AT24C32-Real-Time-Clock-Module-/271241953886?pt=AU_B_I_Electrical_Test_Equipment&hash=item3f2747c25e

The Adafruit is a DS3231, which is more accurate than the DS1307. I have one but have not yet used it.

http://www.ebay.com.au/itm/300939040180?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1497.l2648

Sleepydoc:
I'm using this: SparkFun Real Time Clock Module - BOB-12708 - SparkFun Electronics

As near as I can tell from the schematic, all the grounds should be connected (I can't imagine why they wouldn't be). All the contacts that should be at ground are connected (RTC chip pin, Battery negative, capacitor neg) except the header pin that connects to Arduino ground. We'll see what spark fun has to say. Thinking I may just ditch the whole thing and get one of these ChronoDot - Ultra-precise Real Time Clock [v2.1] : ID 255 : $17.50 : Adafruit Industries, Unique & fun DIY electronics and kits from Adafruit.

The schematics tells us that all grounds are connected. Is your board different? Is any of the pins/points labeled with GND not connected to the others?

Vbat is the voltage between GND and the Vbat pin. With a new coin cell this is probably higher than promised on the battery's label. Measure it, you'll probably be surprised. USB power is below 5V in many cases so connecting an external power supply to the Arduino's power input is the first thing I would try. Don't use a 9V battery, block batteries often are not fast enough to deliver current.

pylon:
Don't use a 9V battery, block batteries often are not fast enough to deliver current.

Hah! Yes, that would be a likely trap.

So after struggling for a week thinking the code was bad, it turns out it was a cold solder joint. It looked fine, but after figuring out that the ground pin on the header wasn't connected I took the soldering iron and re-heated the joint and now it works perfectly.

Still can't explain why it mis-behaved as consistently as it did; I would think that a floating ground would be much more erratic, but it's working now, so I'm happy.

Thanks for everyone's assistance - especially to Pylon for asking about the voltage.