DS1388 RTC

Hi,

I'm doing some experiments with this chip, my setup is a breadboarded atmega328P-PU running @ 8MHz with the internal oscillator, the board is powered @ 3.3V and everything runs fine except that I cannot set (or maybe get?) the correct year from the RTC.

I modified the RTClib to support theDS1388 as follows:

void RTC_DS1388::adjust(const DateTime& dt) {
    Wire.beginTransmission(DS1307_ADDRESS);
    Wire.write(i);
    Wire.write(bin2bcd(0)); // hundreds of seconds 0x00
    Wire.write(bin2bcd(dt.second())); // 0x01
    Wire.write(bin2bcd(dt.minute())); // 0x02
    Wire.write(bin2bcd(dt.hour())); // 0x03
    Wire.write(bin2bcd(0)); // 0x04
    Wire.write(bin2bcd(dt.day())); // 0x05
    Wire.write(bin2bcd(dt.month())); // 0x06
    Wire.write(bin2bcd(dt.year() - 2000)); // 0x07
    /*
    Wire.write(i); // 0x08
    Wire.write(i); // 0x09
    Wire.write(i); // 0x0A
    Wire.write(i); // 0x0B
    Wire.write(i); // 0x0C
    */
    Wire.endTransmission();
}

DateTime RTC_DS1388::now() {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(i);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);
  uint8_t hs = bcd2bin(Wire.read() & 0x7F);  // hundreds of seconds
  uint8_t ss = bcd2bin(Wire.read() & 0x7F);
  uint8_t mm = bcd2bin(Wire.read());
  uint8_t hh = bcd2bin(Wire.read());
  Wire.read();
  uint8_t d = bcd2bin(Wire.read());
  uint8_t m = bcd2bin(Wire.read());
  uint16_t y = bcd2bin(Wire.read()) + 2000;

  return DateTime (y, m, d, hh, mm, ss);
}

but all I get, whatever the year I set is always 2165 (end of the world?)

It comes from 2000 + 165 (converted from BCD) ... 165 must have something special: is the value I got for all bytes when I ran the unprogammed RTC the first time.

From the datasheet, the only difference from the DS1307 (which works perfectly @ 5V in the same circuit) is the first address which contains hundred seconds in the DS1388, so I just ignored this byte and shifted all by one in respect to the DS1307.

Any idea or suggestion?

Might be a broken chip... but hour, minute, second, month and day works just fine.

You request 7 bytes and then try to read 8 bytes.

Also, what is the value 'i' being written?

johnwasser:
You request 7 bytes and then try to read 8 bytes.

Also, what is the value 'i' being written?

Oh silly me!

Thanks you, its true that 4 eyballs are better than 2, it works perfectly now.

i is just integer 0 in the lib, should have a better name though.

Hi,

For anyone else stumbling across this topic, I've got a few pieces of info I've learnt from using the DS1388 with an arduino.

Firstly, you need to change isRunning, because the register in question is in a different place!

Secondly, you need to change the adjust code to actually clear the 'time invalid' flag.

There's also some watchdog issues if anyone uses those, which I will post separately.

So, here are my 3 modified functions, adjust(), isRunning() and now()

uint8_t RTC_DS1307::isrunning(void) {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0x0b);	
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 1);
  uint8_t ss = Wire.read();
  return !(ss>>7);
}

void RTC_DS1307::adjust(const DateTime& dt) {
    Wire.beginTransmission(DS1307_ADDRESS);
    Wire.write(i);
    Wire.write(bin2bcd(0)); // hundreds of seconds 0x00
    Wire.write(bin2bcd(dt.second())); // 0x01
    Wire.write(bin2bcd(dt.minute())); // 0x02
    Wire.write(bin2bcd(dt.hour())); // 0x03
    Wire.write(bin2bcd(0)); // 0x04
    Wire.write(bin2bcd(dt.day())); // 0x05
    Wire.write(bin2bcd(dt.month())); // 0x06
    Wire.write(bin2bcd(dt.year() - 2000)); // 0x07
    Wire.endTransmission();

	Wire.beginTransmission(DS1307_ADDRESS);
	Wire.write(0x0b);
	Wire.write(0x00);			//clear the flag bit (OSF)
	Wire.endTransmission();
}

DateTime RTC_DS1307::now() {
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(i);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 8);
  uint8_t hs = bcd2bin(Wire.read() & 0x7F);  // hundreds of seconds
  uint8_t ss = bcd2bin(Wire.read() & 0x7F);
  uint8_t mm = bcd2bin(Wire.read());
  uint8_t hh = bcd2bin(Wire.read());
  Wire.read();
  uint8_t d = bcd2bin(Wire.read());
  uint8_t m = bcd2bin(Wire.read());
  uint16_t y = bcd2bin(Wire.read()) + 2000;

  return DateTime (y, m, d, hh, mm, ss);
}

Watchdogs then!

My circuit has the arduino in a deep sleep, woken up every 60 seconds by the RTC interrupt, which then does some logging, and goes straight back to sleep. Nearly ripped my hair out trying to find out why this didn't work the way I wanted.

Here's what I learnt:

To initialise it in the first place the data sheet says it needs to be disabled before you can write to the watchdog time registers, then re-enabled.

  //Disable the RTC watchdog first.
  Wire.beginTransmission(0x68);  
  Wire.write(0x0c);
  Wire.write(0x00);  
  Wire.endTransmission();

  //Set the watchdog timer to 60 seconds
 Wire.beginTransmission(0x68);
  Wire.write(0x08);
  Wire.write(0x00);  //08h    
  Wire.write(0x60);  //09h - time 60 seconds
  Wire.write(0x00);  //0ah
  Wire.write(0x00);  //0bh - clear the triggered bit.
  Wire.endTransmission();  
   
  //Enable the watchdog timer in the RTC.  0x0c -> 0x03 (WDE and WDE/RST)
  Wire.beginTransmission(0x68);
  Wire.write(0x0c);
  Wire.write(0x03);
  Wire.endTransmission();

  attachInterrupt(1, onWake, RISING);   //here's my interrupt handler.

Once it wakes you up, you need to do the following to make it go off in another minute - if you don't, it will never fire again!
You need to re-specify the time, and clear the 'triggered' bit in the 0x0b register, then you can safely sleep, and it will wake you in another 60 seconds :slight_smile:

  //Reset the watchdog timer
  Wire.beginTransmission(0x68);
  Wire.write(0x08);
  Wire.write(0x00);  //08h    
  Wire.write(0x60);  //09h - time 60 seconds.
  Wire.write(0x00);  //0ah
  Wire.write(0x00);  //0bh - clear the triggered bit.
  Wire.endTransmission();

Thanks for your code and ideas,

it would be nice if you could rename the class to match the chip DS1307 -> DS1388 and upload the code on github, I'm sure that somebody will cooperate to check and maybe improve the library.

Thanks!

I did wonder whether it might be better to adjust the class heirarchy a bit, and have a core DSRTC class, with two subclasses (DS1388 and DS1307) etc to improve code re-use.

One problem I've found with some libraries like the DS1307 is that it isn't maintained in simply one place. I wonder if the arduino 'core' project team has considered adopting it like the I2C libraries etc? If so, it'd be clear who owned it, and therefore who to submit patches to.

Any thoughts ? :slight_smile:

Any thoughts ?

Take ownership?

Your proposal makes a lot of sense!
Maybe not primary for code reuse but at least for interface reuse, so all those RTC's can be called in the same manner.

I can review the code if you want.

Ooh, that'd be interesting!

Take ownership, as in the Arduino project taking ownership?

I could hack the code into some semblance of order certainly, but I'd not have the time to 'maintain' it separately outside the Arduino family.

David

but I'd not have the time to 'maintain' it separately outside the Arduino family.

I understand, I maintain some code myself (on playground) and I must say the first releases were hardest :wink:

To drive the DS1388 I used https://github.com/jcw/rtclib , I modified the lib adding a DS1388 class.

I could fork the original lib on github, add my modifications, and you can then add yours.
Or we can do the opposite: you fork (or just start a new repo if yours does not inherit from RTCLib) and I add my modifications (if needed).

I think that github is a very good way to distribute development efforts and maintain the code.

I don't think this lib will ever go into the Arduino core, there are so many chips out there that supporting them all would be a real nightmare for core maintainers.

Hi elpaso,

If you're happy to fork the lib and add your changes, I can add mine on top. Be interested to see what else you did :slight_smile:

Cheers,

David

Hi,

sorry for the delay, I forked RTClib and added initial support for DS1388

it's far from being complete (watchdog and charger are completely missing), but it's a start :wink:

Great!

I will try to figure out how github works (I was used to cvs in the past!) and am a bit out of date w.r.t. modern source control!

I will send a patch for my changes to isRunning, and adjust().

Cheers,

David

Oh, and another problem I found with the DS1388.

It's very sensitive to any crystal instability, so touching the contacts of the crystal while it's running is enough to upset it and make isRunning() return false.

Problem fixed by coating those pins and the short length of track between them and the ds1388 with hot glue. Solved :slight_smile:

Hi David,

I think "isRunning" doesn't exists anymore in the lib, to tell you the truth I was using an older version with isRunning already in place but when I forked I noticed that it has been dropped meanwhile.

We could add it back and ask for a merge (pull request in git jargon), it was definitely a useful function to initalize the clock with compile time when loading the sketch.

Another recent addition to RTClib is an intial support for PCF8563, I've also patched a working lib in the past, it's here: GitHub - elpaso/Rtc_Pcf8563: Arduino Pcf8563 RTC library. A fixed/expanded version of the original Rtc_Pcf8563 , it would be nice to merge the two...

Fork created, changes added, pull request sent :slight_smile:

David

I think isrunning() is something in the ladyada fork of jcw's lib, but never got put back into the original jcw one... Which is a pity.

I've added it back into the pull request I sent :slight_smile:

Merged and pull-requested to jcw :slight_smile:

I agree that isRunning was useful, I asked to pull it.

https://github.com/jcw/rtclib/pull/4

Many thanks for the code revision and corrections !

jcw merged the pull:

https://github.com/jcw/rtclib/pull/4

It's always a pleasure to see how people cooperates to build better code, thank you all!

I really love open source!!!