ArduinoLibs
DS1307RTC.cpp
00001 /*
00002  * Copyright (C) 2012 Southern Storm Software, Pty Ltd.
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a
00005  * copy of this software and associated documentation files (the "Software"),
00006  * to deal in the Software without restriction, including without limitation
00007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00008  * and/or sell copies of the Software, and to permit persons to whom the
00009  * Software is furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included
00012  * in all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00015  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00019  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00020  * DEALINGS IN THE SOFTWARE.
00021  */
00022 
00023 #include "DS1307RTC.h"
00024 #include "../I2C/I2CMaster.h"
00025 #if defined(ARDUINO) && ARDUINO >= 100
00026 #include <Arduino.h>
00027 #else
00028 #include <WProgram.h>
00029 #endif
00030 
00054 // I2C address of the RTC chip (7-bit).
00055 #define DS1307_I2C_ADDRESS  0x68
00056 
00057 // Registers.
00058 #define DS1307_SECOND       0x00
00059 #define DS1307_MINUTE       0x01
00060 #define DS1307_HOUR         0x02
00061 #define DS1307_DAY_OF_WEEK  0x03
00062 #define DS1307_DATE         0x04
00063 #define DS1307_MONTH        0x05
00064 #define DS1307_YEAR         0x06
00065 #define DS1307_CONTROL      0x07
00066 #define DS1307_NVRAM        0x08
00067 
00068 // Alarm storage at the end of the RTC's NVRAM.
00069 #define DS1307_ALARM_SIZE   3
00070 #define DS1307_ALARMS       (64 - RTC::ALARM_COUNT * DS1307_ALARM_SIZE - 1)
00071 #define DS1307_ALARM_MAGIC  63
00072 
00083 DS1307RTC::DS1307RTC(I2CMaster &bus, uint8_t oneHzPin)
00084     : _bus(&bus)
00085     , _oneHzPin(oneHzPin)
00086     , prevOneHz(false)
00087     , _isRealTime(true)
00088 {
00089     // Make sure the CH bit in register 0 is off or the clock won't update.
00090     _bus->startWrite(DS1307_I2C_ADDRESS);
00091     _bus->write(DS1307_SECOND);
00092     if (_bus->startRead(DS1307_I2C_ADDRESS, 1)) {
00093         uint8_t value = _bus->read();
00094         if ((value & 0x80) != 0)
00095             writeRegister(DS1307_SECOND, value & 0x7F);
00096     } else {
00097         // Did not get an acknowledgement from the RTC chip.
00098         _isRealTime = false;
00099     }
00100 
00101     // Turn on the 1 Hz square wave signal if required.
00102     if (oneHzPin != 255 && _isRealTime) {
00103         pinMode(oneHzPin, INPUT);
00104         digitalWrite(oneHzPin, HIGH);
00105         writeRegister(DS1307_CONTROL, 0x10);
00106     }
00107 
00108     // Initialize the alarms in the RTC chip's NVRAM.
00109     if (_isRealTime)
00110         initAlarms();
00111 }
00112 
00118 bool DS1307RTC::hasUpdates()
00119 {
00120     // If not using a 1 Hz pin or there is no RTC chip available,
00121     // then assume that there is an update available.
00122     if (_oneHzPin == 255 || !_isRealTime)
00123         return true;
00124 
00125     // The DS1307 updates the internal registers on the falling edge of the
00126     // 1 Hz clock.  The values should be ready to read on the rising edge.
00127     bool value = digitalRead(_oneHzPin);
00128     if (value && !prevOneHz) {
00129         prevOneHz = value;
00130         return true;
00131     } else {
00132         prevOneHz = value;
00133         return false;
00134     }
00135 }
00136 
00137 inline uint8_t fromBCD(uint8_t value)
00138 {
00139     return (value >> 4) * 10 + (value & 0x0F);
00140 }
00141 
00142 inline uint8_t fromHourBCD(uint8_t value)
00143 {
00144     if ((value & 0x40) != 0) {
00145         // 12-hour mode.
00146         uint8_t result = ((value >> 4) & 0x01) * 10 + (value & 0x0F);
00147         if ((value & 0x20) != 0)
00148             return (result == 12) ? 12 : (result + 12);     // PM
00149         else
00150             return (result == 12) ? 0 : result;             // AM
00151     } else {
00152         // 24-hour mode.
00153         return fromBCD(value);
00154     }
00155 }
00156 
00157 void DS1307RTC::readTime(RTCTime *value)
00158 {
00159     if (_isRealTime) {
00160         _bus->startWrite(DS1307_I2C_ADDRESS);
00161         _bus->write(DS1307_SECOND);
00162         if (_bus->startRead(DS1307_I2C_ADDRESS, 3)) {
00163             value->second = fromBCD(_bus->read() & 0x7F);
00164             value->minute = fromBCD(_bus->read());
00165             value->hour = fromHourBCD(_bus->read());
00166         } else {
00167             // RTC chip is not responding.
00168             value->second = 0;
00169             value->minute = 0;
00170             value->hour = 0;
00171         }
00172     } else {
00173         RTC::readTime(value);
00174     }
00175 }
00176 
00177 void DS1307RTC::readDate(RTCDate *value)
00178 {
00179     if (!_isRealTime) {
00180         RTC::readDate(value);
00181         return;
00182     }
00183     _bus->startWrite(DS1307_I2C_ADDRESS);
00184     _bus->write(DS1307_DATE);
00185     if (_bus->startRead(DS1307_I2C_ADDRESS, 3)) {
00186         value->day = fromBCD(_bus->read());
00187         value->month = fromBCD(_bus->read());
00188         value->year = fromBCD(_bus->read()) + 2000;
00189     } else {
00190         // RTC chip is not responding.
00191         value->day = 1;
00192         value->month = 1;
00193         value->year = 2000;
00194     }
00195 }
00196 
00197 inline uint8_t toBCD(uint8_t value)
00198 {
00199     return ((value / 10) << 4) + (value % 10);
00200 }
00201 
00202 void DS1307RTC::writeTime(const RTCTime *value)
00203 {
00204     if (_isRealTime) {
00205         _bus->startWrite(DS1307_I2C_ADDRESS);
00206         _bus->write(DS1307_SECOND);
00207         _bus->write(toBCD(value->second));
00208         _bus->write(toBCD(value->minute));
00209         _bus->write(toBCD(value->hour));    // Changes mode to 24-hour clock.
00210         _bus->endWrite();
00211     } else {
00212         RTC::writeTime(value);
00213     }
00214 }
00215 
00216 void DS1307RTC::writeDate(const RTCDate *value)
00217 {
00218     if (_isRealTime) {
00219         _bus->startWrite(DS1307_I2C_ADDRESS);
00220         _bus->write(DS1307_DATE);
00221         _bus->write(toBCD(value->day));
00222         _bus->write(toBCD(value->month));
00223         _bus->write(toBCD(value->year % 100));
00224         _bus->endWrite();
00225     } else {
00226         RTC::writeDate(value);
00227     }
00228 }
00229 
00230 void DS1307RTC::readAlarm(uint8_t alarmNum, RTCAlarm *value)
00231 {
00232     if (_isRealTime) {
00233         _bus->startWrite(DS1307_I2C_ADDRESS);
00234         _bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
00235         if (_bus->startRead(DS1307_I2C_ADDRESS, 3)) {
00236             value->hour = fromBCD(_bus->read());
00237             value->minute = fromBCD(_bus->read());
00238             value->flags = _bus->read();
00239         } else {
00240             // RTC chip is not responding.
00241             value->hour = 0;
00242             value->minute = 0;
00243             value->flags = 0;
00244         }
00245     } else {
00246         RTC::readAlarm(alarmNum, value);
00247     }
00248 }
00249 
00250 void DS1307RTC::writeAlarm(uint8_t alarmNum, const RTCAlarm *value)
00251 {
00252     if (_isRealTime) {
00253         _bus->startWrite(DS1307_I2C_ADDRESS);
00254         _bus->write(DS1307_ALARMS + alarmNum * DS1307_ALARM_SIZE);
00255         _bus->write(toBCD(value->hour));
00256         _bus->write(toBCD(value->minute));
00257         _bus->write(value->flags);
00258         _bus->endWrite();
00259     } else {
00260         RTC::writeAlarm(alarmNum, value);
00261     }
00262 }
00263 
00264 int DS1307RTC::byteCount() const
00265 {
00266     return DS1307_ALARMS - DS1307_NVRAM;
00267 }
00268 
00269 uint8_t DS1307RTC::readByte(uint8_t offset)
00270 {
00271     if (_isRealTime)
00272         return readRegister(DS1307_NVRAM + offset);
00273     else
00274         return RTC::readByte(offset);
00275 }
00276 
00277 void DS1307RTC::writeByte(uint8_t offset, uint8_t value)
00278 {
00279     if (_isRealTime)
00280         writeRegister(DS1307_NVRAM + offset, value);
00281     else
00282         RTC::writeByte(offset, value);
00283 }
00284 
00285 void DS1307RTC::initAlarms()
00286 {
00287     uint8_t value = readRegister(DS1307_ALARM_MAGIC);
00288     if (value != (0xB0 + ALARM_COUNT)) {
00289         // This is the first time we have used this clock chip,
00290         // so initialize all alarms to their default state.
00291         RTCAlarm alarm;
00292         alarm.hour = 6;         // Default to 6am for alarms.
00293         alarm.minute = 0;
00294         alarm.flags = 0;
00295         for (uint8_t index = 0; index < ALARM_COUNT; ++index)
00296             writeAlarm(index, &alarm);
00297         writeRegister(DS1307_ALARM_MAGIC, 0xB0 + ALARM_COUNT);
00298 
00299         // Also clear the rest of NVRAM so that it is in a known state.
00300         // Otherwise we'll have whatever garbage was present at power-on.
00301         _bus->startWrite(DS1307_I2C_ADDRESS);
00302         _bus->write(DS1307_NVRAM);
00303         for (uint8_t index = DS1307_NVRAM; index < DS1307_ALARMS; ++index)
00304             _bus->write(0);
00305         _bus->endWrite();
00306     }
00307 }
00308 
00309 uint8_t DS1307RTC::readRegister(uint8_t reg)
00310 {
00311     _bus->startWrite(DS1307_I2C_ADDRESS);
00312     _bus->write(reg);
00313     if (!_bus->startRead(DS1307_I2C_ADDRESS, 1))
00314         return 0;   // RTC chip is not responding.
00315     return _bus->read();
00316 }
00317 
00318 bool DS1307RTC::writeRegister(uint8_t reg, uint8_t value)
00319 {
00320     _bus->startWrite(DS1307_I2C_ADDRESS);
00321     _bus->write(reg);
00322     _bus->write(value);
00323     return _bus->endWrite();
00324 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator