Library for Real Time Clock module MCP97410 based on Library for DS1307
Fork of RTC-DS1307 by
Diff: Rtc_Mcp97410.cpp
- 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,®, 1)) { - ERR("Failed to read register value !\n"); + + if (!readRTC(ADDR_CTRL,®, 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, ®, 1)) { + INFO("[Reg:0x07] = %02x\n", reg); + + if (!writeRTC(ADDR_CTRL, ®, 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,®, 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,®, 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,®,1); + reg = 0xAA; + result &= writeRTC(ADDR_ULID,®,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;