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

Dependents:   LPC1114_data_logger Check_external_RTC LPC1114_barometer_with_data_logging

Revision:
5:959683e91979
Parent:
4:0c07690cb24f
Child:
6:0bf0f681fb69
--- a/m41t62_rtc.cpp	Wed Aug 23 09:26:41 2017 +0000
+++ b/m41t62_rtc.cpp	Fri Aug 07 05:39:14 2020 +0000
@@ -1,34 +1,38 @@
 /*
  * mbed library program
  *  Control M41T62 RTC Module
+ *  STMicroelectronics
  *
- * Copyright (c) 2014,'15,'17 Kenji Arai / JH1PJL
- *  http://www.page.sannet.ne.jp/kenjia/index.html
- *  http://mbed.org/users/kenjiArai/
+ * Copyright (c) 2014,'15,'17,'20 Kenji Arai / JH1PJL
+ *  http://www7b.biglobe.ne.jp/~kenjia/
+ *  https://os.mbed.com/users/kenjiArai/
  *      Created: June       21st, 2014
- *      Revised: August     23rd, 2017
- */
-/*
- *---------------- REFERENCE ----------------------------------------------------------------------
- *  http://www.st-japan.co.jp/web/jp/catalog/sense_power/FM151/CL1410/SC403/PF82507
- *  http://strawberry-linux.com/catalog/items?code=12062
+ *      Revised: August      7th, 2020
  */
 
 #include "mbed.h"
 #include "m41t62_rtc.h"
 
+#define RTC_Wk_Sunday          ((uint8_t)0x00)
+
 M41T62::M41T62 (PinName p_sda, PinName p_scl)
- : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
+    : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
 {
     M41T62_addr = M41T62ADDR;
-    _i2c.frequency(100000);
+    _i2c.frequency(400000);
 }
 
 M41T62::M41T62 (I2C& p_i2c)
- : _i2c(p_i2c)
+    : _i2c(p_i2c)
 {
     M41T62_addr = M41T62ADDR;
-    _i2c.frequency(100000);
+    _i2c.frequency(400000);
+}
+
+/////////////// Read RTC data //////////////////////////////////////////////////
+void M41T62::get_time_rtc (tm *t)
+{
+    read_rtc_std(t);
 }
 
 void M41T62::read_rtc_std (tm *t)
@@ -50,6 +54,12 @@
     t->tm_isdst= 0;
 }
 
+/////////////// Write data to RTC //////////////////////////////////////////////
+void M41T62::set_time_rtc (tm *t)
+{
+    write_rtc_std(t);
+}
+
 void M41T62::write_rtc_std (tm *t)
 {
     rtc_time time;
@@ -68,13 +78,12 @@
     write_rtc_direct(&time);
 }
 
+/////////////// Read/Write RTC another format //////////////////////////////////
 void M41T62::read_rtc_direct (rtc_time *tm)
 {
-    uint8_t eep_dt;
-
-    eep_dt = M41T62_REG_SSEC;
-    _i2c.write((int)M41T62_addr, (char *)eep_dt, 1);
-    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 8);
+    rtc_buf[0] = M41T62_REG_SSEC;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 8, false);
     tm->rtc_seconds = bcd2bin(rtc_buf[M41T62_REG_SEC]  & 0x7f);
     tm->rtc_minutes = bcd2bin(rtc_buf[M41T62_REG_MIN]  & 0x7f);
     tm->rtc_hours   = bcd2bin(rtc_buf[M41T62_REG_HOUR] & 0x3f);
@@ -87,55 +96,136 @@
 
 void M41T62::write_rtc_direct (rtc_time *tm)
 {
-    uint8_t eep_dt;
-
-    eep_dt = M41T62_REG_SSEC;
-    _i2c.write((int)M41T62_addr, (char *)eep_dt, 1);
-    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 8);
-    rtc_buf[0] = M41T62_REG_SSEC;
+    rtc_buf[M41T62_REG_YEAR + 1] = bin2bcd(tm->rtc_year_raw);
+    rtc_buf[M41T62_REG_MON  + 1] = bin2bcd(tm->rtc_month)   & 0x1f;
+    rtc_buf[M41T62_REG_DAY  + 1] = bin2bcd(tm->rtc_date)    & 0x3f;
+    rtc_buf[M41T62_REG_WDAY + 1] = (tm->rtc_weekday & 0x07);
+    rtc_buf[M41T62_REG_HOUR + 1] = bin2bcd(tm->rtc_hours)   & 0x3f;
+    rtc_buf[M41T62_REG_MIN  + 1] = bin2bcd(tm->rtc_minutes) & 0x7f;
+    rtc_buf[M41T62_REG_SEC  + 1] = bin2bcd(tm->rtc_seconds) & 0x7f;
     rtc_buf[M41T62_REG_SSEC + 1] = 0;
-    rtc_buf[M41T62_REG_YEAR + 1] = bin2bcd(tm->rtc_year_raw);
-    rtc_buf[M41T62_REG_MON  + 1] = bin2bcd(tm->rtc_month)   | (rtc_buf[M41T62_REG_MON]  & ~0x1f);
-    rtc_buf[M41T62_REG_DAY  + 1] = bin2bcd(tm->rtc_date)    | (rtc_buf[M41T62_REG_DAY]  & ~0x3f);
-    rtc_buf[M41T62_REG_WDAY + 1] = (tm->rtc_weekday & 0x07) | (rtc_buf[M41T62_REG_WDAY] & ~0x07);
-    rtc_buf[M41T62_REG_HOUR + 1] = bin2bcd(tm->rtc_hours)   | (rtc_buf[M41T62_REG_HOUR] & ~0x3f);
-    rtc_buf[M41T62_REG_MIN  + 1] = bin2bcd(tm->rtc_minutes) | (rtc_buf[M41T62_REG_MIN]  & ~0x7f);
-    rtc_buf[M41T62_REG_SEC  + 1] = bin2bcd(tm->rtc_seconds) | (rtc_buf[M41T62_REG_SEC]  & ~0x7f);
-    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 9);
+    rtc_buf[0] = M41T62_REG_SSEC;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 9, false);
 }
 
-void M41T62::frequency(int hz)
+/////////////// Set Alarm / IRQ ////////////////////////////////////////////////
+void M41T62::set_alarm_reg (uint16_t time)
+{
+    tm t;
+    uint8_t m, h;
+    uint16_t set;
+
+    read_rtc_std(&t);   // read current time
+    set = time + t.tm_hour * 60 + t.tm_min;
+    m = t.tm_min + (uint8_t)(time % 60);
+    h = t.tm_hour;
+    if (m >= 60) {
+        m -= 60;
+        h += 1;
+    }
+    h += (uint8_t)(time / 60);
+    if (h >= 24) {
+        h -= 24;
+    }
+    // set OUT = 1
+    rtc_buf[0] = M41T62_REG_CALIB;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
+    rtc_buf[1] = rtc_buf[0] & 0x3f;     // keep calbration data
+    rtc_buf[1] = rtc_buf[0] | 0x80;     // set OUT
+    rtc_buf[0] = M41T62_REG_CALIB;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
+    // RPT4=1,RPT5=0,RPT3=0,RPT2=0,RPT1=0 & set day,hour,min,sec
+    rtc_buf[4] = 0;                 // M41T62_REG_ALARM_SEC ->RPT=1, set 0sec
+    rtc_buf[3] = bin2bcd(m) & 0x3f; // M41T62_REG_ALARM_MIN ->RPT2=0
+    rtc_buf[2] = bin2bcd(h) & 0x7f; // M41T62_REG_ALARM_HOUR ->RPT3=0
+    rtc_buf[1] = 0xc0;              // M41T62_REG_ALARM_DAY ->RPT4=1,RPT5=1
+    rtc_buf[0] = M41T62_REG_ALARM_DAY;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 5, false);
+    // set AFE(alarm enable flag)
+    rtc_buf[0] = M41T62_REG_ALARM_MON;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
+    rtc_buf[1] = rtc_buf[0] & 0x40;     // keep SQWE bit
+    rtc_buf[1] |= 0x80;                 // set AFE
+    rtc_buf[0] = M41T62_REG_ALARM_MON;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
+}
+
+void M41T62::set_next_IRQ (uint16_t time)
+{
+    uint16_t t;
+
+    if (time < 2) {
+        // Alarm does not check seconds digit.
+        // If 59 to 0 is occured during setting here,
+        // 1 minute will have a trouble.
+        t = 2;
+    } else if (time > 1440) {  // set less than 24 hours
+        t = 1440;
+    } else {
+        t = time;
+    }
+    set_alarm_reg(t);
+}
+
+/////////////// Clear Alarm / IRQ pin interrupt ////////////////////////////////
+void M41T62::clear_IRQ ()
+{
+    for (uint32_t i = 0; i < 40; i++) {
+        rtc_buf[0] = M41T62_REG_FLAGS;
+        _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+        _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
+        if ((rtc_buf[0] & 0x40) == 0) {
+            break;
+        }
+    }
+    // clear AFE(alarm enable flag)
+    rtc_buf[0] = M41T62_REG_ALARM_MON;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
+    rtc_buf[1] = rtc_buf[0] & 0x40;     // keep SQWE bit
+    rtc_buf[0] = M41T62_REG_ALARM_MON;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
+    // set OUT = 1
+    rtc_buf[0] = M41T62_REG_CALIB;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
+    rtc_buf[1] = rtc_buf[0] & 0x3f;     // keep calbration data
+    rtc_buf[1] = rtc_buf[0] | 0x80;     // set OUT
+    rtc_buf[0] = M41T62_REG_CALIB;
+}
+
+/////////////// I2C Freq. //////////////////////////////////////////////////////
+void M41T62::frequency (int hz)
 {
     _i2c.frequency(hz);
 }
 
-void M41T62::set_sq_wave (uint8_t sqw_dt)
+/////////////// Square wave output /////////////////////////////////////////////
+void M41T62::set_sq_wave (sq_wave_t sqw_dt)
 {
-    uint8_t eep_dt[2];
-
     // set SQW frequency
-    eep_dt[0] = M41T62_REG_WDAY;
-    _i2c.write((int)M41T62_addr, (char *)eep_dt, 1);
-    _i2c.read((int)M41T62_addr, (char *)eep_dt, 1);
-    eep_dt[1] = (eep_dt[0] & 0x07) | (sqw_dt << 4);
-    eep_dt[0] = M41T62_REG_WDAY;
-    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2);
+    rtc_buf[0] = M41T62_REG_WDAY;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
+    rtc_buf[1] = (rtc_buf[0] & 0x07) | (sqw_dt << 4);
+    rtc_buf[0] = M41T62_REG_WDAY;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
     // set or clear SQWE
-    eep_dt[0] = M41T62_REG_ALARM_MON;
-    _i2c.write((int)M41T62_addr, (char *)eep_dt, 1);
-    _i2c.read((int)M41T62_addr, (char *)eep_dt, 1);
-    eep_dt[1] = (eep_dt[0] & 0x07) | (sqw_dt << 4);
-    eep_dt[0] = M41T62_REG_WDAY;
-    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2);
+    rtc_buf[0] = M41T62_REG_ALARM_MON;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 1, true);
+    _i2c.read((int)M41T62_addr, (char *)rtc_buf, 1, false);
     if (sqw_dt == RTC_SQW_NONE) {   // Clear SQWE
-        eep_dt[1] = eep_dt[0] & 0xbf;
+        rtc_buf[1] = rtc_buf[0] & 0xbf;
     } else {                        // Set SQWE
-        eep_dt[1] = eep_dt[0] | 0x40;
+        rtc_buf[1] = rtc_buf[0] | 0x40;
     }
-    eep_dt[0] = M41T62_REG_ALARM_MON;
-    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2);
+    rtc_buf[0] = M41T62_REG_ALARM_MON;
+    _i2c.write((int)M41T62_addr, (char *)rtc_buf, 2, false);
 }
 
+/////////////// conversion BCD & BIN ///////////////////////////////////////////
 uint8_t M41T62::bin2bcd (uint8_t dt)
 {
     uint8_t bcdhigh = 0;
@@ -154,5 +244,3 @@
     tmp = ((uint8_t)(dt & (uint8_t)0xf0) >> (uint8_t)0x4) * 10;
     return (tmp + (dt & (uint8_t)0x0f));
 }
-
-