Library for Real Time Clock module MCP97410 based on Library for DS1307
Fork of RTC-DS1307 by
Rtc_Mcp97410.cpp
- Committer:
- charly
- Date:
- 2015-03-08
- Revision:
- 13:10e564536e23
- Parent:
- 12:88f82e47b6a1
File content as of revision 13:10e564536e23:
#include "mbed.h" #include "Rtc_Mcp97410.h" #ifndef DEBUG #define DEBUG #endif #include "debug.h" const char *Rtc_Mcp97410::m_weekDays[] = { "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" }; Rtc_Mcp97410::Rtc_Mcp97410(I2C* i2c) { _i2c = i2c; if (_i2c == NULL) error("Rtc_Mcp97410: no I2C specified"); // Set the frequency to standard 100kHz // MCP97410 can handle full 400kHz-speed! //_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 (!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[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[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[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 (!writeRTC(ADDR_SEC, buffer, 7) ) { ERR("Failed to write the data to RTC!\n"); return false; } return true; } bool Rtc_Mcp97410::getTime(Time_rtc& time) { char buffer[7]; bool thm = false; INFO("Getting time from RTC\n"); if (!readRTC(ADDR_SEC, buffer, 7) ) { // Failed to read ERR("Failed to read from RTC\n"); return false; } 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[ADDR_HOUR] & 0x1F ); if ((buffer[ADDR_HOUR] & PM) == PM) time.hour += 12; } else { time.hour = Rtc_Mcp97410::bcdToDecimal( buffer[ADDR_HOUR] & 0x3F ); } 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; } bool Rtc_Mcp97410::startClock() { char strtStop; INFO ("Reading clock start/stop register value\n"); if (!readRTC(ADDR_SEC, &strtStop, 1)) { ERR("Failed to read clock start stop register !\n"); return false; } //set bit strtStop |= START_32KHZ; INFO("Writing back start/stop register value\n"); 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; } bool Rtc_Mcp97410::stopClock() { char strtStop; INFO ("Reading clock start/stop register value\n"); if (!readRTC(ADDR_SEC, &strtStop, 1)) { ERR("Failed to read clock start stop register !\n"); return false; } //clear bit strtStop &= ~START_32KHZ; INFO("Writing back start/stop register value\n"); 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; } bool Rtc_Mcp97410::setSquareWaveOutput(bool ena, SqwRateSelect_t rs) { char reg; INFO("Reading register value first\n"); if (!readRTC(ADDR_CTRL,®, 1)) { ERR("Failed to read RTC register value !\n"); return false; } INFO("[Reg:0x07] = %02x\n", reg); // preserve the OUT control bit while writing the frequency and enable bits reg = (reg & OUT_PIN) | (ena ? 0x10 : 0) | ((char)rs & 0x03); INFO("Writing back register value\n"); 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 control_byte, int address, char *buffer, int len) { char buffer2[2] = {(char)address, 0}; // _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 (_i2c->read(control_byte, buffer, len) != 0) { ERR("Failed to read register !\n"); return false; } _i2c->stop(); INFO("Successfully read %d bytes from RTC or EEPROM\n", len); return true; } 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]; // _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; } _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; } } uint8_t Rtc_Mcp97410::readTrim() { uint8_t trim; if (readRTC(ADDR_CAL, (char *) &trim, 1)) { INFO("OSCTRIM: %02X \n", trim); return trim; } else { return 0; } } bool Rtc_Mcp97410::incTrim() { uint8_t trim; uint8_t trim_val; uint8_t trim_sign; readRTC(ADDR_CAL, (char *) &trim, 1); trim_val = 0x7F&trim; trim_sign= trim >> 7; if (trim_sign == 1) { // positive: inc if (trim_val < 0x7F) { trim_val = trim_val++; } } else { // negative: dec if (trim_val != 0) { trim_val = trim_val--; } else { // change sign trim_sign = 1; } } trim = trim_sign <<7 | trim_val; INFO("incTrim: New TRIM: %02X\n", trim); return writeRTC(ADDR_CAL, (char *) &trim, 1); } bool Rtc_Mcp97410::decTrim() { uint8_t trim; uint8_t trim_val; uint8_t trim_sign; readRTC(ADDR_CAL, (char *) &trim, 1); trim_val = 0x7F&trim; trim_sign= trim >> 7; if (trim_sign == 0) { // negative: inc if (trim_val < 0x7F) { trim_val = trim_val++; } } else { // positive: dec if (trim_val != 0) { trim_val = trim_val--; } else { // change sign trim_sign = 0; } } trim = trim_sign <<7 | trim_val; INFO("decTrim: New TRIM: %02X\n", trim); return writeRTC(ADDR_CAL, (char *) &trim, 1); } 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::readEUI64(uint8_t* eui64) { //EUI64 start at EEPROM-address 0xF2 return(readEEPROM(0xF0,(char *) eui64,8)); } bool Rtc_Mcp97410::writeEUI64(uint8_t* eui64) { //EUI64 start at EEPROM-address 0xF2 return(writeEEPROM(0xF0,(char *) eui64,8)); } 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) { Time_rtc t; // query time from device getTime(t); // sync the time with MBED RTC 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) { // start the wave setSquareWaveOutput(true, RS1Hz); // register callback from now on the time will be maintained by the square wave input m_sqw.rise(this, &RtcCls::_callback); } } void RtcCls::_callback(void) { // INFO("Tick!"); // Simply increase the number of seconds m_time++; // if (m_bAlarmEnabled && (m_time == m_alarmTime)) { // if (m_alarmfunc != NULL) // m_alarmfunc(); // m_bAlarmEnabled = false; // } } time_t RtcCls::getTime() { // when not using the HW support, we have to query the RTC chip. Other wise we can just return out stored value if (!m_bUseSqw) { Time_rtc t; getTime(t); 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 { INFO("getting time Ticks=%08lx", m_time); } return m_time; } void RtcCls::setTime(time_t t) { Time_rtc tim; struct tm *now; now = localtime(&t); tim.sec = now->tm_sec; tim.min = now->tm_min; tim.hour = now->tm_hour; tim.date = now->tm_mday; tim.mon = now->tm_mon+1; tim.year = now->tm_year + 1900; tim.wday = now->tm_wday +1; setTime( tim, true, true); set_time(t); }