M41T62 is a serial real-time clock (RTC) made by STMicroelectronics.

Dependents:   LPC1114_data_logger Check_external_RTC LPC1114_barometer_with_data_logging

Committer:
kenjiArai
Date:
Fri Aug 07 06:21:06 2020 +0000
Revision:
6:0bf0f681fb69
Parent:
5:959683e91979
bug fix in set_alarm_reg

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kenjiArai 0:2919f8bd90f3 1 /*
kenjiArai 3:41c351da2fdf 2 * mbed library program
kenjiArai 0:2919f8bd90f3 3 * Control M41T62 RTC Module
kenjiArai 5:959683e91979 4 * STMicroelectronics
kenjiArai 0:2919f8bd90f3 5 *
kenjiArai 5:959683e91979 6 * Copyright (c) 2014,'15,'17,'20 Kenji Arai / JH1PJL
kenjiArai 5:959683e91979 7 * http://www7b.biglobe.ne.jp/~kenjia/
kenjiArai 5:959683e91979 8 * https://os.mbed.com/users/kenjiArai/
kenjiArai 4:0c07690cb24f 9 * Created: June 21st, 2014
kenjiArai 5:959683e91979 10 * Revised: August 7th, 2020
kenjiArai 0:2919f8bd90f3 11 */
kenjiArai 0:2919f8bd90f3 12
kenjiArai 0:2919f8bd90f3 13 #include "mbed.h"
kenjiArai 0:2919f8bd90f3 14 #include "m41t62_rtc.h"
kenjiArai 0:2919f8bd90f3 15
kenjiArai 5:959683e91979 16 #define RTC_Wk_Sunday ((uint8_t)0x00)
kenjiArai 5:959683e91979 17
kenjiArai 4:0c07690cb24f 18 M41T62::M41T62 (PinName p_sda, PinName p_scl)
kenjiArai 5:959683e91979 19 : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
kenjiArai 3:41c351da2fdf 20 {
kenjiArai 1:9d7702a887d3 21 M41T62_addr = M41T62ADDR;
kenjiArai 5:959683e91979 22 _i2c.frequency(400000);
kenjiArai 1:9d7702a887d3 23 }
kenjiArai 1:9d7702a887d3 24
kenjiArai 4:0c07690cb24f 25 M41T62::M41T62 (I2C& p_i2c)
kenjiArai 5:959683e91979 26 : _i2c(p_i2c)
kenjiArai 3:41c351da2fdf 27 {
kenjiArai 0:2919f8bd90f3 28 M41T62_addr = M41T62ADDR;
kenjiArai 5:959683e91979 29 _i2c.frequency(400000);
kenjiArai 5:959683e91979 30 }
kenjiArai 5:959683e91979 31
kenjiArai 5:959683e91979 32 /////////////// Read RTC data //////////////////////////////////////////////////
kenjiArai 5:959683e91979 33 void M41T62::get_time_rtc (tm *t)
kenjiArai 5:959683e91979 34 {
kenjiArai 5:959683e91979 35 read_rtc_std(t);
kenjiArai 0:2919f8bd90f3 36 }
kenjiArai 0:2919f8bd90f3 37
kenjiArai 3:41c351da2fdf 38 void M41T62::read_rtc_std (tm *t)
kenjiArai 3:41c351da2fdf 39 {
kenjiArai 3:41c351da2fdf 40 rtc_time time;
kenjiArai 1:9d7702a887d3 41
kenjiArai 1:9d7702a887d3 42 read_rtc_direct(&time);
kenjiArai 1:9d7702a887d3 43 t->tm_sec = time.rtc_seconds;
kenjiArai 1:9d7702a887d3 44 t->tm_min = time.rtc_minutes;
kenjiArai 1:9d7702a887d3 45 t->tm_hour = time.rtc_hours;
kenjiArai 1:9d7702a887d3 46 t->tm_mday = time.rtc_date;
kenjiArai 3:41c351da2fdf 47 if ( time.rtc_weekday == RTC_Wk_Sunday) {
kenjiArai 1:9d7702a887d3 48 t->tm_wday = 0; // Sun is not 7 but 0
kenjiArai 1:9d7702a887d3 49 } else {
kenjiArai 1:9d7702a887d3 50 t->tm_wday = time.rtc_weekday;
kenjiArai 1:9d7702a887d3 51 }
kenjiArai 1:9d7702a887d3 52 t->tm_mon = time.rtc_month - 1;
kenjiArai 1:9d7702a887d3 53 t->tm_year = time.rtc_year_raw + 100;
kenjiArai 1:9d7702a887d3 54 t->tm_isdst= 0;
kenjiArai 0:2919f8bd90f3 55 }
kenjiArai 0:2919f8bd90f3 56
kenjiArai 5:959683e91979 57 /////////////// Write data to RTC //////////////////////////////////////////////
kenjiArai 5:959683e91979 58 void M41T62::set_time_rtc (tm *t)
kenjiArai 5:959683e91979 59 {
kenjiArai 5:959683e91979 60 write_rtc_std(t);
kenjiArai 5:959683e91979 61 }
kenjiArai 5:959683e91979 62
kenjiArai 3:41c351da2fdf 63 void M41T62::write_rtc_std (tm *t)
kenjiArai 3:41c351da2fdf 64 {
kenjiArai 3:41c351da2fdf 65 rtc_time time;
kenjiArai 3:41c351da2fdf 66
kenjiArai 1:9d7702a887d3 67 time.rtc_seconds = t->tm_sec;
kenjiArai 1:9d7702a887d3 68 time.rtc_minutes = t->tm_min;
kenjiArai 1:9d7702a887d3 69 time.rtc_hours = t->tm_hour;
kenjiArai 1:9d7702a887d3 70 time.rtc_date = t->tm_mday;
kenjiArai 3:41c351da2fdf 71 if ( t->tm_wday == 0) {
kenjiArai 1:9d7702a887d3 72 time.rtc_weekday = RTC_Wk_Sunday;
kenjiArai 1:9d7702a887d3 73 } else {
kenjiArai 1:9d7702a887d3 74 time.rtc_weekday = t->tm_wday;
kenjiArai 1:9d7702a887d3 75 }
kenjiArai 1:9d7702a887d3 76 time.rtc_month = t->tm_mon + 1;
kenjiArai 1:9d7702a887d3 77 time.rtc_year_raw = t->tm_year - 100;
kenjiArai 1:9d7702a887d3 78 write_rtc_direct(&time);
kenjiArai 1:9d7702a887d3 79 }
kenjiArai 1:9d7702a887d3 80
kenjiArai 5:959683e91979 81 /////////////// Read/Write RTC another format //////////////////////////////////
kenjiArai 3:41c351da2fdf 82 void M41T62::read_rtc_direct (rtc_time *tm)
kenjiArai 3:41c351da2fdf 83 {
kenjiArai 5:959683e91979 84 rtc_buf[0] = M41T62_REG_SSEC;
kenjiArai 5:959683e91979 85 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 86 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 8, false);
kenjiArai 0:2919f8bd90f3 87 tm->rtc_seconds = bcd2bin(rtc_buf[M41T62_REG_SEC] & 0x7f);
kenjiArai 0:2919f8bd90f3 88 tm->rtc_minutes = bcd2bin(rtc_buf[M41T62_REG_MIN] & 0x7f);
kenjiArai 0:2919f8bd90f3 89 tm->rtc_hours = bcd2bin(rtc_buf[M41T62_REG_HOUR] & 0x3f);
kenjiArai 0:2919f8bd90f3 90 tm->rtc_date = bcd2bin(rtc_buf[M41T62_REG_DAY] & 0x3f);
kenjiArai 0:2919f8bd90f3 91 tm->rtc_weekday = rtc_buf[M41T62_REG_WDAY] & 0x07;
kenjiArai 0:2919f8bd90f3 92 tm->rtc_month = bcd2bin(rtc_buf[M41T62_REG_MON] & 0x1f);
kenjiArai 1:9d7702a887d3 93 tm->rtc_year_raw= bcd2bin(rtc_buf[M41T62_REG_YEAR]);
kenjiArai 1:9d7702a887d3 94 tm->rtc_year = tm->rtc_year_raw + 100 + 1900;
kenjiArai 0:2919f8bd90f3 95 }
kenjiArai 0:2919f8bd90f3 96
kenjiArai 3:41c351da2fdf 97 void M41T62::write_rtc_direct (rtc_time *tm)
kenjiArai 3:41c351da2fdf 98 {
kenjiArai 5:959683e91979 99 rtc_buf[M41T62_REG_YEAR + 1] = bin2bcd(tm->rtc_year_raw);
kenjiArai 5:959683e91979 100 rtc_buf[M41T62_REG_MON + 1] = bin2bcd(tm->rtc_month) & 0x1f;
kenjiArai 5:959683e91979 101 rtc_buf[M41T62_REG_DAY + 1] = bin2bcd(tm->rtc_date) & 0x3f;
kenjiArai 5:959683e91979 102 rtc_buf[M41T62_REG_WDAY + 1] = (tm->rtc_weekday & 0x07);
kenjiArai 5:959683e91979 103 rtc_buf[M41T62_REG_HOUR + 1] = bin2bcd(tm->rtc_hours) & 0x3f;
kenjiArai 5:959683e91979 104 rtc_buf[M41T62_REG_MIN + 1] = bin2bcd(tm->rtc_minutes) & 0x7f;
kenjiArai 5:959683e91979 105 rtc_buf[M41T62_REG_SEC + 1] = bin2bcd(tm->rtc_seconds) & 0x7f;
kenjiArai 0:2919f8bd90f3 106 rtc_buf[M41T62_REG_SSEC + 1] = 0;
kenjiArai 5:959683e91979 107 rtc_buf[0] = M41T62_REG_SSEC;
kenjiArai 5:959683e91979 108 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 9, false);
kenjiArai 0:2919f8bd90f3 109 }
kenjiArai 0:2919f8bd90f3 110
kenjiArai 5:959683e91979 111 /////////////// Set Alarm / IRQ ////////////////////////////////////////////////
kenjiArai 5:959683e91979 112 void M41T62::set_alarm_reg (uint16_t time)
kenjiArai 5:959683e91979 113 {
kenjiArai 5:959683e91979 114 tm t;
kenjiArai 5:959683e91979 115 uint8_t m, h;
kenjiArai 5:959683e91979 116
kenjiArai 5:959683e91979 117 read_rtc_std(&t); // read current time
kenjiArai 5:959683e91979 118 m = t.tm_min + (uint8_t)(time % 60);
kenjiArai 5:959683e91979 119 h = t.tm_hour;
kenjiArai 5:959683e91979 120 if (m >= 60) {
kenjiArai 5:959683e91979 121 m -= 60;
kenjiArai 5:959683e91979 122 h += 1;
kenjiArai 5:959683e91979 123 }
kenjiArai 5:959683e91979 124 h += (uint8_t)(time / 60);
kenjiArai 5:959683e91979 125 if (h >= 24) {
kenjiArai 5:959683e91979 126 h -= 24;
kenjiArai 5:959683e91979 127 }
kenjiArai 5:959683e91979 128 // set OUT = 1
kenjiArai 5:959683e91979 129 rtc_buf[0] = M41T62_REG_CALIB;
kenjiArai 5:959683e91979 130 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 131 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
kenjiArai 5:959683e91979 132 rtc_buf[1] = rtc_buf[0] & 0x3f; // keep calbration data
kenjiArai 5:959683e91979 133 rtc_buf[1] = rtc_buf[0] | 0x80; // set OUT
kenjiArai 5:959683e91979 134 rtc_buf[0] = M41T62_REG_CALIB;
kenjiArai 5:959683e91979 135 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
kenjiArai 5:959683e91979 136 // RPT4=1,RPT5=0,RPT3=0,RPT2=0,RPT1=0 & set day,hour,min,sec
kenjiArai 5:959683e91979 137 rtc_buf[4] = 0; // M41T62_REG_ALARM_SEC ->RPT=1, set 0sec
kenjiArai 6:0bf0f681fb69 138 rtc_buf[3] = bin2bcd(m) & 0x7f; // M41T62_REG_ALARM_MIN ->RPT2=0
kenjiArai 6:0bf0f681fb69 139 rtc_buf[2] = bin2bcd(h) & 0x3f; // M41T62_REG_ALARM_HOUR ->RPT3=0
kenjiArai 5:959683e91979 140 rtc_buf[1] = 0xc0; // M41T62_REG_ALARM_DAY ->RPT4=1,RPT5=1
kenjiArai 5:959683e91979 141 rtc_buf[0] = M41T62_REG_ALARM_DAY;
kenjiArai 5:959683e91979 142 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 5, false);
kenjiArai 5:959683e91979 143 // set AFE(alarm enable flag)
kenjiArai 5:959683e91979 144 rtc_buf[0] = M41T62_REG_ALARM_MON;
kenjiArai 5:959683e91979 145 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 146 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
kenjiArai 5:959683e91979 147 rtc_buf[1] = rtc_buf[0] & 0x40; // keep SQWE bit
kenjiArai 5:959683e91979 148 rtc_buf[1] |= 0x80; // set AFE
kenjiArai 5:959683e91979 149 rtc_buf[0] = M41T62_REG_ALARM_MON;
kenjiArai 5:959683e91979 150 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
kenjiArai 5:959683e91979 151 }
kenjiArai 5:959683e91979 152
kenjiArai 5:959683e91979 153 void M41T62::set_next_IRQ (uint16_t time)
kenjiArai 5:959683e91979 154 {
kenjiArai 5:959683e91979 155 uint16_t t;
kenjiArai 5:959683e91979 156
kenjiArai 5:959683e91979 157 if (time < 2) {
kenjiArai 5:959683e91979 158 // Alarm does not check seconds digit.
kenjiArai 5:959683e91979 159 // If 59 to 0 is occured during setting here,
kenjiArai 5:959683e91979 160 // 1 minute will have a trouble.
kenjiArai 5:959683e91979 161 t = 2;
kenjiArai 5:959683e91979 162 } else if (time > 1440) { // set less than 24 hours
kenjiArai 5:959683e91979 163 t = 1440;
kenjiArai 5:959683e91979 164 } else {
kenjiArai 5:959683e91979 165 t = time;
kenjiArai 5:959683e91979 166 }
kenjiArai 5:959683e91979 167 set_alarm_reg(t);
kenjiArai 5:959683e91979 168 }
kenjiArai 5:959683e91979 169
kenjiArai 5:959683e91979 170 /////////////// Clear Alarm / IRQ pin interrupt ////////////////////////////////
kenjiArai 5:959683e91979 171 void M41T62::clear_IRQ ()
kenjiArai 5:959683e91979 172 {
kenjiArai 5:959683e91979 173 for (uint32_t i = 0; i < 40; i++) {
kenjiArai 5:959683e91979 174 rtc_buf[0] = M41T62_REG_FLAGS;
kenjiArai 5:959683e91979 175 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 176 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
kenjiArai 5:959683e91979 177 if ((rtc_buf[0] & 0x40) == 0) {
kenjiArai 5:959683e91979 178 break;
kenjiArai 5:959683e91979 179 }
kenjiArai 5:959683e91979 180 }
kenjiArai 5:959683e91979 181 // clear AFE(alarm enable flag)
kenjiArai 5:959683e91979 182 rtc_buf[0] = M41T62_REG_ALARM_MON;
kenjiArai 5:959683e91979 183 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 184 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
kenjiArai 5:959683e91979 185 rtc_buf[1] = rtc_buf[0] & 0x40; // keep SQWE bit
kenjiArai 5:959683e91979 186 rtc_buf[0] = M41T62_REG_ALARM_MON;
kenjiArai 5:959683e91979 187 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
kenjiArai 5:959683e91979 188 // set OUT = 1
kenjiArai 5:959683e91979 189 rtc_buf[0] = M41T62_REG_CALIB;
kenjiArai 5:959683e91979 190 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 191 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
kenjiArai 5:959683e91979 192 rtc_buf[1] = rtc_buf[0] & 0x3f; // keep calbration data
kenjiArai 5:959683e91979 193 rtc_buf[1] = rtc_buf[0] | 0x80; // set OUT
kenjiArai 5:959683e91979 194 rtc_buf[0] = M41T62_REG_CALIB;
kenjiArai 5:959683e91979 195 }
kenjiArai 5:959683e91979 196
kenjiArai 5:959683e91979 197 /////////////// I2C Freq. //////////////////////////////////////////////////////
kenjiArai 5:959683e91979 198 void M41T62::frequency (int hz)
kenjiArai 3:41c351da2fdf 199 {
kenjiArai 3:41c351da2fdf 200 _i2c.frequency(hz);
kenjiArai 3:41c351da2fdf 201 }
kenjiArai 3:41c351da2fdf 202
kenjiArai 5:959683e91979 203 /////////////// Square wave output /////////////////////////////////////////////
kenjiArai 5:959683e91979 204 void M41T62::set_sq_wave (sq_wave_t sqw_dt)
kenjiArai 3:41c351da2fdf 205 {
kenjiArai 1:9d7702a887d3 206 // set SQW frequency
kenjiArai 5:959683e91979 207 rtc_buf[0] = M41T62_REG_WDAY;
kenjiArai 5:959683e91979 208 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 209 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
kenjiArai 5:959683e91979 210 rtc_buf[1] = (rtc_buf[0] & 0x07) | (sqw_dt << 4);
kenjiArai 5:959683e91979 211 rtc_buf[0] = M41T62_REG_WDAY;
kenjiArai 5:959683e91979 212 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
kenjiArai 1:9d7702a887d3 213 // set or clear SQWE
kenjiArai 5:959683e91979 214 rtc_buf[0] = M41T62_REG_ALARM_MON;
kenjiArai 5:959683e91979 215 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
kenjiArai 5:959683e91979 216 _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
kenjiArai 3:41c351da2fdf 217 if (sqw_dt == RTC_SQW_NONE) { // Clear SQWE
kenjiArai 5:959683e91979 218 rtc_buf[1] = rtc_buf[0] & 0xbf;
kenjiArai 1:9d7702a887d3 219 } else { // Set SQWE
kenjiArai 5:959683e91979 220 rtc_buf[1] = rtc_buf[0] | 0x40;
kenjiArai 1:9d7702a887d3 221 }
kenjiArai 5:959683e91979 222 rtc_buf[0] = M41T62_REG_ALARM_MON;
kenjiArai 5:959683e91979 223 _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
kenjiArai 0:2919f8bd90f3 224 }
kenjiArai 0:2919f8bd90f3 225
kenjiArai 5:959683e91979 226 /////////////// conversion BCD & BIN ///////////////////////////////////////////
kenjiArai 3:41c351da2fdf 227 uint8_t M41T62::bin2bcd (uint8_t dt)
kenjiArai 3:41c351da2fdf 228 {
kenjiArai 3:41c351da2fdf 229 uint8_t bcdhigh = 0;
kenjiArai 0:2919f8bd90f3 230
kenjiArai 3:41c351da2fdf 231 while (dt >= 10) {
kenjiArai 0:2919f8bd90f3 232 bcdhigh++;
kenjiArai 0:2919f8bd90f3 233 dt -= 10;
kenjiArai 0:2919f8bd90f3 234 }
kenjiArai 0:2919f8bd90f3 235 return ((uint8_t)(bcdhigh << 4) | dt);
kenjiArai 0:2919f8bd90f3 236 }
kenjiArai 0:2919f8bd90f3 237
kenjiArai 3:41c351da2fdf 238 uint8_t M41T62::bcd2bin (uint8_t dt)
kenjiArai 3:41c351da2fdf 239 {
kenjiArai 3:41c351da2fdf 240 uint8_t tmp = 0;
kenjiArai 0:2919f8bd90f3 241
kenjiArai 0:2919f8bd90f3 242 tmp = ((uint8_t)(dt & (uint8_t)0xf0) >> (uint8_t)0x4) * 10;
kenjiArai 0:2919f8bd90f3 243 return (tmp + (dt & (uint8_t)0x0f));
kenjiArai 0:2919f8bd90f3 244 }