Library for Real Time Clock module MCP97410 based on Library for DS1307
Fork of RTC-DS1307 by
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,®, 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, ®, 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,®, 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,®, 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,®,1); 00354 reg = 0xAA; 00355 result &= writeRTC(ADDR_ULID,®,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 }
Generated on Tue Jul 12 2022 22:54:37 by
