DS1338 RTC library RTC + 55 bytes nvram

This library let you access a DS1338, which includes a RTC and some nvram.

Most of the mbed chip already have a good rtc, but they can't be powered by a separate backup battery.

With a DS1338, plus a small lithium 3V battery, you will keep trace of time.

You will also have 55 bytes (DS1338 says 56 bytes, but I use one of them for the library) of NVRAM backed up by the battery, to store fast changing data (which would tear down an eeprom), and keep it, even in the case of a watchdog reset.

Demo code

#include "mbed.h"
#include "fr_time.h"
#include "ds1338.h"

int main() {
    struct tm time;
    int count;

    pc=new RawSerial(USBTX, USBRX);
    pc->baud(115200);
    pc->printf("DS1338 Demo\r\n");
    DS1338 ds1338(P0_19,P0_20);
#ifdef INIT_TIME
    count=0;
    time.tm_sec=0;
    time.tm_min=0;
    time.tm_hour=8;
    time.tm_mday=4;
    time.tm_mon=2;
    time.tm_year=115;
    time.tm_wday=1;
    time.tm_yday=0;
    time.tm_isdst=0;
    ds1338.writeTime(&time);
#endif


    while (true) {
        wait(0.5);
        ds1338.readTime(&time);
        ds1338.read(0,4,(char *)(&count));
        count++;
        ds1338.write(0,4,(char *)(&count));
        pc->printf("loop %d at %s\r\n",count,asctime(&time));
    }
}

ds1338.cpp

Committer:
scachat
Date:
2015-03-04
Revision:
1:e77d69913c46
Parent:
0:0ffb7046206a

File content as of revision 1:e77d69913c46:

#include "mbed.h"
#include "ds1338.h"

/*
 * Constructor, initialize the ds1338 on i2c interface.
 * @param sda : sda i2c pin (PinName)
 * @param scl : scl i2c pin (PinName)
*/
DS1338::DS1338(PinName sda, PinName scl): _i2c(sda, scl) {
    _i2c.frequency(400000);
    buffer[0]=0x07;
    _i2c.write(DS1338_ADR,buffer,1,true);
    _i2c.read(DS1338_ADR,buffer,1);
    if (buffer[0]&0x20){
       buffer[0]=0x07;
       buffer[1]=0xB0;//do not erase error condition !
    }else{
       buffer[0]=0x07;
       buffer[1]=0x90;
    }
    _i2c.write(DS1338_ADR,buffer,1+1);
}
/**
 * read bytes from nvram (55 bytes available)
 * @param adr the start address (starts at 0)
 * @param count number of byte to read
 * @param data where to put the bytes
 * @return the byte
 */
void DS1338::read(unsigned char adr,unsigned char count,char * data) {
    if (count>DS1338_BUFFER_SIZE) {
        count=DS1338_BUFFER_SIZE;
    }
    buffer[0]=9+adr;
    _i2c.write(DS1338_ADR,&(buffer[0]),1,true);
    _i2c.read(DS1338_ADR,data,count);
}
/**
 * write bytes to nvram (55 bytes available)
 * @param adr the start address (starts at 0)
 * @param count number of byte to write
 * @param data to be written
 * @return the byte
 */
void DS1338::write(unsigned char adr,unsigned char count,char * data) {
    if (count>DS1338_BUFFER_SIZE-1) {
        count=DS1338_BUFFER_SIZE-1;
    }
    buffer[0]=9+adr;
    for (unsigned char i=0; i<count; i++) {
        buffer[1+i]=*(data+i);
    }
    _i2c.write(DS1338_ADR,buffer,1+count);
}
/**
 * read the current time
 * @param x the time;
 */
void DS1338::readTime(tm * time) {
    buffer[0]=0;
    _i2c.write(DS1338_ADR,&(buffer[0]),1,true);
    _i2c.read(DS1338_ADR,buffer,9);
    time->tm_sec=((buffer[0]>>4)&0x07)*10+(buffer[0]&0x0F);
    time->tm_min=((buffer[1]>>4)&0x07)*10+(buffer[1]&0x0F);
    time->tm_hour=((buffer[2]>>4)&0x03)*10+(buffer[2]&0x0F);
    time->tm_mday=((buffer[4]>>4)&0x03)*10+(buffer[4]&0x0F);
    time->tm_mon=((buffer[5]>>4)&0x01)*10+(buffer[5]&0x0F)-1;
    time->tm_year=((buffer[6]>>4)&0x0F)*10+(buffer[6]&0x0F);
    if (time->tm_year<70){
       time->tm_year+=100;
    }
    time->tm_wday=buffer[3]&0x07;
    time->tm_yday=0;
    time->tm_isdst=0;
    if (time->tm_sec>=60||
        time->tm_min>=60||
        time->tm_hour>=24||
        time->tm_mday>31 || time->tm_mday<1||
        time->tm_mon>11||
        time->tm_wday>=7||
        buffer[0x08]!=0xCA||//checksum
        (buffer[0x07]&0x20)!=0){//error condition
          time->tm_sec=0;
          time->tm_min=0;
          time->tm_hour=0;
          time->tm_mday=1;
          time->tm_mon=0;
          time->tm_year=70;
          time->tm_wday=1;
          time->tm_yday=0;
          time->tm_isdst=0;
          writeTime(time);
        }
}
/**
 * write the current time
 * @param time the time;
 */
void DS1338::writeTime(tm * time) {
   buffer[0]=0;
   buffer[1]=(((time->tm_sec/10)<<4)+(time->tm_sec%10))&0x7F;//clock not halted
   buffer[2]=(((time->tm_min/10)<<4)+(time->tm_min%10))&0x7F;
   buffer[3]=(((time->tm_hour/10)<<4)+(time->tm_hour%10))&0x3F;//mode 24h
   buffer[4]=(time->tm_wday)&0x03;
   buffer[5]=(((time->tm_mday/10)<<4)+(time->tm_mday%10))&0x3F;
   buffer[6]=((((time->tm_mon+1)/10)<<4)+((time->tm_mon+1)%10))&0x1F;
   buffer[7]=((((time->tm_year%100)/10)<<4)+(time->tm_year%10))&0xFF;
   buffer[8]=0x90;//1Hz, erase error cond
   buffer[9]=0xCA;
   _i2c.write(DS1338_ADR,buffer,1+9);
}