Library for Maxim DS3232M super-accurate, I2C based Real Time Clock chip with 234 bytes of user RAM. Library includes user RAM read/write operations along with CRC routines for accessing the user RAM area.
Dependents: ds3232m_HelloWorld
ds3232m.cpp
00001 #include "mbed.h" 00002 #include "ds3232m.h" 00003 00004 #define RTCI2CADDRESS 0xd0 //i2c address of the DS3232M 00005 #define DS3232SECONDS 0x00 //seconds register 00006 #define DS3232DAYOFWEEK 0x03 //day of the week register 00007 #define DS3232ALM1BOTTOM 0x07 //alarm 1 registers (not used) 00008 #define DS3232ALM2BOTTOM 0x0b //alarm 2 registers (not used) 00009 #define DS3232CTLREG 0x0e //control register 00010 #define DS3232STATREG 0x0f //status register 00011 #define DS3232TEMPERATURE 0x11 //temperature registers 00012 #define DS3232TESTREG 0x13 //test register (do not use) 00013 #define DS3232RAMBOTTOM 0x14 //where user RAM starts 00014 #define DS3232RAMCRC16 0xfc //crc16 registers (top 2 bytes of user RAM) 00015 #define DS3232RAMTOP 0xfe //where user RAM ends. Note: bug in F746 only allows for a I2C xfer of 255 max!!!! 00016 00017 //control register 00018 #define DS3232_EOSCN_BIT 0x80 //turn on/off oscillator in batt backup mode, 0 = on 00019 #define DS3232_BBSQW_BIT 0x40 //battery backed 1Hz enable, 1 = enable 00020 #define DS3232_CONV_BIT 0x20 //start temperature conversion, 1 = start 00021 #define DS3232_INTCN_BIT 0x04 //interrupt control, 1 = interrupt mode, 0 = 1Hz mode 00022 00023 //status register 00024 #define DS3232_OSF_BIT 0x80 //oscillator stopped, 1 = stopped 00025 #define DS3232_BB32KHZ_BIT 0x40 //battery backed 32KHz enable, 1 = enable(writable bit) 00026 #define DS3232_EN32KHZ_BIT 0x08 //32KHz enable, 1 = enable(writable bit) 00027 #define DS3232_BUSY_BIT 0x04 //busy doing a temperature A:D conversion, 1 = busy 00028 00029 char RtcCtlReg = 0; //mirror of control register 00030 char RtcStatReg = 0; //mirror of status register 00031 00032 //char RTCbuffer[256]; //buffer may contain up to 256 bytes, depending on command used 00033 00034 //--------------------------------------------------------------------------------------------------------------------------------------// 00035 // constructor with fixed frequency 00036 00037 ds3232m::ds3232m(PinName sda, PinName scl) { 00038 // Create a new I2C object 00039 _i2c_ = new I2C(sda, scl); 00040 // Set the frequency to standard 400kHz 00041 _i2c_->frequency(400000); 00042 } 00043 00044 //--------------------------------------------------------------------------------------------------------------------------------------// 00045 // constructor with I2C frequency selection 00046 00047 ds3232m::ds3232m(PinName sda, PinName scl, int i2cFrequency) { 00048 _i2c_ = new I2C(sda, scl); 00049 _i2c_->frequency(i2cFrequency); 00050 } 00051 00052 //--------------------------------------------------------------------------------------------------------------------------------------// 00053 // deconstructor 00054 00055 ds3232m::~ds3232m() { 00056 } 00057 00058 //--------------------------------------------------------------------------------------------------------------------------------------// 00059 // set time up into the DS3232M 00060 00061 void ds3232m::setTime(Time_rtc& dsSTR) { 00062 dsSTR.RTCbuffer [0] = DS3232SECONDS; 00063 dsSTR.RTCbuffer [1] = DecToBCD(dsSTR.sec ); 00064 dsSTR.RTCbuffer [2] = DecToBCD(dsSTR.min ); 00065 dsSTR.RTCbuffer [3] = DecToBCD(dsSTR.hour ); 00066 dsSTR.RTCbuffer [4] = dsSTR.wday ; 00067 dsSTR.RTCbuffer [5] = DecToBCD(dsSTR.date ); 00068 dsSTR.RTCbuffer [6] = DecToBCD(dsSTR.mon ); 00069 dsSTR.RTCbuffer [7] = DecToBCD(dsSTR.year - 2000); 00070 00071 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 8, false); 00072 } 00073 00074 //--------------------------------------------------------------------------------------------------------------------------------------// 00075 // get time from the DS3232M and stick it into the mbed's RTC 00076 00077 void ds3232m::getTime(Time_rtc& dsSTR) { 00078 dsSTR.RTCbuffer [0] = DS3232SECONDS; 00079 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, true); 00080 _i2c_->read(RTCI2CADDRESS, dsSTR.RTCbuffer , 7, false); 00081 00082 dsSTR.sec = BCDToDec(dsSTR.RTCbuffer [0]); 00083 dsSTR.min = BCDToDec(dsSTR.RTCbuffer [1]); 00084 dsSTR.hour = ds3232m::BCDToDec(dsSTR.RTCbuffer [2]); 00085 dsSTR.wday = dsSTR.RTCbuffer [3]; 00086 dsSTR.date = ds3232m::BCDToDec(dsSTR.RTCbuffer [4]); 00087 dsSTR.mon = ds3232m::BCDToDec(dsSTR.RTCbuffer [5]); 00088 dsSTR.year = ds3232m::BCDToDec(dsSTR.RTCbuffer [6]) + 2000; 00089 } 00090 00091 //--------------------------------------------------------------------------------------------------------------------------------------// 00092 // retrieve the control and status registers 00093 00094 void ds3232m::getControlStatusRegs(Time_rtc& dsSTR) { 00095 dsSTR.RTCbuffer[0] = DS3232CTLREG; 00096 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer, 1, true); 00097 _i2c_->read(RTCI2CADDRESS, dsSTR.RTCbuffer, 2, false); 00098 RtcCtlReg = dsSTR.RTCbuffer[0]; 00099 RtcStatReg = dsSTR.RTCbuffer[1]; 00100 } 00101 00102 //--------------------------------------------------------------------------------------------------------------------------------------// 00103 // enables/disables the main oscillator during battery backup mode. true = enable during battery backup mode 00104 00105 void ds3232m::enableBattClock(Time_rtc& dsSTR, bool batt) { 00106 getControlStatusRegs(dsSTR); 00107 if(batt == true) { 00108 RtcCtlReg &= ~DS3232_EOSCN_BIT; 00109 } else { 00110 RtcCtlReg |= DS3232_EOSCN_BIT; 00111 } 00112 00113 dsSTR.RTCbuffer [0] = DS3232CTLREG; 00114 dsSTR.RTCbuffer [1] = RtcCtlReg; 00115 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 2, false); 00116 } 00117 00118 //--------------------------------------------------------------------------------------------------------------------------------------// 00119 // check to see if DS3232M's temperature conversion cycle is bust or not 00120 // only 1 per second max 00121 00122 bool ds3232m::checkTempBusy(Time_rtc& dsSTR) { 00123 getControlStatusRegs(dsSTR); 00124 if(RtcCtlReg & DS3232_CONV_BIT) return true; //is already busy 00125 if(RtcStatReg & DS3232_BUSY_BIT) return true; //is already busy 00126 return false; 00127 } 00128 00129 //--------------------------------------------------------------------------------------------------------------------------------------// 00130 // start a temperature conversion cycle 00131 // only 1 per second max 00132 00133 bool ds3232m::startTempCycle(Time_rtc& dsSTR) { 00134 getControlStatusRegs(dsSTR); 00135 if((checkTempBusy(dsSTR)) == true) return false; //is already busy 00136 RtcCtlReg |= DS3232_CONV_BIT; 00137 00138 dsSTR.RTCbuffer [0] = DS3232CTLREG; 00139 dsSTR.RTCbuffer [1] = RtcCtlReg; 00140 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 2, false); 00141 return true; 00142 } 00143 00144 //--------------------------------------------------------------------------------------------------------------------------------------// 00145 // get temperature 00146 // if returned value = 255.0, then temperature conversion was still busy 00147 00148 float ds3232m::getTemperature(Time_rtc& dsSTR) { 00149 getControlStatusRegs(dsSTR); 00150 if((checkTempBusy(dsSTR)) == false) return(255.0); //is already busy 00151 00152 dsSTR.RTCbuffer [0] = DS3232TEMPERATURE; 00153 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, true); 00154 _i2c_->read(RTCI2CADDRESS, dsSTR.RTCbuffer , 2, false); 00155 int8_t temp3232a = dsSTR.RTCbuffer [0]; 00156 uint8_t temp3232b = dsSTR.RTCbuffer [1]; 00157 00158 float temp3232 = (float)temp3232a; 00159 //for positive temp 00160 if((temp3232b == 0x40) && (temp3232a >= 0)) temp3232 += 0.25; 00161 if (temp3232b == 0x80) temp3232 += 0.5; 00162 if((temp3232b == 0xc0) && (temp3232a >= 0)) temp3232 += 0.75; 00163 //for negative temp 00164 if((temp3232b == 0x40) && (temp3232a < 0)) temp3232 += 0.75; 00165 if((temp3232b == 0xc0) && (temp3232a < 0)) temp3232 += 0.25; 00166 return (temp3232); 00167 } 00168 00169 //--------------------------------------------------------------------------------------------------------------------------------------// 00170 // get seconds register 00171 00172 uint8_t ds3232m::getSeconds(Time_rtc& dsSTR) { 00173 dsSTR.RTCbuffer [0] = DS3232SECONDS; 00174 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, true); 00175 _i2c_->read(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, false); 00176 int seconds3232 = dsSTR.RTCbuffer [0]; 00177 int xbcd = BCDToDec(seconds3232); 00178 return(xbcd); 00179 } 00180 00181 //--------------------------------------------------------------------------------------------------------------------------------------// 00182 // get day of the week register (1 = Monday... 7 = Sunday) 00183 00184 uint8_t ds3232m::getDayOfWeek(Time_rtc& dsSTR) { 00185 dsSTR.RTCbuffer [0] = DS3232DAYOFWEEK; 00186 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, true); 00187 _i2c_->read(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, false); 00188 int dow3232 = dsSTR.RTCbuffer [0]; 00189 return(BCDToDec(dow3232)); 00190 } 00191 00192 //--------------------------------------------------------------------------------------------------------------------------------------// 00193 // set day of the week register (1 = Monday... 7 = Sunday) 00194 00195 void ds3232m::putDayOfWeek(Time_rtc& dsSTR, uint8_t dow3232) { 00196 dow3232 = dow3232 & 7; 00197 dsSTR.RTCbuffer [0] = DS3232DAYOFWEEK; 00198 dsSTR.RTCbuffer [1] = DecToBCD(dow3232); 00199 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 2, false); 00200 } 00201 00202 //--------------------------------------------------------------------------------------------------------------------------------------// 00203 // clears all user memory inside the DS3232M. Top 2 locations - reserved for CRC, also set to 00 since CRC value is 0x00 0x00 00204 00205 void ds3232m::clearRAM(Time_rtc& dsSTR) { 00206 for(int i = DS3232SECONDS; i <= DS3232RAMTOP; i++) dsSTR.RTCbuffer [i] = 0; 00207 dsSTR.RTCbuffer [0] = DS3232RAMBOTTOM; 00208 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , (DS3232RAMTOP - DS3232RAMBOTTOM + 2), false); 00209 } 00210 00211 //--------------------------------------------------------------------------------------------------------------------------------------// 00212 // retrieves user data from DS3232M RAM 00213 00214 uint8_t ds3232m::getUserRAM(char *buffer, Time_rtc& dsSTR, int offset, int length) { 00215 if((offset + length) > DS3232RAMCRC16) return(DS3232_OVERFLOWERROR); 00216 if(offset < DS3232RAMBOTTOM) return(DS3232_OFFSETERROR); 00217 if(length == 0) return(DS3232_LENZEROERROR); 00218 dsSTR.RTCbuffer [0] = offset; 00219 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, true); 00220 _i2c_->read(RTCI2CADDRESS, buffer, length, false); 00221 if(LoadRTCRam(dsSTR) == false) return(DS3232_CRCERROR); 00222 return(DS3232_NOERROR); 00223 } 00224 00225 //--------------------------------------------------------------------------------------------------------------------------------------// 00226 // puts user data into DS3232M RAM. CRC16 value added to the top 2 RAM location 00227 00228 uint8_t ds3232m::putUserRAM(char *buffer, Time_rtc& dsSTR, int offset, int length) { 00229 if((offset + length) > DS3232RAMCRC16) return(DS3232_OVERFLOWERROR); 00230 if(offset < DS3232RAMBOTTOM) return(DS3232_OFFSETERROR); 00231 if(length == 0) return(DS3232_LENZEROERROR); 00232 for(int i = 0; i < 32; i++) dsSTR.RTCbuffer [i] = NULL; 00233 dsSTR.RTCbuffer [0] = offset; 00234 dsSTR.RTCbuffer [1] = NULL; 00235 strcat(dsSTR.RTCbuffer , buffer); 00236 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , length + 1, false); 00237 addCRC16(dsSTR); 00238 return(DS3232_NOERROR); 00239 } 00240 00241 //--------------------------------------------------------------------------------------------------------------------------------------// 00242 // enable/disable 32KHz output with run on battery mode option 00243 00244 void ds3232m::set32KhzOutput(Time_rtc& dsSTR, bool ena, bool batt) { 00245 getControlStatusRegs(dsSTR); 00246 if(ena == true) { 00247 RtcStatReg |= DS3232_EN32KHZ_BIT; 00248 if(batt == true) { 00249 RtcStatReg |= DS3232_BB32KHZ_BIT; 00250 } else { 00251 RtcStatReg &= ~DS3232_BB32KHZ_BIT; 00252 } 00253 } else { 00254 RtcStatReg &= ~DS3232_EN32KHZ_BIT; 00255 RtcStatReg &= ~DS3232_BB32KHZ_BIT; 00256 } 00257 00258 dsSTR.RTCbuffer [0] = DS3232STATREG; 00259 dsSTR.RTCbuffer [1] = RtcStatReg; 00260 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 2, false); 00261 } 00262 00263 //--------------------------------------------------------------------------------------------------------------------------------------// 00264 // enable/disable 1Hz output with run on battery mode option 00265 00266 void ds3232m::set1hzOutput(Time_rtc& dsSTR, bool ena, bool batt) { 00267 getControlStatusRegs(dsSTR); 00268 if(ena == true) { 00269 RtcCtlReg &= ~DS3232_INTCN_BIT; 00270 if(batt == true) { 00271 RtcCtlReg |= DS3232_BBSQW_BIT; 00272 } else { 00273 RtcCtlReg &= ~DS3232_BBSQW_BIT; 00274 } 00275 } else { 00276 RtcCtlReg |= DS3232_INTCN_BIT; 00277 RtcCtlReg &= ~DS3232_BBSQW_BIT; 00278 } 00279 00280 dsSTR.RTCbuffer [0] = DS3232CTLREG; 00281 dsSTR.RTCbuffer [1] = RtcCtlReg; 00282 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 2, false); 00283 } 00284 00285 //--------------------------------------------------------------------------------------------------------------------------------------// 00286 // CRC table and routine taken from Emilie Laverge's CRC16 library 00287 //--------------------------------------------------------------------------------------------------------------------------------------// 00288 // lookup table for calculating crc16 00289 00290 uint16_t crc16table[256] = { 00291 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, 00292 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, 00293 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072, 00294 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041, 00295 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2, 00296 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1, 00297 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1, 00298 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082, 00299 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192, 00300 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1, 00301 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1, 00302 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2, 00303 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151, 00304 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162, 00305 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132, 00306 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101, 00307 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312, 00308 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321, 00309 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371, 00310 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342, 00311 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1, 00312 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2, 00313 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2, 00314 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381, 00315 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291, 00316 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2, 00317 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2, 00318 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1, 00319 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252, 00320 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261, 00321 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231, 00322 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202 00323 }; 00324 00325 //--------------------------------------------------------------------------------------------------------------------------------------// 00326 // calculate a crc value for the DS3232M user ram area. CRC value calculated from address 0x14 - 0xfd 00327 00328 uint16_t ds3232m::calculateCRC16(char input[], Time_rtc& dsSTR, int offset, int length) { 00329 uint16_t CRC16s = 0; 00330 input+= offset; 00331 for(int i = offset; i < (length + offset); i++) { 00332 uint16_t tableValue = crc16table[((CRC16s >> 8) ^ *(char *)input++) & 0x00ff]; 00333 CRC16s = (CRC16s << 8) ^ tableValue; 00334 } 00335 dsSTR.c_crc = CRC16s; 00336 return CRC16s; 00337 } 00338 00339 //--------------------------------------------------------------------------------------------------------------------------------------// 00340 // This function gets the entire contents of the RTC. Returns flase if a CRC error occured 00341 00342 bool ds3232m::LoadRTCRam(Time_rtc& dsSTR) { 00343 dsSTR.RTCbuffer [0] = DS3232SECONDS; 00344 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer , 1, true); 00345 _i2c_->read(RTCI2CADDRESS, dsSTR.RTCbuffer , DS3232RAMTOP, false); //BUG in F746 only allows for xfer of 255 bytes max!!! 00346 00347 dsSTR.s_crc = (dsSTR.RTCbuffer [DS3232RAMCRC16] << 8) | dsSTR.RTCbuffer [DS3232RAMCRC16 + 1]; 00348 calculateCRC16(dsSTR.RTCbuffer , dsSTR, DS3232RAMBOTTOM, (DS3232RAMCRC16 - DS3232RAMBOTTOM)); 00349 00350 ////reload the time registers 00351 //dsSTR.RTCbuffer[0] = DS3232SECONDS; 00352 //_i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer, 1, true); 00353 //_i2c_->read(RTCI2CADDRESS, dsSTR.RTCbuffer, 7, false); 00354 00355 if(dsSTR.c_crc != dsSTR.s_crc ) return false; 00356 return true; 00357 } 00358 00359 //--------------------------------------------------------------------------------------------------------------------------------------// 00360 // This function calculates and saves CRC data to the end of RTC's RAM. 00361 // CRC calculated address range is 0x14 - 0xfd. CRC data is placed in 0xfe and 0xff 00362 00363 void ds3232m::addCRC16(Time_rtc& dsSTR) { 00364 LoadRTCRam(dsSTR); 00365 dsSTR.c_crc = calculateCRC16(dsSTR.RTCbuffer, dsSTR, DS3232RAMBOTTOM, (DS3232RAMCRC16 - DS3232RAMBOTTOM)); //0x14 is offset from 0 in buffer, 230 is length // 00366 dsSTR.RTCbuffer[0] = DS3232RAMCRC16; 00367 dsSTR.RTCbuffer[1] = dsSTR.c_crc >> 8; 00368 dsSTR.RTCbuffer[2] = dsSTR.c_crc & 0xff; 00369 _i2c_->write(RTCI2CADDRESS, dsSTR.RTCbuffer, 3, false); 00370 } 00371
Generated on Mon Jul 18 2022 17:28:07 by 1.7.2