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

Fork of RTC-DS1307 by Henry Leinen

Revision:
11:ef48dcb888c9
Parent:
10:780027029afe
Child:
12:88f82e47b6a1
--- a/Rtc_Mcp97410.cpp	Wed Jan 07 21:46:02 2015 +0000
+++ b/Rtc_Mcp97410.cpp	Fri Jan 16 20:44:51 2015 +0000
@@ -6,54 +6,57 @@
 #endif
 #include "debug.h"
 
-const char *Rtc_Mcp97410::m_weekDays[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };    
+const char *Rtc_Mcp97410::m_weekDays[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };
 
 
 Rtc_Mcp97410::Rtc_Mcp97410(I2C* i2c)
 {
-   
-    m_rtc = i2c;
-    if (m_rtc == NULL)
+
+    _i2c = i2c;
+    if (_i2c == NULL)
         error("Rtc_Mcp97410: no I2C specified");
-        
+
     // Set the frequency to standard 100kHz
     // MCP97410 can handle full 400kHz-speed!
-    //m_rtc->frequency(100000);
+    //_i2c->frequency(100000);
 }
 
 Rtc_Mcp97410::~Rtc_Mcp97410()
 {
-    
+
 }
 
 bool Rtc_Mcp97410::setTime(Time_rtc& time, bool start, bool thm)
 {
     char buffer[7];
     INFO("reading clock registers to write the new time : %d:%d:%d\n", time.hour, time.min, time.sec);
-    if (!read(0,buffer,7)) {
+    if (!readRTC(ADDR_SEC,buffer,7)) {
         ERR("Failed to read from RTC\n");
         return false;
     }
     //  Now update only the time part (saving the existing flags)
-    if (start) { buffer[0] |= 0x80; } else { buffer[0] &= 0x7F; }
-    buffer[0] = (buffer[0]&0x80) | (decimalToBcd(time.sec)& 0x7f);
-    buffer[1] = decimalToBcd(time.min);
+    if (start) {
+        buffer[ADDR_SEC] |= START_32KHZ;
+    } else {
+        buffer[ADDR_SEC] &= ~START_32KHZ;
+    }
+    buffer[ADDR_SEC] = (buffer[ADDR_SEC]& START_32KHZ) | (decimalToBcd(time.sec)& ~START_32KHZ);
+    buffer[ADDR_MIN] = decimalToBcd(time.min);
     if (thm) {
         //  AM PM format
-        buffer[2] = (buffer[2]& 196) | (time.hour>12 ? (0x20 | ((decimalToBcd(time.hour-12)))) : decimalToBcd(time.hour));
-    }
-    else {
-        // 24 hours format
-        buffer[2] = (buffer[2]& 196) | (decimalToBcd(time.hour) & 0x3F);
+        buffer[ADDR_HOUR] = HOUR_12 | (time.hour>12 ? (0x20 | ((decimalToBcd(time.hour-12)))) : decimalToBcd(time.hour));
+    } else {
+        // 24 hours format: HOUR_12 is 0
+        buffer[ADDR_HOUR] = decimalToBcd(time.hour) & 0x3F;
     }
     // bit 3 of register 03 on MCP97410 is VBATEN (different to DS1307)!
     // should be set to 1 to enable Battery-Backup
-    buffer[3] = 0x08 | (time.wday & 0x07);
-    buffer[4] = decimalToBcd(time.date);
-    buffer[5] = decimalToBcd(time.mon);
-    buffer[6] = decimalToBcd(time.year-2000);
+    buffer[ADDR_DAY] = VBATEN | (time.wday & 0x07);
+    buffer[ADDR_DATE] = decimalToBcd(time.date);
+    buffer[ADDR_MNTH] = decimalToBcd(time.mon);
+    buffer[ADDR_YEAR] = decimalToBcd(time.year-2000);
     INFO("Writing new time and date data to RTC\n");
-    if (!write(0, buffer, 7) ) {
+    if (!writeRTC(ADDR_SEC, buffer, 7) ) {
         ERR("Failed to write the data to RTC!\n");
         return false;
     }
@@ -64,31 +67,30 @@
 {
     char buffer[7];
     bool thm = false;
-    
+
     INFO("Getting time from RTC\n");
-    if (!read(0, buffer, 7) ) {
+    if (!readRTC(ADDR_SEC, buffer, 7) ) {
         //  Failed to read
         ERR("Failed to read from RTC\n");
         return false;
     }
-    thm = ((buffer[2] & 64) == 64);
-    time.sec = bcdToDecimal(buffer[0]&0x7F);
-    time.min = bcdToDecimal(buffer[1]);
+    thm = ((buffer[ADDR_HOUR] & HOUR_12) == HOUR_12);
+    time.sec = bcdToDecimal(buffer[ADDR_SEC]&0x7F);
+    time.min = bcdToDecimal(buffer[ADDR_MIN]);
     if (thm) {
         // in 12-hour-mode, we need to add 12 hours if PM bit is set
-        time.hour = Rtc_Mcp97410::bcdToDecimal( buffer[2] & 31 );
-        if ((buffer[2] & 32) == 32)
+        time.hour = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_HOUR] & 0x1F );
+        if ((buffer[ADDR_HOUR] & PM) == PM)
             time.hour += 12;
+    } else {
+        time.hour = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_HOUR] & 0x3F );
     }
-    else {
-        time.hour = Rtc_Mcp97410::bcdToDecimal( buffer[2] & 63 );
-    }  
-    time.wday = buffer[3] & 0x07;
-    INFO("OSCRUN:%0d PWRFAIL:%0d VBATEN:%0d\n", (buffer[3]>>5) & 0x01, buffer[3]>>4 & 0x01, buffer[3]>>3 & 0x01);
-    time.date = Rtc_Mcp97410::bcdToDecimal( buffer[4]);
-    time.mon = Rtc_Mcp97410::bcdToDecimal( buffer[5]);
-    time.year = Rtc_Mcp97410::bcdToDecimal(buffer[6]) + 2000;   //  plus hundret is because RTC is giving the years since 2000, but std c struct tm needs years since 1900
-    
+    time.wday = buffer[ADDR_DAY] & 0x07;
+    INFO("OSCRUN:%0d PWRFAIL:%0d VBATEN:%0d\n", (buffer[ADDR_STAT]>>5) & 0x01, buffer[ADDR_STAT]>>4 & 0x01, buffer[ADDR_STAT]>>3 & 0x01);
+    time.date = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_DATE]);
+    time.mon = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_MNTH]);
+    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
+
     return true;
 }
 
@@ -96,22 +98,22 @@
 bool Rtc_Mcp97410::startClock()
 {
     char strtStop;
-    
+
     INFO ("Reading clock start/stop register value\n");
-    if (!read(0, &strtStop, 1)) {
+    if (!readRTC(ADDR_SEC, &strtStop, 1)) {
         ERR("Failed to read clock start stop register !\n");
         return false;
     }
-    
-    strtStop |= 0x80;
-    
-    
+    //set bit
+    strtStop |= START_32KHZ;
+
+
     INFO("Writing back start/stop register value\n");
-    if (!write(0, &strtStop, 1)) {
+    if (!writeRTC(ADDR_SEC, &strtStop, 1)) {
         ERR("Failed to write the start stop register !\n");
         return false;
     }
-    
+
     INFO("Start/stop register value successfully written\n");
     return true;
 }
@@ -119,21 +121,21 @@
 bool Rtc_Mcp97410::stopClock()
 {
     char strtStop;
-    
+
     INFO ("Reading clock start/stop register value\n");
-    if (!read(0, &strtStop, 1)) {
+    if (!readRTC(ADDR_SEC, &strtStop, 1)) {
         ERR("Failed to read clock start stop register !\n");
         return false;
     }
-    
-    strtStop &= 0x7F;
-    
+    //clear bit
+    strtStop &= ~START_32KHZ;
+
     INFO("Writing back start/stop register value\n");
-    if (!write(0, &strtStop, 1)) {
+    if (!writeRTC(ADDR_SEC, &strtStop, 1)) {
         ERR("Failed to write the start stop register !\n");
         return false;
     }
-    
+
     INFO("Start/stop register value successfully written\n");
     return true;
 }
@@ -142,69 +144,143 @@
 {
     char reg;
     INFO("Reading register value first\n");
-    
-    if (!read(7,&reg, 1)) {
-        ERR("Failed to read register value !\n");
+
+    if (!readRTC(ADDR_CTRL,&reg, 1)) {
+        ERR("Failed to read RTC register value !\n");
         return false;
     }
-    INFO("[Reg:0x07] = %02x\n", reg); 
-    
+    INFO("[Reg:0x07] = %02x\n", reg);
+
     //  preserve the OUT control bit while writing the frequency and enable bits
-    reg = (reg & 0x80) | (ena ? 0x10 : 0) | ((char)rs & 0x03);
+    reg = (reg & OUT_PIN) | (ena ? 0x10 : 0) | ((char)rs & 0x03);
 
     INFO("Writing back register value\n");
-    INFO("[Reg:0x07] = %02x\n", reg); 
-    
-    if (!write(7, &reg, 1)) {
+    INFO("[Reg:0x07] = %02x\n", reg);
+
+    if (!writeRTC(ADDR_CTRL, &reg, 1)) {
         ERR("Failed to write register value !\n");
         return false;
     }
-    
+
     INFO("Successfully changed the square wave output.\n");
     return true;
 }
 
 
 
-bool Rtc_Mcp97410::read(int address, char *buffer, int len)
+bool Rtc_Mcp97410::read(int control_byte, int address, char *buffer, int len)
 {
     char buffer2[2] = {(char)address, 0};
-    
-//    m_rtc->start();
-    if (m_rtc->write(0xDF, buffer2, 1) != 0) {
-        ERR("Failed to write register address on rtv!\n");
-        m_rtc->stop();
+
+//    _i2c->start();
+    if (_i2c->write(control_byte, buffer2, 1) != 0) {
+        ERR("Failed to write register address on RTC or EEPROM!\n");
+        _i2c->stop();
         return false;
     }
-    if (m_rtc->read(0xDF, buffer, len) != 0) {
+    if (_i2c->read(control_byte, buffer, len) != 0) {
         ERR("Failed to read register !\n");
         return false;
     }
-    m_rtc->stop();
-    
-    INFO("Successfully read %d registers from RTC\n", len);
+    _i2c->stop();
+
+    INFO("Successfully read %d bytes from RTC or EEPROM\n", len);
     return true;
 }
 
-bool Rtc_Mcp97410::write(int address, char *buffer, int len)
+bool Rtc_Mcp97410::readRTC(int address, char *buffer, int len)
+{
+    return read(ADDR_RTCC, address,buffer, len);
+}
+
+bool Rtc_Mcp97410::readEEPROM(int address, char *buffer, int len)
+{
+    return read(ADDR_EEPROM, address,buffer, len);
+}
+
+bool Rtc_Mcp97410::write(int control_byte, int address, char *buffer, int len)
 {
     char buffer2[10];
     buffer2[0] = address&0xFF;
     for (int i = 0 ; i < len ; i++)
         buffer2[i+1] = buffer[i];
 
-//    m_rtc->start();        
-    if (m_rtc->write(0xDF, buffer2, len+1) != 0) {
-        ERR("Failed to write data to rtc\n");
-        m_rtc->stop();
+//    _i2c->start();
+    if (_i2c->write(control_byte, buffer2, len+1) != 0) {
+        ERR("Failed to write data to rtc or EEPROM\n");
+        _i2c->stop();
         return false;
     }
-    m_rtc->stop();
+    _i2c->stop();
+    INFO("Successfully written %d bytes to RTC or EEPROM\n", len);
     return true;
 }
 
 
+bool Rtc_Mcp97410::writeRTC(int address, char *buffer, int len)
+{
+    return write(ADDR_RTCC, address,buffer, len);
+}
 
+bool Rtc_Mcp97410::writeEEPROM(int address, char* buffer, int len)
+{
+    if (len <=8) {
+        return write(ADDR_EEPROM, address,buffer, len);
+    } else {
+        ERR("Can write maximum 8 Bytes to EEPROM in one call\n");
+        return false;
+    }
+}
+
+bool Rtc_Mcp97410::disableEEPROMWrite()
+{
+    // protect all EEPROM from write operations
+    // set STATUS_REGISTER 0xFF bits 2 and 3
+    char reg = 0x0C;
+    return write(ADDR_EEPROM, ADDR_EEPROM_SR,&reg, 1);
+}
+
+
+bool Rtc_Mcp97410::enableEEPROMWrite()
+{
+    // enable  all EEPROM write operations
+    // unset STATUS_REGISTER 0xFF bits 2 and 3
+    char reg = 0x00;
+    return write(ADDR_EEPROM, ADDR_EEPROM_SR,&reg, 1);
+}
+
+bool Rtc_Mcp97410::readEUI48(uint8_t* eui48)
+{
+    //EUI48 start at EEPROM-address 0xF2
+    return(readEEPROM(0xF2,(char *) eui48,6));
+}
+
+
+bool Rtc_Mcp97410::writeEUI48(uint8_t* eui48)
+{
+    //EUI48 start at EEPROM-address 0xF2
+    return(writeEEPROM(0xF2,(char *) eui48,6));
+}
+
+bool Rtc_Mcp97410::unlockEUI()
+{
+    // unlock the special EEPROM area
+    // write 0x55 and then 0xAA to the EEUNLOCK-register
+    char reg =0x00;
+    bool result = true;
+    
+    reg = 0x55;
+    result &= writeRTC(ADDR_ULID,&reg,1);
+    reg = 0xAA;
+    result &= writeRTC(ADDR_ULID,&reg,1);
+    if (result) {
+        INFO("Successfully UNLOCKED the EUI-Area in EEPROM\n");
+        return true;
+    } else {
+        ERR("Error in UNLOCKING the EUI-Area in EEPROM\n");
+        return false;
+    }
+}
 
 RtcCls::RtcCls(I2C* i2c, PinName sqw, bool bUseSqw)
     : Rtc_Mcp97410(i2c), m_sqw(sqw), m_bUseSqw(bUseSqw), m_bAlarmEnabled(false), m_alarmfunc(NULL)
@@ -216,7 +292,7 @@
     struct tm now = {t.sec, t.min, t.hour, t.date, t.mon-1, t.year-1900};
     m_time = mktime(&now);
     set_time(m_time);
-    
+
     //  Only register the callback and start the SQW if requested to do so. Otherwise the system
     //  will use the MBED built-in RTC.
     if (m_bUseSqw) {
@@ -248,8 +324,7 @@
         struct tm now = {t.sec, t.min, t.hour, t.date, t.mon-1, t.year-1900};
         m_time = mktime(&now);
         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);
-    }
-    else {
+    } else {
         INFO("getting time Ticks=%08lx", m_time);
     }
     return m_time;