M41T62 is a serial real-time clock (RTC) made by STMicroelectronics.
Dependents: LPC1114_data_logger Check_external_RTC LPC1114_barometer_with_data_logging
m41t62_rtc.cpp
00001 /* 00002 * mbed library program 00003 * Control M41T62 RTC Module 00004 * STMicroelectronics 00005 * 00006 * Copyright (c) 2014,'15,'17,'20 Kenji Arai / JH1PJL 00007 * http://www7b.biglobe.ne.jp/~kenjia/ 00008 * https://os.mbed.com/users/kenjiArai/ 00009 * Created: June 21st, 2014 00010 * Revised: August 7th, 2020 00011 */ 00012 00013 #include "mbed.h" 00014 #include "m41t62_rtc.h" 00015 00016 #define RTC_Wk_Sunday ((uint8_t)0x00) 00017 00018 M41T62::M41T62 (PinName p_sda, PinName p_scl) 00019 : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) 00020 { 00021 M41T62_addr = M41T62ADDR; 00022 _i2c.frequency(400000); 00023 } 00024 00025 M41T62::M41T62 (I2C& p_i2c) 00026 : _i2c(p_i2c) 00027 { 00028 M41T62_addr = M41T62ADDR; 00029 _i2c.frequency(400000); 00030 } 00031 00032 /////////////// Read RTC data ////////////////////////////////////////////////// 00033 void M41T62::get_time_rtc (tm *t) 00034 { 00035 read_rtc_std(t); 00036 } 00037 00038 void M41T62::read_rtc_std (tm *t) 00039 { 00040 rtc_time time; 00041 00042 read_rtc_direct(&time); 00043 t->tm_sec = time.rtc_seconds; 00044 t->tm_min = time.rtc_minutes; 00045 t->tm_hour = time.rtc_hours; 00046 t->tm_mday = time.rtc_date; 00047 if ( time.rtc_weekday == RTC_Wk_Sunday) { 00048 t->tm_wday = 0; // Sun is not 7 but 0 00049 } else { 00050 t->tm_wday = time.rtc_weekday; 00051 } 00052 t->tm_mon = time.rtc_month - 1; 00053 t->tm_year = time.rtc_year_raw + 100; 00054 t->tm_isdst= 0; 00055 } 00056 00057 /////////////// Write data to RTC ////////////////////////////////////////////// 00058 void M41T62::set_time_rtc (tm *t) 00059 { 00060 write_rtc_std(t); 00061 } 00062 00063 void M41T62::write_rtc_std (tm *t) 00064 { 00065 rtc_time time; 00066 00067 time.rtc_seconds = t->tm_sec; 00068 time.rtc_minutes = t->tm_min; 00069 time.rtc_hours = t->tm_hour; 00070 time.rtc_date = t->tm_mday; 00071 if ( t->tm_wday == 0) { 00072 time.rtc_weekday = RTC_Wk_Sunday; 00073 } else { 00074 time.rtc_weekday = t->tm_wday; 00075 } 00076 time.rtc_month = t->tm_mon + 1; 00077 time.rtc_year_raw = t->tm_year - 100; 00078 write_rtc_direct(&time); 00079 } 00080 00081 /////////////// Read/Write RTC another format ////////////////////////////////// 00082 void M41T62::read_rtc_direct (rtc_time *tm) 00083 { 00084 rtc_buf[0] = M41T62_REG_SSEC; 00085 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00086 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 8, false); 00087 tm->rtc_seconds = bcd2bin(rtc_buf[M41T62_REG_SEC] & 0x7f); 00088 tm->rtc_minutes = bcd2bin(rtc_buf[M41T62_REG_MIN] & 0x7f); 00089 tm->rtc_hours = bcd2bin(rtc_buf[M41T62_REG_HOUR] & 0x3f); 00090 tm->rtc_date = bcd2bin(rtc_buf[M41T62_REG_DAY] & 0x3f); 00091 tm->rtc_weekday = rtc_buf[M41T62_REG_WDAY] & 0x07; 00092 tm->rtc_month = bcd2bin(rtc_buf[M41T62_REG_MON] & 0x1f); 00093 tm->rtc_year_raw= bcd2bin(rtc_buf[M41T62_REG_YEAR]); 00094 tm->rtc_year = tm->rtc_year_raw + 100 + 1900; 00095 } 00096 00097 void M41T62::write_rtc_direct (rtc_time *tm) 00098 { 00099 rtc_buf[M41T62_REG_YEAR + 1] = bin2bcd(tm->rtc_year_raw); 00100 rtc_buf[M41T62_REG_MON + 1] = bin2bcd(tm->rtc_month) & 0x1f; 00101 rtc_buf[M41T62_REG_DAY + 1] = bin2bcd(tm->rtc_date) & 0x3f; 00102 rtc_buf[M41T62_REG_WDAY + 1] = (tm->rtc_weekday & 0x07); 00103 rtc_buf[M41T62_REG_HOUR + 1] = bin2bcd(tm->rtc_hours) & 0x3f; 00104 rtc_buf[M41T62_REG_MIN + 1] = bin2bcd(tm->rtc_minutes) & 0x7f; 00105 rtc_buf[M41T62_REG_SEC + 1] = bin2bcd(tm->rtc_seconds) & 0x7f; 00106 rtc_buf[M41T62_REG_SSEC + 1] = 0; 00107 rtc_buf[0] = M41T62_REG_SSEC; 00108 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 9, false); 00109 } 00110 00111 /////////////// Set Alarm / IRQ //////////////////////////////////////////////// 00112 void M41T62::set_alarm_reg (uint16_t time) 00113 { 00114 tm t; 00115 uint8_t m, h; 00116 00117 read_rtc_std(&t); // read current time 00118 m = t.tm_min + (uint8_t)(time % 60); 00119 h = t.tm_hour; 00120 if (m >= 60) { 00121 m -= 60; 00122 h += 1; 00123 } 00124 h += (uint8_t)(time / 60); 00125 if (h >= 24) { 00126 h -= 24; 00127 } 00128 // set OUT = 1 00129 rtc_buf[0] = M41T62_REG_CALIB; 00130 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00131 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false); 00132 rtc_buf[1] = rtc_buf[0] & 0x3f; // keep calbration data 00133 rtc_buf[1] = rtc_buf[0] | 0x80; // set OUT 00134 rtc_buf[0] = M41T62_REG_CALIB; 00135 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false); 00136 // RPT4=1,RPT5=0,RPT3=0,RPT2=0,RPT1=0 & set day,hour,min,sec 00137 rtc_buf[4] = 0; // M41T62_REG_ALARM_SEC ->RPT=1, set 0sec 00138 rtc_buf[3] = bin2bcd(m) & 0x7f; // M41T62_REG_ALARM_MIN ->RPT2=0 00139 rtc_buf[2] = bin2bcd(h) & 0x3f; // M41T62_REG_ALARM_HOUR ->RPT3=0 00140 rtc_buf[1] = 0xc0; // M41T62_REG_ALARM_DAY ->RPT4=1,RPT5=1 00141 rtc_buf[0] = M41T62_REG_ALARM_DAY; 00142 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 5, false); 00143 // set AFE(alarm enable flag) 00144 rtc_buf[0] = M41T62_REG_ALARM_MON; 00145 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00146 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false); 00147 rtc_buf[1] = rtc_buf[0] & 0x40; // keep SQWE bit 00148 rtc_buf[1] |= 0x80; // set AFE 00149 rtc_buf[0] = M41T62_REG_ALARM_MON; 00150 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false); 00151 } 00152 00153 void M41T62::set_next_IRQ (uint16_t time) 00154 { 00155 uint16_t t; 00156 00157 if (time < 2) { 00158 // Alarm does not check seconds digit. 00159 // If 59 to 0 is occured during setting here, 00160 // 1 minute will have a trouble. 00161 t = 2; 00162 } else if (time > 1440) { // set less than 24 hours 00163 t = 1440; 00164 } else { 00165 t = time; 00166 } 00167 set_alarm_reg(t); 00168 } 00169 00170 /////////////// Clear Alarm / IRQ pin interrupt //////////////////////////////// 00171 void M41T62::clear_IRQ () 00172 { 00173 for (uint32_t i = 0; i < 40; i++) { 00174 rtc_buf[0] = M41T62_REG_FLAGS; 00175 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00176 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false); 00177 if ((rtc_buf[0] & 0x40) == 0) { 00178 break; 00179 } 00180 } 00181 // clear AFE(alarm enable flag) 00182 rtc_buf[0] = M41T62_REG_ALARM_MON; 00183 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00184 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false); 00185 rtc_buf[1] = rtc_buf[0] & 0x40; // keep SQWE bit 00186 rtc_buf[0] = M41T62_REG_ALARM_MON; 00187 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false); 00188 // set OUT = 1 00189 rtc_buf[0] = M41T62_REG_CALIB; 00190 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00191 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false); 00192 rtc_buf[1] = rtc_buf[0] & 0x3f; // keep calbration data 00193 rtc_buf[1] = rtc_buf[0] | 0x80; // set OUT 00194 rtc_buf[0] = M41T62_REG_CALIB; 00195 } 00196 00197 /////////////// I2C Freq. ////////////////////////////////////////////////////// 00198 void M41T62::frequency (int hz) 00199 { 00200 _i2c.frequency(hz); 00201 } 00202 00203 /////////////// Square wave output ///////////////////////////////////////////// 00204 void M41T62::set_sq_wave (sq_wave_t sqw_dt) 00205 { 00206 // set SQW frequency 00207 rtc_buf[0] = M41T62_REG_WDAY; 00208 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00209 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false); 00210 rtc_buf[1] = (rtc_buf[0] & 0x07) | (sqw_dt << 4); 00211 rtc_buf[0] = M41T62_REG_WDAY; 00212 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false); 00213 // set or clear SQWE 00214 rtc_buf[0] = M41T62_REG_ALARM_MON; 00215 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true); 00216 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false); 00217 if (sqw_dt == RTC_SQW_NONE) { // Clear SQWE 00218 rtc_buf[1] = rtc_buf[0] & 0xbf; 00219 } else { // Set SQWE 00220 rtc_buf[1] = rtc_buf[0] | 0x40; 00221 } 00222 rtc_buf[0] = M41T62_REG_ALARM_MON; 00223 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false); 00224 } 00225 00226 /////////////// conversion BCD & BIN /////////////////////////////////////////// 00227 uint8_t M41T62::bin2bcd (uint8_t dt) 00228 { 00229 uint8_t bcdhigh = 0; 00230 00231 while (dt >= 10) { 00232 bcdhigh++; 00233 dt -= 10; 00234 } 00235 return ((uint8_t)(bcdhigh << 4) | dt); 00236 } 00237 00238 uint8_t M41T62::bcd2bin (uint8_t dt) 00239 { 00240 uint8_t tmp = 0; 00241 00242 tmp = ((uint8_t)(dt & (uint8_t)0xf0) >> (uint8_t)0x4) * 10; 00243 return (tmp + (dt & (uint8_t)0x0f)); 00244 }
Generated on Wed Jul 13 2022 00:47:59 by 1.7.2