A feature complete driver for the ISL1208 real time clock from Intersil.
Dependents: ISL1208_HelloWorld
ISL1208.cpp
00001 /* ISL1208 Driver Library 00002 * Copyright (c) 2013 Neil Thiessen 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "ISL1208.h" 00018 00019 const int ISL1208::m_ADDR = (0x6F << 1); 00020 00021 ISL1208::ISL1208(PinName sda, PinName scl, int hz) : m_I2C(sda, scl) 00022 { 00023 //Set the I2C bus frequency 00024 m_I2C.frequency(hz); 00025 } 00026 00027 bool ISL1208::open() 00028 { 00029 //Probe for the ISL1208 using a Zero Length Transfer 00030 if (!m_I2C.write(m_ADDR, NULL, 0)) { 00031 //Read the current status register 00032 char sr = read8(REG_CTL_SR); 00033 00034 //Disable auto reset for BAT and ALM bits 00035 sr &= ~(1 << 7); 00036 00037 //Write the new status register 00038 write8(REG_CTL_SR, sr); 00039 00040 //Return success 00041 return true; 00042 } else { 00043 //Return failure 00044 return false; 00045 } 00046 } 00047 00048 time_t ISL1208::time() 00049 { 00050 //Setup a tm structure based on the RTC 00051 struct tm timeinfo; 00052 timeinfo.tm_sec = bcd2bin(read8(REG_RTC_SC)); 00053 timeinfo.tm_min = bcd2bin(read8(REG_RTC_MN)); 00054 00055 //Make sure we get the proper hour regardless of the mode 00056 char hours = read8(REG_RTC_HR); 00057 if (hours & (1 << 7)) { 00058 //RTC is in 24-hour mode 00059 timeinfo.tm_hour = bcd2bin(hours & 0x3F); 00060 } else { 00061 //RTC is in 12-hour mode 00062 timeinfo.tm_hour = bcd2bin(hours & 0x1F); 00063 00064 //Check for the PM flag 00065 if (hours & (1 << 5)) 00066 timeinfo.tm_hour += 12; 00067 } 00068 00069 //Continue reading the registers 00070 timeinfo.tm_mday = bcd2bin(read8(REG_RTC_DT)); 00071 timeinfo.tm_mon = bcd2bin(read8(REG_RTC_MO)) - 1; 00072 timeinfo.tm_year = bcd2bin(read8(REG_RTC_YR)) + 100; 00073 timeinfo.tm_wday = bcd2bin(read8(REG_RTC_DW)); 00074 00075 //Return as a timestamp 00076 return mktime(&timeinfo); 00077 } 00078 00079 void ISL1208::time(time_t t) 00080 { 00081 //Convert the time to a tm 00082 struct tm *timeinfo = localtime(&t); 00083 00084 /* The clock has an 8 bit wide bcd-coded register (they never learn) 00085 * for the year. tm_year is an offset from 1900 and we are interested 00086 * in the 2000-2099 range, so any value less than 100 is invalid. 00087 */ 00088 if (timeinfo->tm_year < 100) 00089 return; 00090 00091 //Read the old SR register value 00092 char sr = read8(REG_CTL_SR); 00093 00094 //Enable RTC writing 00095 write8(REG_CTL_SR, sr | (1 << 4)); 00096 00097 //Write the current time 00098 write8(REG_RTC_SC, bin2bcd(timeinfo->tm_sec)); 00099 write8(REG_RTC_MN, bin2bcd(timeinfo->tm_min)); 00100 write8(REG_RTC_HR, bin2bcd(timeinfo->tm_hour) | (1 << 7)); //24-hour mode 00101 write8(REG_RTC_DT, bin2bcd(timeinfo->tm_mday)); 00102 write8(REG_RTC_MO, bin2bcd(timeinfo->tm_mon + 1)); 00103 write8(REG_RTC_YR, bin2bcd(timeinfo->tm_year - 100)); 00104 write8(REG_RTC_DW, bin2bcd(timeinfo->tm_wday & 7)); 00105 00106 //Disable RTC writing 00107 write8(REG_CTL_SR, sr); 00108 } 00109 00110 bool ISL1208::powerFailed() 00111 { 00112 //Read the 8-bit register value 00113 char value = read8(REG_CTL_SR); 00114 00115 //Return the status of the RTCF bit 00116 if (value & (1 << 0)) 00117 return true; 00118 else 00119 return false; 00120 } 00121 00122 bool ISL1208::batteryFlag() 00123 { 00124 //Read the 8-bit register value 00125 char value = read8(REG_CTL_SR); 00126 00127 //Return the status of the BAT bit 00128 if (value & (1 << 1)) 00129 return true; 00130 else 00131 return false; 00132 } 00133 00134 void ISL1208::clearBatteryFlag() 00135 { 00136 //Read the current 8-bit register value 00137 char value = read8(REG_CTL_SR); 00138 00139 //Clear the BAT bit 00140 value &= ~(1 << 1); 00141 00142 //Write the value back out 00143 write8(REG_CTL_SR, value); 00144 } 00145 00146 bool ISL1208::alarmFlag() 00147 { 00148 //Read the 8-bit register value 00149 char value = read8(REG_CTL_SR); 00150 00151 //Return the status of the ALM bit 00152 if (value & (1 << 2)) 00153 return true; 00154 else 00155 return false; 00156 } 00157 00158 void ISL1208::clearAlarmFlag() 00159 { 00160 //Read the current 8-bit register value 00161 char value = read8(REG_CTL_SR); 00162 00163 //Clear the ALM bit 00164 value &= ~(1 << 2); 00165 00166 //Write the value back out 00167 write8(REG_CTL_SR, value); 00168 } 00169 00170 ISL1208::OscillatorMode ISL1208::oscillatorMode() 00171 { 00172 //Read the 8-bit register value 00173 char value = read8(REG_CTL_SR); 00174 00175 //Return the status of the XTOSCB bit 00176 if (value & (1 << 6)) 00177 return OSCILLATOR_EXTERNAL; 00178 else 00179 return OSCILLATOR_CRYSTAL; 00180 } 00181 00182 void ISL1208::oscillatorMode(OscillatorMode mode) 00183 { 00184 //Read the current 8-bit register value 00185 char value = read8(REG_CTL_SR); 00186 00187 //Set or clear the XTOSCB bit 00188 if (mode == OSCILLATOR_EXTERNAL) 00189 value |= (1 << 6); 00190 else 00191 value &= ~(1 << 6); 00192 00193 //Write the value back out 00194 write8(REG_CTL_SR, value); 00195 } 00196 00197 ISL1208::OutputFrequency ISL1208::foutFrequency() 00198 { 00199 //Read the 8-bit register value 00200 char value = read8(REG_CTL_INT); 00201 00202 //Return the lower nibble 00203 return (OutputFrequency)(value & 0x0F); 00204 } 00205 00206 void ISL1208::foutFrequency(OutputFrequency freq) 00207 { 00208 //Read the current 8-bit register value 00209 char value = read8(REG_CTL_INT); 00210 00211 //Clear the old frequency bits 00212 value &= 0xF0; 00213 00214 //Set the new frequency bits 00215 value |= freq; 00216 00217 //Write the value back out 00218 write8(REG_CTL_INT, value); 00219 } 00220 00221 bool ISL1208::outputOnBattery() 00222 { 00223 //Read the 8-bit register value 00224 char value = read8(REG_CTL_INT); 00225 00226 //Return the status of the FOBATB bit 00227 if (value & (1 << 4)) 00228 return false; 00229 else 00230 return true; 00231 } 00232 00233 void ISL1208::outputOnBattery(bool output) 00234 { 00235 //Read the current 8-bit register value 00236 char value = read8(REG_CTL_INT); 00237 00238 //Set or clear the FOBATB bit 00239 if (output) 00240 value &= ~(1 << 4); 00241 else 00242 value |= (1 << 4); 00243 00244 //Write the value back out 00245 write8(REG_CTL_INT, value); 00246 } 00247 00248 ISL1208::PowerMode ISL1208::powerMode() 00249 { 00250 //Read the 8-bit register value 00251 char value = read8(REG_CTL_INT); 00252 00253 //Return the status of the LPMODE bit 00254 if (value & (1 << 5)) 00255 return POWER_LPMODE; 00256 else 00257 return POWER_NORMAL; 00258 } 00259 00260 void ISL1208::powerMode(PowerMode mode) 00261 { 00262 //Read the current 8-bit register value 00263 char value = read8(REG_CTL_INT); 00264 00265 //Set or clear the LPMODE bit 00266 if (mode == POWER_LPMODE) 00267 value |= (1 << 5); 00268 else 00269 value &= ~(1 << 5); 00270 00271 //Write the value back out 00272 write8(REG_CTL_INT, value); 00273 } 00274 00275 ISL1208::AlarmMode ISL1208::alarmMode() 00276 { 00277 //Read the 8-bit register value 00278 char value = read8(REG_CTL_INT); 00279 00280 //Return the status of the ALME and IM bits 00281 if (value & (1 << 6)) { 00282 if (value & (1 << 7)) 00283 return ALARM_INTERRUPT; 00284 else 00285 return ALARM_SINGLE; 00286 } else 00287 return ALARM_DISABLED; 00288 } 00289 00290 void ISL1208::alarmMode(AlarmMode mode) 00291 { 00292 //Read the current 8-bit register value 00293 char value = read8(REG_CTL_INT); 00294 00295 //Set or clear the ALME and IM bit 00296 if (mode != ALARM_DISABLED) { 00297 value |= (1 << 6); 00298 if (mode == ALARM_INTERRUPT) 00299 value |= (1 << 7); 00300 else 00301 value &= ~(1 << 7); 00302 } else 00303 value &= ~(1 << 6); 00304 00305 //Write the value back out 00306 write8(REG_CTL_INT, value); 00307 } 00308 00309 float ISL1208::analogTrim() 00310 { 00311 //Read the 8-bit register value 00312 char value = read8(REG_CTL_ATR); 00313 00314 //Mask off the top 2 bits 00315 value &= 0x3F; 00316 00317 //Invert bit 5 00318 value ^= 1 << 5; 00319 00320 //Add an offset of 4.5pF (unit[atr] = 0.25pF) 00321 value += 2 * 9; 00322 00323 //Return the analog trim in pF 00324 return value * 0.25; 00325 } 00326 00327 void ISL1208::analogTrim(float trim) 00328 { 00329 //Range limit trim 00330 if (trim < 4.5) 00331 trim = 4.5; 00332 else if (trim > 20.25) 00333 trim = 20.25; 00334 00335 //Convert the analog trim value to a 6-bit integer 00336 char value = (char)(trim / 0.25); 00337 00338 //Remove the offset of 4.5pF (unit[atr] = 0.25pF) 00339 value -= 2 * 9; 00340 00341 //Invert bit 5 00342 value ^= 1 << 5; 00343 00344 //Read the current 8-bit register value 00345 char reg = read8(REG_CTL_ATR); 00346 00347 //Clear the old ATR bits 00348 reg &= 0xC0; 00349 00350 //Add the new ATR bits 00351 reg |= value; 00352 00353 //Write the value back out 00354 write8(REG_CTL_ATR, reg); 00355 } 00356 00357 ISL1208::BatteryModeATR ISL1208::batteryModeATR() 00358 { 00359 //Read the 8-bit register value 00360 char value = read8(REG_CTL_ATR); 00361 00362 //Shift out the ATR bits 00363 value >>= 6; 00364 00365 //Return the value as a BatteryModeATR enum 00366 return (BatteryModeATR)value; 00367 } 00368 00369 void ISL1208::batteryModeATR(BatteryModeATR atr) 00370 { 00371 //Read the current 8-bit register value 00372 char value = read8(REG_CTL_ATR); 00373 00374 //Clear the old battery mode ATR bits 00375 value &= 0x3F; 00376 00377 //Add the new battery mode ATR bits 00378 value |= (atr << 6); 00379 00380 //Write the value back out 00381 write8(REG_CTL_ATR, value); 00382 } 00383 00384 ISL1208::DigitalTrim ISL1208::digitalTrim() 00385 { 00386 //Read the 8-bit register value 00387 char value = read8(REG_CTL_DTR); 00388 00389 //Mask off the reserved bit 00390 value &= ~(1 << 7); 00391 00392 //Return the value as a DigitalTrim enum 00393 return (DigitalTrim)value; 00394 } 00395 00396 void ISL1208::digitalTrim(DigitalTrim dtr) 00397 { 00398 //Read the current 8-bit register value (to preserve the reserved bit) 00399 char value = read8(REG_CTL_DTR); 00400 00401 //Clear the old DTR bits 00402 value &= 0xF8; 00403 00404 //Add the new DTR bits 00405 value |= dtr; 00406 00407 //Write the value back out 00408 write8(REG_CTL_DTR, value); 00409 } 00410 00411 time_t ISL1208::alarmTime() 00412 { 00413 //Setup a tm structure based on the RTC 00414 struct tm timeinfo; 00415 00416 //MSB of each alarm register is an enable bit 00417 timeinfo.tm_sec = bcd2bin(read8(REG_ALM_SCA) & 0x7F); 00418 timeinfo.tm_min = bcd2bin(read8(REG_ALM_MNA) & 0x7F); 00419 timeinfo.tm_hour = bcd2bin(read8(REG_ALM_HRA) & 0x3F); 00420 timeinfo.tm_mday = bcd2bin(read8(REG_ALM_DTA) & 0x3F); 00421 timeinfo.tm_mon = bcd2bin(read8(REG_ALM_MOA) & 0x1F) - 1; 00422 timeinfo.tm_wday = bcd2bin(read8(REG_ALM_DWA) & 0x03); 00423 00424 //The alarm doesn't store the year, so get it from the RTC section 00425 timeinfo.tm_year = bcd2bin(read8(REG_RTC_YR)) + 100; 00426 00427 //Return as a timestamp 00428 return mktime(&timeinfo); 00429 } 00430 00431 void ISL1208::alarmTime(time_t t, bool sc, bool mn, bool hr, bool dt, bool mo, bool dw) 00432 { 00433 //Convert the time to a tm 00434 struct tm *timeinfo = localtime(&t); 00435 00436 //Write the new alarm time components (if enabled) 00437 if (sc) 00438 write8(REG_ALM_SCA, bin2bcd(timeinfo->tm_sec) | 0x80); 00439 else 00440 write8(REG_ALM_SCA, 0x0); 00441 if (mn) 00442 write8(REG_ALM_MNA, bin2bcd(timeinfo->tm_min) | 0x80); 00443 else 00444 write8(REG_ALM_MNA, 0x0); 00445 if (hr) 00446 write8(REG_ALM_HRA, bin2bcd(timeinfo->tm_hour) | 0x80); 00447 else 00448 write8(REG_ALM_HRA, 0x0); 00449 if (hr) 00450 write8(REG_ALM_DTA, bin2bcd(timeinfo->tm_mday) | 0x80); 00451 else 00452 write8(REG_ALM_DTA, 0x0); 00453 if (mo) 00454 write8(REG_ALM_MOA, bin2bcd(timeinfo->tm_mon + 1) | 0x80); 00455 else 00456 write8(REG_ALM_MOA, 0x0); 00457 if (dw) 00458 write8(REG_ALM_DWA, bin2bcd(timeinfo->tm_wday & 7) | 0x80); 00459 else 00460 write8(REG_ALM_DWA, 0x0); 00461 } 00462 00463 unsigned short ISL1208::sram() 00464 { 00465 //Return the complete contents of the SRAM 00466 return read16(REG_USR_USR1); 00467 } 00468 00469 void ISL1208::sram(unsigned short data) 00470 { 00471 //Write the complete contents of the SRAM 00472 write16(REG_USR_USR1, data); 00473 } 00474 00475 char ISL1208::read8(char reg) 00476 { 00477 //Select the register 00478 m_I2C.write(m_ADDR, ®, 1, true); 00479 00480 //Read the 8-bit register 00481 m_I2C.read(m_ADDR, ®, 1); 00482 00483 //Return the byte 00484 return reg; 00485 } 00486 00487 void ISL1208::write8(char reg, char data) 00488 { 00489 //Create a temporary buffer 00490 char buff[2]; 00491 00492 //Load the register address and 8-bit data 00493 buff[0] = reg; 00494 buff[1] = data; 00495 00496 //Write the data 00497 m_I2C.write(m_ADDR, buff, 2); 00498 } 00499 00500 unsigned short ISL1208::read16(char reg) 00501 { 00502 //Create a temporary buffer 00503 char buff[2]; 00504 00505 //Select the register 00506 m_I2C.write(m_ADDR, ®, 1, true); 00507 00508 //Read the 16-bit register 00509 m_I2C.read(m_ADDR, buff, 2); 00510 00511 //Return the combined 16-bit value 00512 return (buff[0] << 8) | buff[1]; 00513 } 00514 00515 void ISL1208::write16(char reg, unsigned short data) 00516 { 00517 //Create a temporary buffer 00518 char buff[3]; 00519 00520 //Load the register address and 16-bit data 00521 buff[0] = reg; 00522 buff[1] = data >> 8; 00523 buff[2] = data; 00524 00525 //Write the data 00526 m_I2C.write(m_ADDR, buff, 3); 00527 } 00528 00529 unsigned int ISL1208::bcd2bin(unsigned char val) 00530 { 00531 return (val & 0x0F) + (val >> 4) * 10; 00532 } 00533 00534 char ISL1208::bin2bcd(unsigned int val) 00535 { 00536 return ((val / 10) << 4) + val % 10; 00537 }
Generated on Tue Jul 12 2022 23:47:46 by 1.7.2