Library for Real Time Clock module MCP97410 based on Library for DS1307

Fork of RTC-DS1307 by Henry Leinen

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Rtc_Mcp97410.cpp Source File

Rtc_Mcp97410.cpp

00001 #include "mbed.h"
00002 #include "Rtc_Mcp97410.h"
00003 
00004 #ifndef DEBUG
00005 #define DEBUG
00006 #endif
00007 #include "debug.h"
00008 
00009 const char *Rtc_Mcp97410::m_weekDays[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };
00010 
00011 
00012 Rtc_Mcp97410::Rtc_Mcp97410(I2C* i2c)
00013 {
00014 
00015     _i2c = i2c;
00016     if (_i2c == NULL)
00017         error("Rtc_Mcp97410: no I2C specified");
00018 
00019     // Set the frequency to standard 100kHz
00020     // MCP97410 can handle full 400kHz-speed!
00021     //_i2c->frequency(100000);
00022 }
00023 
00024 Rtc_Mcp97410::~Rtc_Mcp97410()
00025 {
00026 
00027 }
00028 
00029 bool Rtc_Mcp97410::setTime(Time_rtc& time, bool start, bool thm)
00030 {
00031     char buffer[7];
00032     INFO("reading clock registers to write the new time : %d:%d:%d\n", time.hour , time.min , time.sec );
00033     if (!readRTC(ADDR_SEC,buffer,7)) {
00034         ERR("Failed to read from RTC\n");
00035         return false;
00036     }
00037     //  Now update only the time part (saving the existing flags)
00038     if (start) {
00039         buffer[ADDR_SEC] |= START_32KHZ;
00040     } else {
00041         buffer[ADDR_SEC] &= ~START_32KHZ;
00042     }
00043     buffer[ADDR_SEC] = (buffer[ADDR_SEC]& START_32KHZ) | (decimalToBcd(time.sec )& ~START_32KHZ);
00044     buffer[ADDR_MIN] = decimalToBcd(time.min );
00045     if (thm) {
00046         //  AM PM format
00047         buffer[ADDR_HOUR] = HOUR_12 | (time.hour >12 ? (0x20 | ((decimalToBcd(time.hour -12)))) : decimalToBcd(time.hour ));
00048     } else {
00049         // 24 hours format: HOUR_12 is 0
00050         buffer[ADDR_HOUR] = decimalToBcd(time.hour ) & 0x3F;
00051     }
00052     // bit 3 of register 03 on MCP97410 is VBATEN (different to DS1307)!
00053     // should be set to 1 to enable Battery-Backup
00054     buffer[ADDR_DAY] = VBATEN | (time.wday  & 0x07);
00055     buffer[ADDR_DATE] = decimalToBcd(time.date );
00056     buffer[ADDR_MNTH] = decimalToBcd(time.mon );
00057     buffer[ADDR_YEAR] = decimalToBcd(time.year -2000);
00058     INFO("Writing new time and date data to RTC\n");
00059     if (!writeRTC(ADDR_SEC, buffer, 7) ) {
00060         ERR("Failed to write the data to RTC!\n");
00061         return false;
00062     }
00063     return true;
00064 }
00065 
00066 bool Rtc_Mcp97410::getTime(Time_rtc& time)
00067 {
00068     char buffer[7];
00069     bool thm = false;
00070 
00071     INFO("Getting time from RTC\n");
00072     if (!readRTC(ADDR_SEC, buffer, 7) ) {
00073         //  Failed to read
00074         ERR("Failed to read from RTC\n");
00075         return false;
00076     }
00077     thm = ((buffer[ADDR_HOUR] & HOUR_12) == HOUR_12);
00078     time.sec  = bcdToDecimal(buffer[ADDR_SEC]&0x7F);
00079     time.min  = bcdToDecimal(buffer[ADDR_MIN]);
00080     if (thm) {
00081         // in 12-hour-mode, we need to add 12 hours if PM bit is set
00082         time.hour  = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_HOUR] & 0x1F );
00083         if ((buffer[ADDR_HOUR] & PM) == PM)
00084             time.hour  += 12;
00085     } else {
00086         time.hour  = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_HOUR] & 0x3F );
00087     }
00088     time.wday  = buffer[ADDR_DAY] & 0x07;
00089     INFO("OSCRUN:%0d PWRFAIL:%0d VBATEN:%0d\n", (buffer[ADDR_STAT]>>5) & 0x01, buffer[ADDR_STAT]>>4 & 0x01, buffer[ADDR_STAT]>>3 & 0x01);
00090     time.date  = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_DATE]);
00091     time.mon  = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_MNTH]);
00092     time.year  = Rtc_Mcp97410::bcdToDecimal(buffer[ADDR_YEAR]) + 2000;   //  plus hundret is because RTC is giving the years since 2000, but std c struct tm needs years since 1900
00093 
00094     return true;
00095 }
00096 
00097 
00098 bool Rtc_Mcp97410::startClock()
00099 {
00100     char strtStop;
00101 
00102     INFO ("Reading clock start/stop register value\n");
00103     if (!readRTC(ADDR_SEC, &strtStop, 1)) {
00104         ERR("Failed to read clock start stop register !\n");
00105         return false;
00106     }
00107     //set bit
00108     strtStop |= START_32KHZ;
00109 
00110 
00111     INFO("Writing back start/stop register value\n");
00112     if (!writeRTC(ADDR_SEC, &strtStop, 1)) {
00113         ERR("Failed to write the start stop register !\n");
00114         return false;
00115     }
00116 
00117     INFO("Start/stop register value successfully written\n");
00118     return true;
00119 }
00120 
00121 bool Rtc_Mcp97410::stopClock()
00122 {
00123     char strtStop;
00124 
00125     INFO ("Reading clock start/stop register value\n");
00126     if (!readRTC(ADDR_SEC, &strtStop, 1)) {
00127         ERR("Failed to read clock start stop register !\n");
00128         return false;
00129     }
00130     //clear bit
00131     strtStop &= ~START_32KHZ;
00132 
00133     INFO("Writing back start/stop register value\n");
00134     if (!writeRTC(ADDR_SEC, &strtStop, 1)) {
00135         ERR("Failed to write the start stop register !\n");
00136         return false;
00137     }
00138 
00139     INFO("Start/stop register value successfully written\n");
00140     return true;
00141 }
00142 
00143 bool Rtc_Mcp97410::setSquareWaveOutput(bool ena, SqwRateSelect_t rs)
00144 {
00145     char reg;
00146     INFO("Reading register value first\n");
00147 
00148     if (!readRTC(ADDR_CTRL,&reg, 1)) {
00149         ERR("Failed to read RTC register value !\n");
00150         return false;
00151     }
00152     INFO("[Reg:0x07] = %02x\n", reg);
00153 
00154     //  preserve the OUT control bit while writing the frequency and enable bits
00155     reg = (reg & OUT_PIN) | (ena ? 0x10 : 0) | ((char)rs & 0x03);
00156 
00157     INFO("Writing back register value\n");
00158     INFO("[Reg:0x07] = %02x\n", reg);
00159 
00160     if (!writeRTC(ADDR_CTRL, &reg, 1)) {
00161         ERR("Failed to write register value !\n");
00162         return false;
00163     }
00164 
00165     INFO("Successfully changed the square wave output.\n");
00166     return true;
00167 }
00168 
00169 
00170 
00171 bool Rtc_Mcp97410::read(int control_byte, int address, char *buffer, int len)
00172 {
00173     char buffer2[2] = {(char)address, 0};
00174 
00175 //    _i2c->start();
00176     if (_i2c->write(control_byte, buffer2, 1) != 0) {
00177         ERR("Failed to write register address on RTC or EEPROM!\n");
00178         _i2c->stop();
00179         return false;
00180     }
00181     if (_i2c->read(control_byte, buffer, len) != 0) {
00182         ERR("Failed to read register !\n");
00183         return false;
00184     }
00185     _i2c->stop();
00186 
00187     INFO("Successfully read %d bytes from RTC or EEPROM\n", len);
00188     return true;
00189 }
00190 
00191 bool Rtc_Mcp97410::readRTC(int address, char *buffer, int len)
00192 {
00193     return read(ADDR_RTCC, address,buffer, len);
00194 }
00195 
00196 bool Rtc_Mcp97410::readEEPROM(int address, char *buffer, int len)
00197 {
00198     return read(ADDR_EEPROM, address,buffer, len);
00199 }
00200 
00201 bool Rtc_Mcp97410::write(int control_byte, int address, char *buffer, int len)
00202 {
00203     char buffer2[10];
00204     buffer2[0] = address&0xFF;
00205     for (int i = 0 ; i < len ; i++)
00206         buffer2[i+1] = buffer[i];
00207 
00208 //    _i2c->start();
00209     if (_i2c->write(control_byte, buffer2, len+1) != 0) {
00210         ERR("Failed to write data to rtc or EEPROM\n");
00211         _i2c->stop();
00212         return false;
00213     }
00214     _i2c->stop();
00215     INFO("Successfully written %d bytes to RTC or EEPROM\n", len);
00216     return true;
00217 }
00218 
00219 
00220 bool Rtc_Mcp97410::writeRTC(int address, char *buffer, int len)
00221 {
00222     return write(ADDR_RTCC, address,buffer, len);
00223 }
00224 
00225 bool Rtc_Mcp97410::writeEEPROM(int address, char* buffer, int len)
00226 {
00227     if (len <=8) {
00228         return write(ADDR_EEPROM, address,buffer, len);
00229     } else {
00230         ERR("Can write maximum 8 Bytes to EEPROM in one call\n");
00231         return false;
00232     }
00233 }
00234 
00235 
00236 uint8_t Rtc_Mcp97410::readTrim()
00237 {
00238     uint8_t  trim;
00239     if (readRTC(ADDR_CAL, (char *) &trim, 1)) {
00240         INFO("OSCTRIM: %02X \n", trim);
00241         return trim;
00242     } else {
00243         return 0;
00244     }
00245 }
00246 
00247 bool Rtc_Mcp97410::incTrim()
00248 {
00249     uint8_t  trim;
00250     uint8_t  trim_val;
00251     uint8_t  trim_sign;
00252 
00253     readRTC(ADDR_CAL, (char *) &trim, 1);
00254     trim_val = 0x7F&trim;
00255     trim_sign= trim >> 7;
00256     if (trim_sign == 1) {
00257         // positive: inc
00258         if (trim_val < 0x7F) {
00259             trim_val = trim_val++;
00260         }
00261     } else {
00262         // negative: dec
00263         if (trim_val != 0) {
00264             trim_val = trim_val--;
00265         } else {
00266             // change sign
00267             trim_sign = 1;
00268         }
00269     }
00270     trim = trim_sign <<7 | trim_val;
00271     INFO("incTrim: New TRIM: %02X\n", trim);
00272     return writeRTC(ADDR_CAL, (char *) &trim, 1);
00273 }
00274 
00275 bool Rtc_Mcp97410::decTrim()
00276 {
00277     uint8_t  trim;
00278     uint8_t  trim_val;
00279     uint8_t  trim_sign;
00280 
00281     readRTC(ADDR_CAL, (char *) &trim, 1);
00282     trim_val = 0x7F&trim;
00283     trim_sign= trim >> 7;
00284     if (trim_sign == 0) {
00285         // negative: inc
00286         if (trim_val < 0x7F) {
00287             trim_val = trim_val++;
00288         }
00289     } else {
00290         // positive: dec
00291         if (trim_val != 0) {
00292             trim_val = trim_val--;
00293         } else {
00294             // change sign
00295             trim_sign = 0;
00296         }
00297     }
00298     trim = trim_sign <<7 | trim_val;
00299     INFO("decTrim: New TRIM: %02X\n", trim);
00300     return writeRTC(ADDR_CAL, (char *) &trim, 1);
00301 }
00302 
00303 bool Rtc_Mcp97410::disableEEPROMWrite()
00304 {
00305     // protect all EEPROM from write operations
00306     // set STATUS_REGISTER 0xFF bits 2 and 3
00307     char reg = 0x0C;
00308     return write(ADDR_EEPROM, ADDR_EEPROM_SR,&reg, 1);
00309 }
00310 
00311 
00312 bool Rtc_Mcp97410::enableEEPROMWrite()
00313 {
00314     // enable  all EEPROM write operations
00315     // unset STATUS_REGISTER 0xFF bits 2 and 3
00316     char reg = 0x00;
00317     return write(ADDR_EEPROM, ADDR_EEPROM_SR,&reg, 1);
00318 }
00319 
00320 bool Rtc_Mcp97410::readEUI48(uint8_t* eui48)
00321 {
00322     //EUI48 start at EEPROM-address 0xF2
00323     return(readEEPROM(0xF2,(char *) eui48,6));
00324 }
00325 
00326 bool Rtc_Mcp97410::writeEUI48(uint8_t* eui48)
00327 {
00328     //EUI48 start at EEPROM-address 0xF2
00329     return(writeEEPROM(0xF2,(char *) eui48,6));
00330 }
00331 
00332 bool Rtc_Mcp97410::readEUI64(uint8_t* eui64)
00333 {
00334     //EUI64 start at EEPROM-address 0xF2
00335     return(readEEPROM(0xF0,(char *) eui64,8));
00336 }
00337 
00338 
00339 bool Rtc_Mcp97410::writeEUI64(uint8_t* eui64)
00340 {
00341     //EUI64 start at EEPROM-address 0xF2
00342     return(writeEEPROM(0xF0,(char *) eui64,8));
00343 }
00344 
00345 bool Rtc_Mcp97410::unlockEUI()
00346 {
00347     // unlock the special EEPROM area
00348     // write 0x55 and then 0xAA to the EEUNLOCK-register
00349     char reg =0x00;
00350     bool result = true;
00351 
00352     reg = 0x55;
00353     result &= writeRTC(ADDR_ULID,&reg,1);
00354     reg = 0xAA;
00355     result &= writeRTC(ADDR_ULID,&reg,1);
00356     if (result) {
00357         INFO("Successfully UNLOCKED the EUI-Area in EEPROM\n");
00358         return true;
00359     } else {
00360         ERR("Error in UNLOCKING the EUI-Area in EEPROM\n");
00361         return false;
00362     }
00363 }
00364 
00365 RtcCls::RtcCls(I2C* i2c, PinName sqw, bool bUseSqw)
00366     : Rtc_Mcp97410(i2c), m_sqw(sqw), m_bUseSqw(bUseSqw), m_bAlarmEnabled(false), m_alarmfunc(NULL)
00367 {
00368     Time_rtc t;
00369     //  query time from device
00370     getTime(t);
00371     //  sync the time with MBED RTC
00372     struct tm now = {t.sec, t.min, t.hour, t.date, t.mon-1, t.year-1900};
00373     m_time = mktime(&now);
00374     set_time(m_time);
00375 
00376     //  Only register the callback and start the SQW if requested to do so. Otherwise the system
00377     //  will use the MBED built-in RTC.
00378     if (m_bUseSqw) {
00379         //  start the wave
00380         setSquareWaveOutput(true, RS1Hz);
00381         //  register callback from now on the time will be maintained by the square wave input
00382         m_sqw.rise(this, &RtcCls::_callback);
00383     }
00384 }
00385 
00386 void RtcCls::_callback(void)
00387 {
00388 //    INFO("Tick!");
00389     //  Simply increase the number of seconds
00390     m_time++;
00391 //    if (m_bAlarmEnabled && (m_time == m_alarmTime)) {
00392 //        if (m_alarmfunc != NULL)
00393 //            m_alarmfunc();
00394 //        m_bAlarmEnabled = false;
00395 //    }
00396 }
00397 
00398 time_t RtcCls::getTime()
00399 {
00400     //  when not using the HW support, we have to query the RTC chip. Other wise we can just return out stored value
00401     if (!m_bUseSqw) {
00402         Time_rtc t;
00403         getTime(t);
00404         struct tm now = {t.sec, t.min, t.hour, t.date, t.mon-1, t.year-1900};
00405         m_time = mktime(&now);
00406         INFO("getting time %02d.%02d.%04d %02d:%02d:%02d Ticks=%08lx", t.date, t.mon, t.year, t.hour, t.min, t.sec, m_time);
00407     } else {
00408         INFO("getting time Ticks=%08lx", m_time);
00409     }
00410     return m_time;
00411 }
00412 
00413 void RtcCls::setTime(time_t t)
00414 {
00415     Time_rtc tim;
00416     struct tm *now;
00417     now = localtime(&t);
00418 
00419     tim.sec = now->tm_sec;
00420     tim.min = now->tm_min;
00421     tim.hour = now->tm_hour;
00422     tim.date = now->tm_mday;
00423     tim.mon = now->tm_mon+1;
00424     tim.year = now->tm_year + 1900;
00425     tim.wday = now->tm_wday +1;
00426 
00427     setTime( tim, true, true);
00428     set_time(t);
00429 }