From cdae2475f1857aa030f1e556bc8f9768a079e352 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 27 Apr 2022 23:02:09 +0200 Subject: [PATCH 01/50] Added new class RTC_RV3032C7 (based on RTC_DS3231) to RTClib.h --- src/RTClib.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/RTClib.h b/src/RTClib.h index 380ada80..c87cec3a 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -394,6 +394,38 @@ class RTC_DS3231 : RTC_I2C { static uint8_t dowToDS3231(uint8_t d) { return d == 0 ? 7 : d; } }; +/**************************************************************************/ +/*! + @brief RTC based on the RV-3032-C7 chip connected via I2C and the Wire library +*/ +/**************************************************************************/ +class RTC_RV3032C7 : RTC_I2C { +public: + boolean begin(TwoWire *wireInstance = &Wire); + void adjust(const DateTime &dt); + bool lostPower(void); + DateTime now(); + Ds3231SqwPinMode readSqwPinMode(); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type + void writeSqwPinMode(Ds3231SqwPinMode mode); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type + bool setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode); // TODO: replace Ds3231Alarm1Mode with proper RV3032C7 type + bool setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode); // TODO: replace Ds3231Alarm1Mode with proper RV3032C7 type + void disableAlarm(uint8_t alarm_num); + void clearAlarm(uint8_t alarm_num); + bool alarmFired(uint8_t alarm_num); + void enable32K(void); + void disable32K(void); + bool isEnabled32K(void); + float getTemperature(); // in Celsius degree + /*! + @brief Convert the day of the week to a representation suitable for + storing in the RV3032C7: from 1 (Monday) to 7 (Sunday). + @param d Day of the week as represented by the library: + from 0 (Sunday) to 6 (Saturday). + @return the converted value + */ + static uint8_t dowToRV3032C7(uint8_t d) { return d == 0 ? 7 : d; } +}; + /**************************************************************************/ /*! @brief RTC based on the PCF8523 chip connected via I2C and the Wire library From 9a90bdf3acf573eb7f1e8982b36b23c9b91a167e Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 27 Apr 2022 23:17:08 +0200 Subject: [PATCH 02/50] Added RTC_RV3032C7.cpp (based on RTC_DS3231.cpp) --- src/RTC_RV3032C7.cpp | 251 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 src/RTC_RV3032C7.cpp diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp new file mode 100644 index 00000000..a790ac96 --- /dev/null +++ b/src/RTC_RV3032C7.cpp @@ -0,0 +1,251 @@ +#include "RTClib.h" + +#define RV3032C7_ADDRESS 0x68 ///< I2C address for RV3032C7 +#define RV3032C7_TIME 0x00 ///< Time register +#define RV3032C7_ALARM1 0x07 ///< Alarm 1 register +#define RV3032C7_ALARM2 0x0B ///< Alarm 2 register +#define RV3032C7_CONTROL 0x0E ///< Control register +#define RV3032C7_STATUSREG 0x0F ///< Status register +#define RV3032C7_TEMPERATUREREG \ + 0x11 ///< Temperature register (high byte - low byte is at 0x12), 10-bit + ///< temperature value + +/**************************************************************************/ +/*! + @brief Start I2C for the RV3032C7 and test succesful connection + @param wireInstance pointer to the I2C bus + @return True if Wire can find RV3032C7 or false otherwise. +*/ +/**************************************************************************/ +boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { + if (i2c_dev) + delete i2c_dev; + i2c_dev = new Adafruit_I2CDevice(RV3032C7_ADDRESS, wireInstance); + if (!i2c_dev->begin()) + return false; + return true; +} + +/**************************************************************************/ +/*! + @brief Check the status register Oscillator Stop Flag to see if the RV3032C7 + stopped due to power loss + @return True if the bit is set (oscillator stopped) or false if it is + running +*/ +/**************************************************************************/ +bool RTC_RV3032C7::lostPower(void) { + return read_register(RV3032C7_STATUSREG) >> 7; +} + +/**************************************************************************/ +/*! + @brief Set the date and flip the Oscillator Stop Flag + @param dt DateTime object containing the date/time to set +*/ +/**************************************************************************/ +void RTC_RV3032C7::adjust(const DateTime &dt) { + uint8_t buffer[8] = {RV3032C7_TIME, + bin2bcd(dt.second()), + bin2bcd(dt.minute()), + bin2bcd(dt.hour()), + bin2bcd(dowToRV3032C7(dt.dayOfTheWeek())), + bin2bcd(dt.day()), + bin2bcd(dt.month()), + bin2bcd(dt.year() - 2000U)}; + i2c_dev->write(buffer, 8); + + uint8_t statreg = read_register(RV3032C7_STATUSREG); + statreg &= ~0x80; // flip OSF bit + write_register(RV3032C7_STATUSREG, statreg); +} + +/**************************************************************************/ +/*! + @brief Get the current date/time + @return DateTime object with the current date/time +*/ +/**************************************************************************/ +DateTime RTC_RV3032C7::now() { + uint8_t buffer[7]; + buffer[0] = 0; + i2c_dev->write_then_read(buffer, 1, buffer, 7); + + return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x7F), + bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]), + bcd2bin(buffer[0] & 0x7F)); +} + +/**************************************************************************/ +/*! + @brief Read the SQW pin mode + @return Pin mode, see Ds3231SqwPinMode enum +*/ +/**************************************************************************/ +Ds3231SqwPinMode RTC_RV3032C7::readSqwPinMode() { + int mode; + mode = read_register(RV3032C7_CONTROL) & 0x1C; + if (mode & 0x04) + mode = DS3231_OFF; + return static_cast(mode); +} + +/**************************************************************************/ +/*! + @brief Set the SQW pin mode + @param mode Desired mode, see Ds3231SqwPinMode enum +*/ +/**************************************************************************/ +void RTC_RV3032C7::writeSqwPinMode(Ds3231SqwPinMode mode) { + uint8_t ctrl = read_register(RV3032C7_CONTROL); + + ctrl &= ~0x04; // turn off INTCON + ctrl &= ~0x18; // set freq bits to 0 + + write_register(RV3032C7_CONTROL, ctrl | mode); +} + +/**************************************************************************/ +/*! + @brief Get the current temperature from the RV3032C7's temperature sensor + @return Current temperature (float) +*/ +/**************************************************************************/ +float RTC_RV3032C7::getTemperature() { + uint8_t buffer[2] = {RV3032C7_TEMPERATUREREG, 0}; + i2c_dev->write_then_read(buffer, 1, buffer, 2); + return (float)buffer[0] + (buffer[1] >> 6) * 0.25f; +} + +/**************************************************************************/ +/*! + @brief Set alarm 1 for RV3032C7 + @param dt DateTime object + @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum + @return False if control register is not set, otherwise true +*/ +/**************************************************************************/ +bool RTC_RV3032C7::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) { + uint8_t ctrl = read_register(RV3032C7_CONTROL); + if (!(ctrl & 0x04)) { + return false; + } + + uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Seconds bit 7. + uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Minutes bit 7. + uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Hour bit 7. + uint8_t A1M4 = (alarm_mode & 0x08) << 4; // Day/Date bit 7. + uint8_t DY_DT = (alarm_mode & 0x10) + << 2; // Day/Date bit 6. Date when 0, day of week when 1. + uint8_t day = (DY_DT) ? dowToRV3032C7(dt.dayOfTheWeek()) : dt.day(); + + uint8_t buffer[5] = {RV3032C7_ALARM1, uint8_t(bin2bcd(dt.second()) | A1M1), + uint8_t(bin2bcd(dt.minute()) | A1M2), + uint8_t(bin2bcd(dt.hour()) | A1M3), + uint8_t(bin2bcd(day) | A1M4 | DY_DT)}; + i2c_dev->write(buffer, 5); + + write_register(RV3032C7_CONTROL, ctrl | 0x01); // AI1E + + return true; +} + +/**************************************************************************/ +/*! + @brief Set alarm 2 for RV3032C7 + @param dt DateTime object + @param alarm_mode Desired mode, see Ds3231Alarm2Mode enum + @return False if control register is not set, otherwise true +*/ +/**************************************************************************/ +bool RTC_RV3032C7::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) { + uint8_t ctrl = read_register(RV3032C7_CONTROL); + if (!(ctrl & 0x04)) { + return false; + } + + uint8_t A2M2 = (alarm_mode & 0x01) << 7; // Minutes bit 7. + uint8_t A2M3 = (alarm_mode & 0x02) << 6; // Hour bit 7. + uint8_t A2M4 = (alarm_mode & 0x04) << 5; // Day/Date bit 7. + uint8_t DY_DT = (alarm_mode & 0x08) + << 3; // Day/Date bit 6. Date when 0, day of week when 1. + uint8_t day = (DY_DT) ? dowToRV3032C7(dt.dayOfTheWeek()) : dt.day(); + + uint8_t buffer[4] = {RV3032C7_ALARM2, uint8_t(bin2bcd(dt.minute()) | A2M2), + uint8_t(bin2bcd(dt.hour()) | A2M3), + uint8_t(bin2bcd(day) | A2M4 | DY_DT)}; + i2c_dev->write(buffer, 4); + + write_register(RV3032C7_CONTROL, ctrl | 0x02); // AI2E + + return true; +} + +/**************************************************************************/ +/*! + @brief Disable alarm + @param alarm_num Alarm number to disable +*/ +/**************************************************************************/ +void RTC_RV3032C7::disableAlarm(uint8_t alarm_num) { + uint8_t ctrl = read_register(RV3032C7_CONTROL); + ctrl &= ~(1 << (alarm_num - 1)); + write_register(RV3032C7_CONTROL, ctrl); +} + +/**************************************************************************/ +/*! + @brief Clear status of alarm + @param alarm_num Alarm number to clear +*/ +/**************************************************************************/ +void RTC_RV3032C7::clearAlarm(uint8_t alarm_num) { + uint8_t status = read_register(RV3032C7_STATUSREG); + status &= ~(0x1 << (alarm_num - 1)); + write_register(RV3032C7_STATUSREG, status); +} + +/**************************************************************************/ +/*! + @brief Get status of alarm + @param alarm_num Alarm number to check status of + @return True if alarm has been fired otherwise false +*/ +/**************************************************************************/ +bool RTC_RV3032C7::alarmFired(uint8_t alarm_num) { + return (read_register(RV3032C7_STATUSREG) >> (alarm_num - 1)) & 0x1; +} + +/**************************************************************************/ +/*! + @brief Enable 32KHz Output + @details The 32kHz output is enabled by default. It requires an external + pull-up resistor to function correctly +*/ +/**************************************************************************/ +void RTC_RV3032C7::enable32K(void) { + uint8_t status = read_register(RV3032C7_STATUSREG); + status |= (0x1 << 0x03); + write_register(RV3032C7_STATUSREG, status); +} + +/**************************************************************************/ +/*! + @brief Disable 32KHz Output +*/ +/**************************************************************************/ +void RTC_RV3032C7::disable32K(void) { + uint8_t status = read_register(RV3032C7_STATUSREG); + status &= ~(0x1 << 0x03); + write_register(RV3032C7_STATUSREG, status); +} + +/**************************************************************************/ +/*! + @brief Get status of 32KHz Output + @return True if enabled otherwise false +*/ +/**************************************************************************/ +bool RTC_RV3032C7::isEnabled32K(void) { + return (read_register(RV3032C7_STATUSREG) >> 0x03) & 0x01; +} From 37e69bc3b565ef64978a519880d342c93b841e54 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Fri, 29 Apr 2022 18:19:24 +0200 Subject: [PATCH 03/50] Implemented basic functions in RTC_RV3032C7.cpp (set/get time, temp., powerloss) --- src/RTC_RV3032C7.cpp | 115 +++++++++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 31 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index a790ac96..1b8e79d3 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -1,14 +1,39 @@ #include "RTClib.h" +// TODO: only what is needed in basic example implemented right now. -#define RV3032C7_ADDRESS 0x68 ///< I2C address for RV3032C7 -#define RV3032C7_TIME 0x00 ///< Time register -#define RV3032C7_ALARM1 0x07 ///< Alarm 1 register -#define RV3032C7_ALARM2 0x0B ///< Alarm 2 register -#define RV3032C7_CONTROL 0x0E ///< Control register -#define RV3032C7_STATUSREG 0x0F ///< Status register -#define RV3032C7_TEMPERATUREREG \ - 0x11 ///< Temperature register (high byte - low byte is at 0x12), 10-bit +//#define DEBUG_SERIAL Serial +#define DEBUG_SERIAL SerialUSB +//#ifdef DEBUG_SERIAL +// #include +//#endif + +#define RV3032C7_ADDRESS 0x51 ///< I2C address for RV3032C7 +#define RV3032C7_100TH_SEC 0x00 ///< Time - 100th seconds +#define RV3032C7_SECONDS 0x01 ///< time - seconds +#define RV3032C7_ALARM1 0x08 ///< Alarm 1 register +#define RV3032C7_ALARM2 0x0B ///< Alarm 2 register +#define RV3032C7_STATUSREG 0x0D ///< Status register +#define RV3032C7_CONTROL1 0x10 ///< Control register +#define RV3032C7_CONTROL2 0x11 ///< Control register +#define RV3032C7_CONTROL3 0x12 ///< Control register +#define RV3032C7_TEMPERATUREREG \ + 0x0E ///< Temperature register (bit 4-7 = lowest 4 bits. + /// high byte is at 0x0F), 12-bit ///< temperature value +#define RV3032C7_TEMPERATURE8BIT 0x0F ///< 8-bit temperature + +// Status register flags +#define RV3032C7_THF 0x80 ///< Temp. High +#define RV3032C7_TLF 0x40 ///< Temp. Low +#define RV3032C7_UF 0x20 ///< Periodic Time Update +#define RV3032C7_TF 0x10 ///< Periodic Coundown Timer +#define RV3032C7_AF 0x08 ///< Alarm +#define RV3032C7_EVF 0x04 ///< External Event +#define RV3032C7_PORF 0x02 ///< Power On Reset +#define RV3032C7_VLF 0x01 ///< Voltage Low + +// Control register flags +#define RV3032C7_STOP 0x01 ///< Control2, STOP bit /**************************************************************************/ /*! @@ -28,24 +53,24 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { /**************************************************************************/ /*! - @brief Check the status register Oscillator Stop Flag to see if the RV3032C7 + @brief Check the status register PORF flag to see if the RV3032C7 stopped due to power loss @return True if the bit is set (oscillator stopped) or false if it is - running + running. TODO: add an option to check for loss of precision (VLF flag) */ /**************************************************************************/ bool RTC_RV3032C7::lostPower(void) { - return read_register(RV3032C7_STATUSREG) >> 7; + return (read_register(RV3032C7_STATUSREG) & RV3032C7_PORF) != 0 ? true : false; } /**************************************************************************/ /*! - @brief Set the date and flip the Oscillator Stop Flag + @brief Set the date and make sure the Oscillator Stop bit is cleared @param dt DateTime object containing the date/time to set */ /**************************************************************************/ void RTC_RV3032C7::adjust(const DateTime &dt) { - uint8_t buffer[8] = {RV3032C7_TIME, + uint8_t buffer[8] = {RV3032C7_SECONDS, bin2bcd(dt.second()), bin2bcd(dt.minute()), bin2bcd(dt.hour()), @@ -55,9 +80,32 @@ void RTC_RV3032C7::adjust(const DateTime &dt) { bin2bcd(dt.year() - 2000U)}; i2c_dev->write(buffer, 8); - uint8_t statreg = read_register(RV3032C7_STATUSREG); - statreg &= ~0x80; // flip OSF bit - write_register(RV3032C7_STATUSREG, statreg); + // Clear the Power On Reset Flag (PORF) + uint8_t stat = read_register(RV3032C7_STATUSREG); // TODO: remove read_register, not needed after initial debug period + #ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("RTCLib RV3032C7_STATUSREG=")); DEBUG_SERIAL.println(stat, BIN); + #endif + write_register(RV3032C7_STATUSREG, ~RV3032C7_PORF); + stat = read_register(RV3032C7_STATUSREG); + #ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("STATUS after clearing PORF=")); DEBUG_SERIAL.println(stat, BIN); + #endif + + /* + // Check STOP bit, clear if set + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + + #ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("RTCLib RV3032C7_CONTROL2=")); DEBUG_SERIAL.println(ctrl2, BIN); + #endif + if ( (ctrl2 & RV3032C7_STOP) >0) { // Oscillator is stopped + ctrl2 &= ~RV3032C7_STOP; // clear STOP bit + #ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("RTCLib RV3032C7_CONTROL2=")); DEBUG_SERIAL.println(ctrl2, BIN); + #endif + //write_register(RV3032C7_CONTROL2, ctrl2); + } + */ } /**************************************************************************/ @@ -68,12 +116,12 @@ void RTC_RV3032C7::adjust(const DateTime &dt) { /**************************************************************************/ DateTime RTC_RV3032C7::now() { uint8_t buffer[7]; - buffer[0] = 0; + buffer[0] = RV3032C7_SECONDS; i2c_dev->write_then_read(buffer, 1, buffer, 7); - return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5] & 0x7F), + return DateTime(bcd2bin(buffer[6]) + 2000U, bcd2bin(buffer[5]), bcd2bin(buffer[4]), bcd2bin(buffer[2]), bcd2bin(buffer[1]), - bcd2bin(buffer[0] & 0x7F)); + bcd2bin(buffer[0])); // Note: RV3032C7 unused bits read = 0 } /**************************************************************************/ @@ -84,7 +132,7 @@ DateTime RTC_RV3032C7::now() { /**************************************************************************/ Ds3231SqwPinMode RTC_RV3032C7::readSqwPinMode() { int mode; - mode = read_register(RV3032C7_CONTROL) & 0x1C; + mode = read_register(RV3032C7_CONTROL1) & 0x1C; if (mode & 0x04) mode = DS3231_OFF; return static_cast(mode); @@ -97,12 +145,12 @@ Ds3231SqwPinMode RTC_RV3032C7::readSqwPinMode() { */ /**************************************************************************/ void RTC_RV3032C7::writeSqwPinMode(Ds3231SqwPinMode mode) { - uint8_t ctrl = read_register(RV3032C7_CONTROL); + uint8_t ctrl = read_register(RV3032C7_CONTROL1); ctrl &= ~0x04; // turn off INTCON ctrl &= ~0x18; // set freq bits to 0 - write_register(RV3032C7_CONTROL, ctrl | mode); + //write_register(RV3032C7_CONTROL1, ctrl | mode); } /**************************************************************************/ @@ -112,9 +160,14 @@ void RTC_RV3032C7::writeSqwPinMode(Ds3231SqwPinMode mode) { */ /**************************************************************************/ float RTC_RV3032C7::getTemperature() { - uint8_t buffer[2] = {RV3032C7_TEMPERATUREREG, 0}; - i2c_dev->write_then_read(buffer, 1, buffer, 2); - return (float)buffer[0] + (buffer[1] >> 6) * 0.25f; + uint8_t buffer1[2]; + uint8_t buffer2[2]; + do { // no blocking, so read twice as suggested in the app. manual + buffer1[0] = buffer2[0] = RV3032C7_TEMPERATUREREG; + i2c_dev->write_then_read(buffer1, 1, buffer1, 2); + i2c_dev->write_then_read(buffer2, 1, buffer2, 2); + } while ( (buffer1[0] != buffer2[0]) || (buffer1[1] != buffer2[1]) ); + return float( int(buffer1[1]<<4) + (buffer1[0]>>4) ) * 0.0625f; } /**************************************************************************/ @@ -126,7 +179,7 @@ float RTC_RV3032C7::getTemperature() { */ /**************************************************************************/ bool RTC_RV3032C7::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) { - uint8_t ctrl = read_register(RV3032C7_CONTROL); + uint8_t ctrl = read_register(RV3032C7_CONTROL1); if (!(ctrl & 0x04)) { return false; } @@ -145,7 +198,7 @@ bool RTC_RV3032C7::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) { uint8_t(bin2bcd(day) | A1M4 | DY_DT)}; i2c_dev->write(buffer, 5); - write_register(RV3032C7_CONTROL, ctrl | 0x01); // AI1E + write_register(RV3032C7_CONTROL1, ctrl | 0x01); // AI1E return true; } @@ -159,7 +212,7 @@ bool RTC_RV3032C7::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) { */ /**************************************************************************/ bool RTC_RV3032C7::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) { - uint8_t ctrl = read_register(RV3032C7_CONTROL); + uint8_t ctrl = read_register(RV3032C7_CONTROL1); if (!(ctrl & 0x04)) { return false; } @@ -176,7 +229,7 @@ bool RTC_RV3032C7::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) { uint8_t(bin2bcd(day) | A2M4 | DY_DT)}; i2c_dev->write(buffer, 4); - write_register(RV3032C7_CONTROL, ctrl | 0x02); // AI2E + write_register(RV3032C7_CONTROL1, ctrl | 0x02); // AI2E return true; } @@ -188,9 +241,9 @@ bool RTC_RV3032C7::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) { */ /**************************************************************************/ void RTC_RV3032C7::disableAlarm(uint8_t alarm_num) { - uint8_t ctrl = read_register(RV3032C7_CONTROL); + uint8_t ctrl = read_register(RV3032C7_CONTROL1); ctrl &= ~(1 << (alarm_num - 1)); - write_register(RV3032C7_CONTROL, ctrl); + write_register(RV3032C7_CONTROL1, ctrl); } /**************************************************************************/ From 204a393bb56f86f4bc84377120b9afa23255e357 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Fri, 29 Apr 2022 18:32:19 +0200 Subject: [PATCH 04/50] Added basic example (tested, works) --- examples/RV3032C7/RV3032C7.ino | 86 ++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 examples/RV3032C7/RV3032C7.ino diff --git a/examples/RV3032C7/RV3032C7.ino b/examples/RV3032C7/RV3032C7.ino new file mode 100644 index 00000000..f65f72f3 --- /dev/null +++ b/examples/RV3032C7/RV3032C7.ino @@ -0,0 +1,86 @@ +// Date and time functions using a RV3032C7 RTC connected via I2C and Wire lib +#include "RTClib.h" + +RTC_RV3032C7 rtc; + +char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; + +void setup () { + Serial.begin(57600); + +#ifndef ESP8266 + while (!Serial); // wait for serial port to connect. Needed for native USB +#endif + + if (! rtc.begin()) { + Serial.println("Couldn't find RTC"); + Serial.flush(); + while (1) delay(10); + } + + if (rtc.lostPower()) { + Serial.println("RTC lost power, let's set the time!"); + // When time needs to be set on a new device, or after a power loss, the + // following line sets the RTC to the date & time this sketch was compiled + rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + // This line sets the RTC with an explicit date & time, for example to set + // January 21, 2014 at 3am you would call: + // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); + } + + // When time needs to be re-set on a previously configured device, the + // following line sets the RTC to the date & time this sketch was compiled + // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + // This line sets the RTC with an explicit date & time, for example to set + // January 21, 2014 at 3am you would call: + // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); +} + +void loop () { + DateTime now = rtc.now(); + + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(" ("); + Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); + Serial.print(") "); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); + + Serial.print(" since midnight 1/1/1970 = "); + Serial.print(now.unixtime()); + Serial.print("s = "); + Serial.print(now.unixtime() / 86400L); + Serial.println("d"); + + // calculate a date which is 7 days, 12 hours, 30 minutes, 6 seconds into the future + DateTime future (now + TimeSpan(7,12,30,6)); + + Serial.print(" now + 7d + 12h + 30m + 6s: "); + Serial.print(future.year(), DEC); + Serial.print('/'); + Serial.print(future.month(), DEC); + Serial.print('/'); + Serial.print(future.day(), DEC); + Serial.print(' '); + Serial.print(future.hour(), DEC); + Serial.print(':'); + Serial.print(future.minute(), DEC); + Serial.print(':'); + Serial.print(future.second(), DEC); + Serial.println(); + + Serial.print("Temperature: "); + Serial.print(rtc.getTemperature()); + Serial.println(" C"); + + Serial.println(); + delay(3000); +} From fa00641d59002953a2c09ea94793b801e043a3ea Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 18:27:16 +0200 Subject: [PATCH 05/50] Added enum RV3032C7AlarmMode --- src/RTClib.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/RTClib.h b/src/RTClib.h index c87cec3a..dad3edee 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -124,6 +124,18 @@ enum Pcf8563SqwPinMode { PCF8563_SquareWave32kHz = 0x80 /**< 32kHz square wave */ }; +/** RV3032C7 Alarm mode */ +enum RV3032C7AlarmMode { + RV3032C7_A_PerMinute = 0x07, /**< Alarm once per minute */ + RV3032C7_A_Minute = 0x06, /**< Alarm when minutes match */ + RV3032C7_A_Hour = 0x05, /**< Alarm when hours match */ + RV3032C7_A_MinuteHour = 0x04, /**< Alarm when minutes & hours match */ + RV3032C7_A_Date = 0x03, /**< Alarm when date (day of month) match */ + RV3032C7_A_MinuteDate = 0x02, /**< Alarm when minutes & date match */ + RV3032C7_A_HourDate = 0x01, /**< Alarm when hours & date match */ + RV3032C7_A_All = 0x00, /**< Alarm when minutes, hours & date match */ +}; + /**************************************************************************/ /*! @brief Simple general-purpose date/time class (no TZ / DST / leap From b6cede31e9c65b101a1dfbfd2f46e7095a915e7d Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 18:29:38 +0200 Subject: [PATCH 06/50] Moved RTC_RV-3032-C7 class after PFC8523 --- src/RTClib.h | 55 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/RTClib.h b/src/RTClib.h index dad3edee..e5b13c45 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -406,6 +406,34 @@ class RTC_DS3231 : RTC_I2C { static uint8_t dowToDS3231(uint8_t d) { return d == 0 ? 7 : d; } }; + +/**************************************************************************/ +/*! + @brief RTC based on the PCF8523 chip connected via I2C and the Wire library +*/ +/**************************************************************************/ +class RTC_PCF8523 : RTC_I2C { +public: + boolean begin(TwoWire *wireInstance = &Wire); + void adjust(const DateTime &dt); + boolean lostPower(void); + boolean initialized(void); + DateTime now(); + void start(void); + void stop(void); + uint8_t isrunning(); + Pcf8523SqwPinMode readSqwPinMode(); + void writeSqwPinMode(Pcf8523SqwPinMode mode); + void enableSecondTimer(void); + void disableSecondTimer(void); + void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods, + uint8_t lowPulseWidth); + void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods); + void disableCountdownTimer(void); + void deconfigureAllTimers(void); + void calibrate(Pcf8523OffsetMode mode, int8_t offset); +}; + /**************************************************************************/ /*! @brief RTC based on the RV-3032-C7 chip connected via I2C and the Wire library @@ -438,33 +466,6 @@ class RTC_RV3032C7 : RTC_I2C { static uint8_t dowToRV3032C7(uint8_t d) { return d == 0 ? 7 : d; } }; -/**************************************************************************/ -/*! - @brief RTC based on the PCF8523 chip connected via I2C and the Wire library -*/ -/**************************************************************************/ -class RTC_PCF8523 : RTC_I2C { -public: - boolean begin(TwoWire *wireInstance = &Wire); - void adjust(const DateTime &dt); - boolean lostPower(void); - boolean initialized(void); - DateTime now(); - void start(void); - void stop(void); - uint8_t isrunning(); - Pcf8523SqwPinMode readSqwPinMode(); - void writeSqwPinMode(Pcf8523SqwPinMode mode); - void enableSecondTimer(void); - void disableSecondTimer(void); - void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods, - uint8_t lowPulseWidth); - void enableCountdownTimer(PCF8523TimerClockFreq clkFreq, uint8_t numPeriods); - void disableCountdownTimer(void); - void deconfigureAllTimers(void); - void calibrate(Pcf8523OffsetMode mode, int8_t offset); -}; - /**************************************************************************/ /*! @brief RTC based on the PCF8563 chip connected via I2C and the Wire library From 13e2c7b2807eca37ff5feda441a913c43f20646a Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 18:33:07 +0200 Subject: [PATCH 07/50] Updated Alarm definition in RTC_RV3032C7 (only 1 alarm) --- src/RTClib.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/RTClib.h b/src/RTClib.h index e5b13c45..a9e454d0 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -447,11 +447,10 @@ class RTC_RV3032C7 : RTC_I2C { DateTime now(); Ds3231SqwPinMode readSqwPinMode(); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type void writeSqwPinMode(Ds3231SqwPinMode mode); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type - bool setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode); // TODO: replace Ds3231Alarm1Mode with proper RV3032C7 type - bool setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode); // TODO: replace Ds3231Alarm1Mode with proper RV3032C7 type - void disableAlarm(uint8_t alarm_num); - void clearAlarm(uint8_t alarm_num); - bool alarmFired(uint8_t alarm_num); + bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode); // TODO: replace Ds3231Alarm1Mode with proper RV3032C7 type + void disableAlarm(void); + void clearAlarm(void); + bool alarmFired(void); void enable32K(void); void disable32K(void); bool isEnabled32K(void); From 57e75332b0e8b503884201aaa220c319b7671fab Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 18:42:04 +0200 Subject: [PATCH 08/50] Added enum RV3032C7EventType --- src/RTClib.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/RTClib.h b/src/RTClib.h index a9e454d0..d0649c7f 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -136,6 +136,15 @@ enum RV3032C7AlarmMode { RV3032C7_A_All = 0x00, /**< Alarm when minutes, hours & date match */ }; +/** RV3032C7 Event type */ +enum RV3032C7EventType { + RV3032C7_EV_Poll = 0x00, /**< Polling, no interrupts */ + RV3032C7_EV_Pollclock = 0x02, /**< Activate clock on CLKOUT */ + RV3032C7_EV_Int = 0x01, /**< Trigger interrupt on INT pin */ + RV3032C7_EV_IntClock = 0x03, /**< Interrupt + clock */ +}; + + /**************************************************************************/ /*! @brief Simple general-purpose date/time class (no TZ / DST / leap From 3eee698b7df0d952ed0cfce95bd5cc4a56afe8a6 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 18:49:03 +0200 Subject: [PATCH 09/50] Added RV3032C7EventType param to RTC_RV3032C7::setAlarm --- src/RTClib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RTClib.h b/src/RTClib.h index d0649c7f..c29f0192 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -456,7 +456,7 @@ class RTC_RV3032C7 : RTC_I2C { DateTime now(); Ds3231SqwPinMode readSqwPinMode(); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type void writeSqwPinMode(Ds3231SqwPinMode mode); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type - bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode); // TODO: replace Ds3231Alarm1Mode with proper RV3032C7 type + bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type = RV3032C7_EV_Int); void disableAlarm(void); void clearAlarm(void); bool alarmFired(void); From 822d76764d462479d6a469dc8f5cc43642d52559 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 19:01:26 +0200 Subject: [PATCH 10/50] Fix RTC_RV3032C7.getTemperature() --- src/RTC_RV3032C7.cpp | 49 ++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 1b8e79d3..bfc1e8b7 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -167,7 +167,7 @@ float RTC_RV3032C7::getTemperature() { i2c_dev->write_then_read(buffer1, 1, buffer1, 2); i2c_dev->write_then_read(buffer2, 1, buffer2, 2); } while ( (buffer1[0] != buffer2[0]) || (buffer1[1] != buffer2[1]) ); - return float( int(buffer1[1]<<4) + (buffer1[0]>>4) ) * 0.0625f; + return float( int((int8_t) buffer1[1])*16 + (buffer1[0]>>4) ) * 0.0625f; } /**************************************************************************/ @@ -178,7 +178,8 @@ float RTC_RV3032C7::getTemperature() { @return False if control register is not set, otherwise true */ /**************************************************************************/ -bool RTC_RV3032C7::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) { +bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type = RV3032C7_EV_Int) { + /* uint8_t ctrl = read_register(RV3032C7_CONTROL1); if (!(ctrl & 0x04)) { return false; @@ -199,38 +200,7 @@ bool RTC_RV3032C7::setAlarm1(const DateTime &dt, Ds3231Alarm1Mode alarm_mode) { i2c_dev->write(buffer, 5); write_register(RV3032C7_CONTROL1, ctrl | 0x01); // AI1E - - return true; -} - -/**************************************************************************/ -/*! - @brief Set alarm 2 for RV3032C7 - @param dt DateTime object - @param alarm_mode Desired mode, see Ds3231Alarm2Mode enum - @return False if control register is not set, otherwise true */ -/**************************************************************************/ -bool RTC_RV3032C7::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) { - uint8_t ctrl = read_register(RV3032C7_CONTROL1); - if (!(ctrl & 0x04)) { - return false; - } - - uint8_t A2M2 = (alarm_mode & 0x01) << 7; // Minutes bit 7. - uint8_t A2M3 = (alarm_mode & 0x02) << 6; // Hour bit 7. - uint8_t A2M4 = (alarm_mode & 0x04) << 5; // Day/Date bit 7. - uint8_t DY_DT = (alarm_mode & 0x08) - << 3; // Day/Date bit 6. Date when 0, day of week when 1. - uint8_t day = (DY_DT) ? dowToRV3032C7(dt.dayOfTheWeek()) : dt.day(); - - uint8_t buffer[4] = {RV3032C7_ALARM2, uint8_t(bin2bcd(dt.minute()) | A2M2), - uint8_t(bin2bcd(dt.hour()) | A2M3), - uint8_t(bin2bcd(day) | A2M4 | DY_DT)}; - i2c_dev->write(buffer, 4); - - write_register(RV3032C7_CONTROL1, ctrl | 0x02); // AI2E - return true; } @@ -240,10 +210,12 @@ bool RTC_RV3032C7::setAlarm2(const DateTime &dt, Ds3231Alarm2Mode alarm_mode) { @param alarm_num Alarm number to disable */ /**************************************************************************/ -void RTC_RV3032C7::disableAlarm(uint8_t alarm_num) { +void RTC_RV3032C7::disableAlarm(void) { + /* uint8_t ctrl = read_register(RV3032C7_CONTROL1); ctrl &= ~(1 << (alarm_num - 1)); write_register(RV3032C7_CONTROL1, ctrl); + */ } /**************************************************************************/ @@ -252,10 +224,12 @@ void RTC_RV3032C7::disableAlarm(uint8_t alarm_num) { @param alarm_num Alarm number to clear */ /**************************************************************************/ -void RTC_RV3032C7::clearAlarm(uint8_t alarm_num) { +void RTC_RV3032C7::clearAlarm(void) { + /* uint8_t status = read_register(RV3032C7_STATUSREG); status &= ~(0x1 << (alarm_num - 1)); write_register(RV3032C7_STATUSREG, status); + */ } /**************************************************************************/ @@ -265,8 +239,11 @@ void RTC_RV3032C7::clearAlarm(uint8_t alarm_num) { @return True if alarm has been fired otherwise false */ /**************************************************************************/ -bool RTC_RV3032C7::alarmFired(uint8_t alarm_num) { +bool RTC_RV3032C7::alarmFired(void) { + /* return (read_register(RV3032C7_STATUSREG) >> (alarm_num - 1)) & 0x1; + */ + return false; } /**************************************************************************/ From c582d35ab388ec116c382eb86825b88b3be84128 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 21:07:29 +0200 Subject: [PATCH 11/50] Fixed spelling of RTC_RV3032C7_EV_PollClock --- src/RTClib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RTClib.h b/src/RTClib.h index c29f0192..52ed40e7 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -139,7 +139,7 @@ enum RV3032C7AlarmMode { /** RV3032C7 Event type */ enum RV3032C7EventType { RV3032C7_EV_Poll = 0x00, /**< Polling, no interrupts */ - RV3032C7_EV_Pollclock = 0x02, /**< Activate clock on CLKOUT */ + RV3032C7_EV_PollClock = 0x02, /**< Activate clock on CLKOUT */ RV3032C7_EV_Int = 0x01, /**< Trigger interrupt on INT pin */ RV3032C7_EV_IntClock = 0x03, /**< Interrupt + clock */ }; From a6e2f96bd8890c81e2bdfa850064c75fb8e32f3d Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 1 May 2022 23:31:14 +0200 Subject: [PATCH 12/50] Implemented RTC_RV3032C7 alarm handling in RTC_RV3032C7.cpp --- src/RTC_RV3032C7.cpp | 82 +++++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 40 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index bfc1e8b7..35aad9e3 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -10,12 +10,14 @@ #define RV3032C7_ADDRESS 0x51 ///< I2C address for RV3032C7 #define RV3032C7_100TH_SEC 0x00 ///< Time - 100th seconds #define RV3032C7_SECONDS 0x01 ///< time - seconds -#define RV3032C7_ALARM1 0x08 ///< Alarm 1 register -#define RV3032C7_ALARM2 0x0B ///< Alarm 2 register +#define RV3032C7_ALARM1 0x08 ///< Alarm 1 register - Minutes +#define RV3032C7_ALARM2 0x09 ///< Alarm 2 register - Hours +#define RV3032C7_ALARM3 0x0A ///< Alarm 2 register - Date #define RV3032C7_STATUSREG 0x0D ///< Status register #define RV3032C7_CONTROL1 0x10 ///< Control register #define RV3032C7_CONTROL2 0x11 ///< Control register #define RV3032C7_CONTROL3 0x12 ///< Control register +#define RV3032C7_INT_MASK 0x14 ///< Clock Interrupt Mask Register #define RV3032C7_TEMPERATUREREG \ 0x0E ///< Temperature register (bit 4-7 = lowest 4 bits. /// high byte is at 0x0F), 12-bit @@ -33,7 +35,16 @@ #define RV3032C7_VLF 0x01 ///< Voltage Low // Control register flags -#define RV3032C7_STOP 0x01 ///< Control2, STOP bit +#define RV3032C7_STOP 0x01 ///< Control2, STOP bit +#define RV3032C7_EIE 0x04 ///< Control2, External Event Interrupt Enable bit +#define RV3032C7_AIE 0x08 ///< Control2, Alarm Interrupt Enable bit +#define RV3032C7_TIE 0x10 ///< Control2, Periodic Countdown Timer Interrupt Enable bit +#define RV3032C7_UIE 0x20 ///< Control2, Periodic Time Update Interrupt Enable bit +#define RV3032C7_CLKIE 0x40 ///< Control2, Interrupt Controlled Clock Output Enable bit + +//Clock Interrupt Mask register flags (only those used in this file) +#define RV3032C7_CAIE 0x10 ///write(buffer, 5); - - write_register(RV3032C7_CONTROL1, ctrl | 0x01); // AI1E -*/ - return true; + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + write_register(RV3032C7_CONTROL2, ctrl2 & (~RV3032C7_AIE) ); // Avoid spurious interrupts + write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag + i2c_dev->write(buffer, 4); + if (event_type & 0x01) { // Enable Interrupt at alarm match + write_register(RV3032C7_CONTROL2, ctrl2 | RV3032C7_AIE ); // Set AIE + } // else it is already cleared + if (event_type & 0x02) { // Enable Clock Output at alarm match + write_register(RV3032C7_INT_MASK, intmask | RV3032C7_CAIE ); // Set CAIE + } else { // Disable Clock Output at alarm match + write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE) ); // Clear CAIE + } + return true; // No check needed for now, may be added in the future } /**************************************************************************/ @@ -211,11 +220,11 @@ bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventTy */ /**************************************************************************/ void RTC_RV3032C7::disableAlarm(void) { - /* - uint8_t ctrl = read_register(RV3032C7_CONTROL1); - ctrl &= ~(1 << (alarm_num - 1)); - write_register(RV3032C7_CONTROL1, ctrl); - */ + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + write_register(RV3032C7_CONTROL2, ctrl2 & (~RV3032C7_AIE) ); // Disable Alarm Interrupt + write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag + write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE) ); // Clear CAIE } /**************************************************************************/ @@ -225,11 +234,7 @@ void RTC_RV3032C7::disableAlarm(void) { */ /**************************************************************************/ void RTC_RV3032C7::clearAlarm(void) { - /* - uint8_t status = read_register(RV3032C7_STATUSREG); - status &= ~(0x1 << (alarm_num - 1)); - write_register(RV3032C7_STATUSREG, status); - */ + write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag } /**************************************************************************/ @@ -240,10 +245,7 @@ void RTC_RV3032C7::clearAlarm(void) { */ /**************************************************************************/ bool RTC_RV3032C7::alarmFired(void) { - /* - return (read_register(RV3032C7_STATUSREG) >> (alarm_num - 1)) & 0x1; - */ - return false; + return ((read_register(RV3032C7_STATUSREG) & RV3032C7_AF) != 0 ); } /**************************************************************************/ From e8f83de9ae1c55471f45dff921fec0ceedeb7fe1 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Mon, 2 May 2022 18:45:47 +0200 Subject: [PATCH 13/50] moved RTC_RV3032C7 class before RTC_Millis --- src/RTClib.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/RTClib.h b/src/RTClib.h index 52ed40e7..e2a1bb47 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -443,6 +443,24 @@ class RTC_PCF8523 : RTC_I2C { void calibrate(Pcf8523OffsetMode mode, int8_t offset); }; +/**************************************************************************/ +/*! + @brief RTC based on the PCF8563 chip connected via I2C and the Wire library +*/ +/**************************************************************************/ +class RTC_PCF8563 : RTC_I2C { +public: + boolean begin(TwoWire *wireInstance = &Wire); + boolean lostPower(void); + void adjust(const DateTime &dt); + DateTime now(); + void start(void); + void stop(void); + uint8_t isrunning(); + Pcf8563SqwPinMode readSqwPinMode(); + void writeSqwPinMode(Pcf8563SqwPinMode mode); +}; + /**************************************************************************/ /*! @brief RTC based on the RV-3032-C7 chip connected via I2C and the Wire library @@ -474,24 +492,6 @@ class RTC_RV3032C7 : RTC_I2C { static uint8_t dowToRV3032C7(uint8_t d) { return d == 0 ? 7 : d; } }; -/**************************************************************************/ -/*! - @brief RTC based on the PCF8563 chip connected via I2C and the Wire library -*/ -/**************************************************************************/ -class RTC_PCF8563 : RTC_I2C { -public: - boolean begin(TwoWire *wireInstance = &Wire); - boolean lostPower(void); - void adjust(const DateTime &dt); - DateTime now(); - void start(void); - void stop(void); - uint8_t isrunning(); - Pcf8563SqwPinMode readSqwPinMode(); - void writeSqwPinMode(Pcf8563SqwPinMode mode); -}; - /**************************************************************************/ /*! @brief RTC using the internal millis() clock, has to be initialized before From 61b59f42cb86e3725de7c6163423fe9c6f0b4004 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Mon, 2 May 2022 23:28:57 +0200 Subject: [PATCH 14/50] implemented enable/disable/query CLKOUT in RTC_RV3032C7 class --- src/RTC_RV3032C7.cpp | 42 +++++++++++++++++++++++++++--------------- src/RTClib.h | 6 +++--- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 35aad9e3..02853c63 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -24,6 +24,9 @@ ///< temperature value #define RV3032C7_TEMPERATURE8BIT 0x0F ///< 8-bit temperature +// RAM Addresses that mirror EEPROM registers +#define RV3032C7_PMU 0xC0 ///< Power Management Unit (PMU) + // Status register flags #define RV3032C7_THF 0x80 ///< Temp. High #define RV3032C7_TLF 0x40 ///< Temp. Low @@ -45,6 +48,8 @@ //Clock Interrupt Mask register flags (only those used in this file) #define RV3032C7_CAIE 0x10 ///> 0x03) & 0x01; +bool RTC_RV3032C7::isEnabledClkOut(void) { + return (read_register(RV3032C7_PMU) & RV3032C7_NCLKE) == 0 ? true : false; } diff --git a/src/RTClib.h b/src/RTClib.h index e2a1bb47..3ff4d0c9 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -478,9 +478,9 @@ class RTC_RV3032C7 : RTC_I2C { void disableAlarm(void); void clearAlarm(void); bool alarmFired(void); - void enable32K(void); - void disable32K(void); - bool isEnabled32K(void); + void enableClkOut(void); + void disableClkOut(void); + bool isEnabledClkOut(void); float getTemperature(); // in Celsius degree /*! @brief Convert the day of the week to a representation suitable for From 5ccf131b2831bff27eb56c0f0ab2aa92716ff815 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Tue, 3 May 2022 18:29:11 +0200 Subject: [PATCH 15/50] disabled EEPROM autorefresh in RV3032C7.begin() --- src/RTC_RV3032C7.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 02853c63..628fd483 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -2,7 +2,7 @@ // TODO: only what is needed in basic example implemented right now. //#define DEBUG_SERIAL Serial -#define DEBUG_SERIAL SerialUSB +//#define DEBUG_SERIAL SerialUSB //#ifdef DEBUG_SERIAL // #include //#endif @@ -37,7 +37,9 @@ #define RV3032C7_PORF 0x02 ///< Power On Reset #define RV3032C7_VLF 0x01 ///< Voltage Low -// Control register flags +// Control register flags (some) +#define RV3032C7_XBIT 0x20 ///< Control1, "X" bit (must be set to 1) +#define RV3032C7_EERD 0x04 ///< Control1, ROM Memory Refresh Disable bit. #define RV3032C7_STOP 0x01 ///< Control2, STOP bit #define RV3032C7_EIE 0x04 ///< Control2, External Event Interrupt Enable bit #define RV3032C7_AIE 0x08 ///< Control2, Alarm Interrupt Enable bit @@ -64,6 +66,13 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { i2c_dev = new Adafruit_I2CDevice(RV3032C7_ADDRESS, wireInstance); if (!i2c_dev->begin()) return false; + + // Next we turn off automatic refresh from EEPROM to behave like other chips in RTClib. + // Future updates may add more explit control over EEPROM refreshes + uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); + if ( (ctrl1 & RV3032C7_EERD) == 0 ) { + write_register(RV3032C7_CONTROL1, ctrl1 | RV3032C7_XBIT | RV3032C7_EERD); + } return true; } @@ -250,15 +259,14 @@ void RTC_RV3032C7::clearAlarm(void) { */ /**************************************************************************/ bool RTC_RV3032C7::alarmFired(void) { - return ((read_register(RV3032C7_STATUSREG) & RV3032C7_AF) != 0 ); + return (read_register(RV3032C7_STATUSREG) & RV3032C7_AF) != 0 ? true : false; } /**************************************************************************/ /*! @brief Enable normal clock output on CLKOUT pin (default 32.768 kHz) @details The CLKOUT output is enabled by default. It is a push-pull output - no pull-up resistor required. Limitation: at date change, - the setting stored in EEPROM is restored. + no pull-up resistor required. TODO: Add option to set specific frequency TODO: Add option to update EEPROM */ From 54adea4604af0ecc811436a8c997c77fa8256e6c Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Tue, 3 May 2022 21:45:49 +0200 Subject: [PATCH 16/50] Improved Doxigen comments for RV3032C7.cpp --- src/RTC_RV3032C7.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 628fd483..3648eb49 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -268,7 +268,6 @@ bool RTC_RV3032C7::alarmFired(void) { @details The CLKOUT output is enabled by default. It is a push-pull output no pull-up resistor required. TODO: Add option to set specific frequency - TODO: Add option to update EEPROM */ /**************************************************************************/ void RTC_RV3032C7::enableClkOut(void) { @@ -280,10 +279,11 @@ void RTC_RV3032C7::enableClkOut(void) { /**************************************************************************/ /*! @brief Disable normal clock output on CLKOUT pin - @details Limitation: at date change, the setting stored in EEPROM is - restored. - TODO: Add option to set specific frequency - TODO: Add option to update EEPROM + @details Disable normal clock output on CLKOUT pin. + When the clock is disabled, it can still be enabled via setAlarm + with event_type set to RV3032C7_EV_PollClock or RV3032C7_EV_IntClock: + when the Alarm triggers CLKOUT is enabled. + It will remain enabled until the alarm is cleared by clearAlarm(). */ /**************************************************************************/ void RTC_RV3032C7::disableClkOut(void) { From 83194c9fdd1fd8ece5f30859963117afc62f58d3 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Tue, 3 May 2022 23:05:39 +0200 Subject: [PATCH 17/50] Commented out debug statements in RV3032C7.cpp --- src/RTC_RV3032C7.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 3648eb49..d682f1ea 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -105,16 +105,16 @@ void RTC_RV3032C7::adjust(const DateTime &dt) { bin2bcd(dt.year() - 2000U)}; i2c_dev->write(buffer, 8); - // Clear the Power On Reset Flag (PORF) - uint8_t stat = read_register(RV3032C7_STATUSREG); // TODO: remove read_register, not needed after initial debug period - #ifdef DEBUG_SERIAL - DEBUG_SERIAL.print(F("RTCLib RV3032C7_STATUSREG=")); DEBUG_SERIAL.println(stat, BIN); - #endif + // Clear the Power On Reset Flag (PORF) + //uint8_t stat = read_register(RV3032C7_STATUSREG); // TODO: remove read_register, not needed after initial debug period + //#ifdef DEBUG_SERIAL + // DEBUG_SERIAL.print(F("RTCLib RV3032C7_STATUSREG=")); DEBUG_SERIAL.println(stat, BIN); + //#endif write_register(RV3032C7_STATUSREG, ~RV3032C7_PORF); - stat = read_register(RV3032C7_STATUSREG); - #ifdef DEBUG_SERIAL - DEBUG_SERIAL.print(F("STATUS after clearing PORF=")); DEBUG_SERIAL.println(stat, BIN); - #endif + //stat = read_register(RV3032C7_STATUSREG); + //#ifdef DEBUG_SERIAL + // DEBUG_SERIAL.print(F("STATUS after clearing PORF=")); DEBUG_SERIAL.println(stat, BIN); + //#endif /* // Check STOP bit, clear if set From 8ebf2a692f74a4b5872946f8d7c2b1c4fbdec60c Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 4 May 2022 18:49:15 +0200 Subject: [PATCH 18/50] removed unsupported RV3032C7.write/readSqwPinMode() --- src/RTC_RV3032C7.cpp | 29 ----------------------------- src/RTClib.h | 2 -- 2 files changed, 31 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index d682f1ea..fb8c68c8 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -149,35 +149,6 @@ DateTime RTC_RV3032C7::now() { bcd2bin(buffer[0])); // Note: RV3032C7 unused bits read = 0 } -/**************************************************************************/ -/*! - @brief Read the SQW pin mode - @return Pin mode, see Ds3231SqwPinMode enum -*/ -/**************************************************************************/ -Ds3231SqwPinMode RTC_RV3032C7::readSqwPinMode() { - int mode; - mode = read_register(RV3032C7_CONTROL1) & 0x1C; - if (mode & 0x04) - mode = DS3231_OFF; - return static_cast(mode); -} - -/**************************************************************************/ -/*! - @brief Set the SQW pin mode - @param mode Desired mode, see Ds3231SqwPinMode enum -*/ -/**************************************************************************/ -void RTC_RV3032C7::writeSqwPinMode(Ds3231SqwPinMode mode) { - uint8_t ctrl = read_register(RV3032C7_CONTROL1); - - ctrl &= ~0x04; // turn off INTCON - ctrl &= ~0x18; // set freq bits to 0 - - //write_register(RV3032C7_CONTROL1, ctrl | mode); -} - /**************************************************************************/ /*! @brief Get the current temperature from the RV3032C7's temperature sensor diff --git a/src/RTClib.h b/src/RTClib.h index 3ff4d0c9..e54209cc 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -472,8 +472,6 @@ class RTC_RV3032C7 : RTC_I2C { void adjust(const DateTime &dt); bool lostPower(void); DateTime now(); - Ds3231SqwPinMode readSqwPinMode(); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type - void writeSqwPinMode(Ds3231SqwPinMode mode); // TODO: replace Ds3231SqwPinMode with proper RV3032C7 type bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type = RV3032C7_EV_Int); void disableAlarm(void); void clearAlarm(void); From 7a5f9b92702511c4ac4b1f8deeb936eacbfd5abc Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 4 May 2022 18:53:59 +0200 Subject: [PATCH 19/50] comments and formatting cleaup --- src/RTC_RV3032C7.cpp | 36 +++++------------------------------- 1 file changed, 5 insertions(+), 31 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index fb8c68c8..398d33db 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -1,5 +1,6 @@ #include "RTClib.h" -// TODO: only what is needed in basic example implemented right now. +// TODO: only what is needed in basic examples is implemented right now. +// The RV3032C7 chip supports a lot more functionality... //#define DEBUG_SERIAL Serial //#define DEBUG_SERIAL SerialUSB @@ -20,9 +21,9 @@ #define RV3032C7_INT_MASK 0x14 ///< Clock Interrupt Mask Register #define RV3032C7_TEMPERATUREREG \ 0x0E ///< Temperature register (bit 4-7 = lowest 4 bits. - /// high byte is at 0x0F), 12-bit - ///< temperature value -#define RV3032C7_TEMPERATURE8BIT 0x0F ///< 8-bit temperature + ///< high byte is at RV3032C7_TEMPERATURE8BIT), 12-bit + ///< Temperature value +#define RV3032C7_TEMPERATURE8BIT 0x0F ///< 8-bit temperature value // RAM Addresses that mirror EEPROM registers #define RV3032C7_PMU 0xC0 ///< Power Management Unit (PMU) @@ -104,33 +105,6 @@ void RTC_RV3032C7::adjust(const DateTime &dt) { bin2bcd(dt.month()), bin2bcd(dt.year() - 2000U)}; i2c_dev->write(buffer, 8); - - // Clear the Power On Reset Flag (PORF) - //uint8_t stat = read_register(RV3032C7_STATUSREG); // TODO: remove read_register, not needed after initial debug period - //#ifdef DEBUG_SERIAL - // DEBUG_SERIAL.print(F("RTCLib RV3032C7_STATUSREG=")); DEBUG_SERIAL.println(stat, BIN); - //#endif - write_register(RV3032C7_STATUSREG, ~RV3032C7_PORF); - //stat = read_register(RV3032C7_STATUSREG); - //#ifdef DEBUG_SERIAL - // DEBUG_SERIAL.print(F("STATUS after clearing PORF=")); DEBUG_SERIAL.println(stat, BIN); - //#endif - - /* - // Check STOP bit, clear if set - uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); - - #ifdef DEBUG_SERIAL - DEBUG_SERIAL.print(F("RTCLib RV3032C7_CONTROL2=")); DEBUG_SERIAL.println(ctrl2, BIN); - #endif - if ( (ctrl2 & RV3032C7_STOP) >0) { // Oscillator is stopped - ctrl2 &= ~RV3032C7_STOP; // clear STOP bit - #ifdef DEBUG_SERIAL - DEBUG_SERIAL.print(F("RTCLib RV3032C7_CONTROL2=")); DEBUG_SERIAL.println(ctrl2, BIN); - #endif - //write_register(RV3032C7_CONTROL2, ctrl2); - } - */ } /**************************************************************************/ From b4840edb2ad60413df9c11a2e21e5066fbf7660f Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 4 May 2022 23:10:34 +0200 Subject: [PATCH 20/50] Fixed RV3032C7 Alarms (CLKF was not handled correctly) --- src/RTC_RV3032C7.cpp | 44 +++++++++++++++++++++++++++++++------------- src/RTClib.h | 1 - 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 398d33db..979012ff 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -54,6 +54,9 @@ //Clock Interrupt Mask register flags (only those used in this file) #define RV3032C7_NCLKE 0x40 ///< Not CLKOUT Enable Bit in Power Management Unit (PMU) +//Temperature register flags (some flags ended up here, albeit unrelated to temperature) +#define RV3032C7_CLKF 0x02 ///< Clock Output Interrupt Flag (CLKF) + /**************************************************************************/ /*! @brief Start I2C for the RV3032C7 and test succesful connection @@ -142,13 +145,14 @@ float RTC_RV3032C7::getTemperature() { /**************************************************************************/ /*! - @brief Set alarm 1 for RV3032C7 + @brief Set alarm 1 for RV3032C7 @param dt DateTime object @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum + @param event_type Desired event type, see RV3032C7EventTyp enum @return False if control register is not set, otherwise true */ /**************************************************************************/ -bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type) { +bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type) { uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Minutes bit 7. uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Hour bit 7. uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Day/Date bit 7. @@ -162,11 +166,16 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag i2c_dev->write(buffer, 4); if (event_type & 0x01) { // Enable Interrupt at alarm match - write_register(RV3032C7_CONTROL2, ctrl2 | RV3032C7_AIE ); // Set AIE + ctrl2 |= RV3032C7_AIE; + write_register(RV3032C7_CONTROL2, ctrl2 ); // Set AIE } // else it is already cleared - if (event_type & 0x02) { // Enable Clock Output at alarm match + if (event_type & 0x02) { // Enable Clock Output at alarm match and select alarm as interrupt source + ctrl2 |= RV3032C7_CLKIE; // Set CLKIE + write_register(RV3032C7_CONTROL2, ctrl2 ); // write ctrl2 to register write_register(RV3032C7_INT_MASK, intmask | RV3032C7_CAIE ); // Set CAIE - } else { // Disable Clock Output at alarm match + } else { // Disable Clock Output at alarm match to be sure + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + write_register(RV3032C7_CONTROL2, ctrl2 ); // write ctrl2 to register write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE) ); // Clear CAIE } return true; // No check needed for now, may be added in the future @@ -175,31 +184,37 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV /**************************************************************************/ /*! @brief Disable alarm - @param alarm_num Alarm number to disable -*/ + @details this function disables the alarm and then clears it (same as clearAlarm()) + / /**************************************************************************/ void RTC_RV3032C7::disableAlarm(void) { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - write_register(RV3032C7_CONTROL2, ctrl2 & (~RV3032C7_AIE) ); // Disable Alarm Interrupt - write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE) ); // Clear CAIE + // TODO: if we ever implement other functions that can set CLKIE then + // check intmask to see if we are the last user left before clearing the following flags + write_register(RV3032C7_CONTROL2, ctrl2 & (~(RV3032C7_AIE | ~RV3032C7_CLKIE)) ); // Disable Alarm Interrupts + clearAlarm(); } /**************************************************************************/ /*! @brief Clear status of alarm - @param alarm_num Alarm number to clear + @details this function clear the Alarm. This cause the INT PIN to go high (not active) and + (in case the alarm event was set to RV3032C7_EV_IntClock) the CLKOUT pin will */ /**************************************************************************/ void RTC_RV3032C7::clearAlarm(void) { write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag + // In addition we clear the CLKF flag since it can be set as well if RV3032C7_EV_IntClock + // TODO: if we ever implement other functions that can set CLKF then add option to clear only AF/CLKF + uint8_t treg = read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the temperature register + write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF) ); } /**************************************************************************/ /*! @brief Get status of alarm - @param alarm_num Alarm number to check status of @return True if alarm has been fired otherwise false */ /**************************************************************************/ @@ -212,7 +227,7 @@ bool RTC_RV3032C7::alarmFired(void) { @brief Enable normal clock output on CLKOUT pin (default 32.768 kHz) @details The CLKOUT output is enabled by default. It is a push-pull output no pull-up resistor required. - TODO: Add option to set specific frequency + TODO: Add option to set specific frequency */ /**************************************************************************/ void RTC_RV3032C7::enableClkOut(void) { @@ -226,9 +241,10 @@ void RTC_RV3032C7::enableClkOut(void) { @brief Disable normal clock output on CLKOUT pin @details Disable normal clock output on CLKOUT pin. When the clock is disabled, it can still be enabled via setAlarm - with event_type set to RV3032C7_EV_PollClock or RV3032C7_EV_IntClock: + with event_type set to RV3032C7_EV_IntClock: when the Alarm triggers CLKOUT is enabled. It will remain enabled until the alarm is cleared by clearAlarm(). + So this function may not actually stop the clock if there is an alarm active at the time it is called. */ /**************************************************************************/ void RTC_RV3032C7::disableClkOut(void) { @@ -240,6 +256,8 @@ void RTC_RV3032C7::disableClkOut(void) { /**************************************************************************/ /*! @brief Get status of clock output on CLKOUT pin + @details only checks if the CLKOUT pin is enabled all the time. + The pin could also be enabled by an alarm, this is not checked @return True if enabled otherwise false */ /**************************************************************************/ diff --git a/src/RTClib.h b/src/RTClib.h index e54209cc..0422cf71 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -139,7 +139,6 @@ enum RV3032C7AlarmMode { /** RV3032C7 Event type */ enum RV3032C7EventType { RV3032C7_EV_Poll = 0x00, /**< Polling, no interrupts */ - RV3032C7_EV_PollClock = 0x02, /**< Activate clock on CLKOUT */ RV3032C7_EV_Int = 0x01, /**< Trigger interrupt on INT pin */ RV3032C7_EV_IntClock = 0x03, /**< Interrupt + clock */ }; From 4924b1055973fa86dc148e66396ce204cc313c78 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 5 May 2022 22:19:24 +0200 Subject: [PATCH 21/50] Fixed RV3032C7 Power On flag, comments --- src/RTC_RV3032C7.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 979012ff..c23e9de3 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -59,7 +59,8 @@ /**************************************************************************/ /*! - @brief Start I2C for the RV3032C7 and test succesful connection + @brief Start I2C for the RV3032C7, test succesful connection + and make sure automatic refresh from EEPROM is off @param wireInstance pointer to the I2C bus @return True if Wire can find RV3032C7 or false otherwise. */ @@ -83,12 +84,14 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { /**************************************************************************/ /*! @brief Check the status register PORF flag to see if the RV3032C7 - stopped due to power loss + stopped due to power loss. After Power On, this function will + continue to return true until the time is set via adjust() @return True if the bit is set (oscillator stopped) or false if it is - running. TODO: add an option to check for loss of precision (VLF flag) + running. */ /**************************************************************************/ bool RTC_RV3032C7::lostPower(void) { + //TODO: add an option to check for loss of precision (VLF flag) return (read_register(RV3032C7_STATUSREG) & RV3032C7_PORF) != 0 ? true : false; } @@ -108,6 +111,7 @@ void RTC_RV3032C7::adjust(const DateTime &dt) { bin2bcd(dt.month()), bin2bcd(dt.year() - 2000U)}; i2c_dev->write(buffer, 8); + write_register(RV3032C7_STATUSREG, ~RV3032C7_PORF ); // clear PORF flag } /**************************************************************************/ @@ -145,7 +149,12 @@ float RTC_RV3032C7::getTemperature() { /**************************************************************************/ /*! - @brief Set alarm 1 for RV3032C7 + @brief Set alarm for RV3032C7. + - If event_type is RV3032C7_EV_Poll the alarm status can be polled with alarmFired() + - If event_type is RV3032C7_EV_Int, in addition the INT PIN goes low (usually this is used to generate an interrupt) + - If event_type is RV3032C7_EV_Int, in addition the clock output on CLKOUT pin becomes active while the INT pin is low + (even if it was turned off via disableClkOut) + @param dt DateTime object @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum @param event_type Desired event type, see RV3032C7EventTyp enum @@ -168,7 +177,7 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV if (event_type & 0x01) { // Enable Interrupt at alarm match ctrl2 |= RV3032C7_AIE; write_register(RV3032C7_CONTROL2, ctrl2 ); // Set AIE - } // else it is already cleared + } if (event_type & 0x02) { // Enable Clock Output at alarm match and select alarm as interrupt source ctrl2 |= RV3032C7_CLKIE; // Set CLKIE write_register(RV3032C7_CONTROL2, ctrl2 ); // write ctrl2 to register @@ -192,16 +201,16 @@ void RTC_RV3032C7::disableAlarm(void) { uint8_t intmask = read_register(RV3032C7_INT_MASK); write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE) ); // Clear CAIE // TODO: if we ever implement other functions that can set CLKIE then - // check intmask to see if we are the last user left before clearing the following flags + // check intmask to see if we are the last user left before clearing CLKIE write_register(RV3032C7_CONTROL2, ctrl2 & (~(RV3032C7_AIE | ~RV3032C7_CLKIE)) ); // Disable Alarm Interrupts clearAlarm(); } /**************************************************************************/ /*! - @brief Clear status of alarm - @details this function clear the Alarm. This cause the INT PIN to go high (not active) and - (in case the alarm event was set to RV3032C7_EV_IntClock) the CLKOUT pin will + @brief Clear status of alarm so that alarmFired() will return false + This also cause the INT PIN to go high (not active). If CLKOUT was activated by the alarm, it + will stop outputing the clock. */ /**************************************************************************/ void RTC_RV3032C7::clearAlarm(void) { @@ -225,7 +234,7 @@ bool RTC_RV3032C7::alarmFired(void) { /**************************************************************************/ /*! @brief Enable normal clock output on CLKOUT pin (default 32.768 kHz) - @details The CLKOUT output is enabled by default. It is a push-pull output + @details The CLKOUT output is enabled by default. It is a push-pull output, no pull-up resistor required. TODO: Add option to set specific frequency */ @@ -257,7 +266,7 @@ void RTC_RV3032C7::disableClkOut(void) { /*! @brief Get status of clock output on CLKOUT pin @details only checks if the CLKOUT pin is enabled all the time. - The pin could also be enabled by an alarm, this is not checked + The pin could also be enabled by an alarm, this is intentionally not checked @return True if enabled otherwise false */ /**************************************************************************/ From 06034243eec5f1c7da92216b770ab80f61ab2c13 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 5 May 2022 23:21:22 +0200 Subject: [PATCH 22/50] RV3032C7, minor change to comments --- src/RTC_RV3032C7.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index c23e9de3..411d77a5 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -194,7 +194,7 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV /*! @brief Disable alarm @details this function disables the alarm and then clears it (same as clearAlarm()) - / +*/ /**************************************************************************/ void RTC_RV3032C7::disableAlarm(void) { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); From df3b75f3a920a2d7a5de324dfb2cd71511bb7175 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 5 May 2022 23:21:51 +0200 Subject: [PATCH 23/50] Added example RV3032C7_alarm --- examples/RV3032C7_alarm/RV3032C7_alarm.ino | 91 ++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 examples/RV3032C7_alarm/RV3032C7_alarm.ino diff --git a/examples/RV3032C7_alarm/RV3032C7_alarm.ino b/examples/RV3032C7_alarm/RV3032C7_alarm.ino new file mode 100644 index 00000000..399ba317 --- /dev/null +++ b/examples/RV3032C7_alarm/RV3032C7_alarm.ino @@ -0,0 +1,91 @@ +/* Example implementation of an alarm using RV3032C7 + * + * VCC and GND of RTC should be connected to some power source + * SDA, SCL of RTC should be connected to SDA, SCL of arduino + * INT should be connected to RTC_INTERRUPT_PIN + * RTC_INTERRUPT_PIN needs to work with interrupts + */ + +#include +// #include + +RTC_RV3032C7 rtc; + +// the pin that is connected to INT +#define RTC_INTERRUPT_PIN 2 + +void setup() { + Serial.begin(9600); + + // initializing the rtc + if(!rtc.begin()) { + Serial.println("Couldn't find RTC!"); + Serial.flush(); + while (1) delay(10); + } + + if(rtc.lostPower()) { + // this will adjust to the date and time at compilation + rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + } + + //we don't need the CLKOUT Pin, so disable it + rtc.disableClkOut(); + + // Making it so, that the alarm will trigger an interrupt + pinMode(RTC_INTERRUPT_PIN, INPUT_PULLUP); // pullup is needed with RV3032C7 INT pin + attachInterrupt(digitalPinToInterrupt(RTC_INTERRUPT_PIN), onAlarm, FALLING); + + // set alarm flag to false (so alarm didn't happen so far) + // if not done, this easily leads to problems, as chip register aren't reset on reboot/recompile + rtc.clearAlarm(); + rtc.disableAlarm(); + + // schedule an alarm 60 seconds in the future + if(!rtc.setAlarm( + rtc.now() + TimeSpan(60), + RV3032C7_A_Minute // this mode triggers the alarm when the minutes match. See Doxygen for other options + )) { + Serial.println("Error, alarm wasn't set!"); + }else { + Serial.println("Alarm will happen in 60 seconds!"); + } +} + +void loop() { + // print current time + char date[10] = "hh:mm:ss"; + rtc.now().toString(date); + Serial.print(date); + // the value at INT-Pin (because of pullup 1 means no alarm) + Serial.print(" INT: "); + Serial.print(digitalRead(RTC_INTERRUPT_PIN)); + // whether a alarm happened happened + Serial.print(" Alarm: "); + Serial.println(rtc.alarmFired()); + // status register values (see https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-3028-C7_App-Manual.pdf page 22) + // Serial.print(" Control: 0d"); + // Serial.println(read_i2c_register(0x51, 0xd), BIN); + + // resetting INT and alarm 1 flag + // using setAlarm, the next alarm could now be configured + if(rtc.alarmFired()) { + rtc.clearAlarm(); + Serial.println(); Serial.println("Alarm cleared"); Serial.println(); + } + + delay(2000); +} + +void onAlarm() { + Serial.println("Alarm occured!"); +} + +/*static uint8_t read_i2c_register(uint8_t addr, uint8_t reg) { + Wire.beginTransmission(addr); + Wire.write((byte)reg); + Wire.endTransmission(); + + Wire.requestFrom(addr, (byte)1); + return Wire.read(); +}*/ From ac4c72274fe249505540c100fb2bd0e7cc2d857a Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 5 May 2022 23:30:24 +0200 Subject: [PATCH 24/50] Updatede keywords including RV3032C7 --- keywords.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/keywords.txt b/keywords.txt index d3082fef..1c846208 100644 --- a/keywords.txt +++ b/keywords.txt @@ -23,6 +23,8 @@ PCF8523TimerClockFreq KEYWORD1 PCF8523TimerIntPulse KEYWORD1 Pcf8523OffsetMode KEYWORD1 Pcf8563SqwPinMode KEYWORD1 +RV3032C7AlarmMode KEYWORD1 +RV3032C7EventType KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -56,6 +58,7 @@ timestamp KEYWORD2 toString KEYWORD2 readnvram KEYWORD2 writenvram KEYWORD2 +setAlarm KEYWORD2 setAlarm1 KEYWORD2 setAlarm2 KEYWORD2 disableAlarm KEYWORD2 @@ -73,6 +76,9 @@ calibrate KEYWORD2 enable32K KEYWORD2 disable32K KEYWORD2 isEnabled32K KEYWORD2 +enableClkOut KEYWORD2 +disableClkOut KEYWORD2 +isEnabledClkOut KEYWORD2 ####################################### # Constants (LITERAL1) From 01f88205a9ff45cc6f5a257ea2e8415210f16f06 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 5 May 2022 23:32:03 +0200 Subject: [PATCH 25/50] Mentioned RV3032C7 in library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index aac076d3..a1faa67d 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=2.0.2 author=Adafruit maintainer=Adafruit sentence=A fork of Jeelab's fantastic RTC library -paragraph=Works with DS1307, DS3231, PCF8523, PCF8563 on multiple architectures +paragraph=Works with DS1307, DS3231, PCF8523, PCF8563, RV3032C7 on multiple architectures category=Timing url=https://github.com/adafruit/RTClib architectures=* From 5cccbd01063e7d761d213e3523e00255eacc040c Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 8 May 2022 23:00:22 +0200 Subject: [PATCH 26/50] Improved doxygen --- src/RTC_RV3032C7.cpp | 29 ++++++++++++++++------------- src/RTClib.h | 4 ++-- src/src.ino | 0 3 files changed, 18 insertions(+), 15 deletions(-) create mode 100644 src/src.ino diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 411d77a5..4cccfa6c 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -60,7 +60,7 @@ /**************************************************************************/ /*! @brief Start I2C for the RV3032C7, test succesful connection - and make sure automatic refresh from EEPROM is off + and initialize the chip for use with RTClib @param wireInstance pointer to the I2C bus @return True if Wire can find RV3032C7 or false otherwise. */ @@ -78,6 +78,7 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { if ( (ctrl1 & RV3032C7_EERD) == 0 ) { write_register(RV3032C7_CONTROL1, ctrl1 | RV3032C7_XBIT | RV3032C7_EERD); } + // TODO: activate backup power source return true; } @@ -86,8 +87,8 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { @brief Check the status register PORF flag to see if the RV3032C7 stopped due to power loss. After Power On, this function will continue to return true until the time is set via adjust() - @return True if the bit is set (oscillator stopped) or false if it is - running. + @return True if the oscillator stopped or false if it is + running since last time the time was set by adjust(). */ /**************************************************************************/ bool RTC_RV3032C7::lostPower(void) { @@ -97,7 +98,8 @@ bool RTC_RV3032C7::lostPower(void) { /**************************************************************************/ /*! - @brief Set the date and make sure the Oscillator Stop bit is cleared + @brief Set the date and time. After this function returns, lostPower() will return false + until the next power loss @param dt DateTime object containing the date/time to set */ /**************************************************************************/ @@ -132,7 +134,8 @@ DateTime RTC_RV3032C7::now() { /**************************************************************************/ /*! - @brief Get the current temperature from the RV3032C7's temperature sensor + @brief Get the current temperature from the RV3032C7's temperature sensor. + The resoluton is 12 bits (corresponding to 0.0625 C) @return Current temperature (float) */ /**************************************************************************/ @@ -152,8 +155,8 @@ float RTC_RV3032C7::getTemperature() { @brief Set alarm for RV3032C7. - If event_type is RV3032C7_EV_Poll the alarm status can be polled with alarmFired() - If event_type is RV3032C7_EV_Int, in addition the INT PIN goes low (usually this is used to generate an interrupt) - - If event_type is RV3032C7_EV_Int, in addition the clock output on CLKOUT pin becomes active while the INT pin is low - (even if it was turned off via disableClkOut) + - If event_type is RV3032C7_EV_IntClock, in addition to the INT PIN going low, the clock is output on the CLKOUT pin while the INT pin is low + (even if it was turned off via disableClkOut()). The clock will be output until the INT pin is cleared by clearAlarm() or disabled with disableAlarm(). @param dt DateTime object @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum @@ -193,7 +196,7 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV /**************************************************************************/ /*! @brief Disable alarm - @details this function disables the alarm and then clears it (same as clearAlarm()) + @details this function disables the alarm and in addition clears it (same as clearAlarm()) */ /**************************************************************************/ void RTC_RV3032C7::disableAlarm(void) { @@ -234,7 +237,7 @@ bool RTC_RV3032C7::alarmFired(void) { /**************************************************************************/ /*! @brief Enable normal clock output on CLKOUT pin (default 32.768 kHz) - @details The CLKOUT output is enabled by default. It is a push-pull output, + @details The CLKOUT output is enabled by default at power on. It is a push-pull output, no pull-up resistor required. TODO: Add option to set specific frequency */ @@ -252,8 +255,7 @@ void RTC_RV3032C7::enableClkOut(void) { When the clock is disabled, it can still be enabled via setAlarm with event_type set to RV3032C7_EV_IntClock: when the Alarm triggers CLKOUT is enabled. - It will remain enabled until the alarm is cleared by clearAlarm(). - So this function may not actually stop the clock if there is an alarm active at the time it is called. + It will remain enabled until the alarm is cleared by clearAlarm() or disabled with disableAlarm(). */ /**************************************************************************/ void RTC_RV3032C7::disableClkOut(void) { @@ -265,8 +267,9 @@ void RTC_RV3032C7::disableClkOut(void) { /**************************************************************************/ /*! @brief Get status of clock output on CLKOUT pin - @details only checks if the CLKOUT pin is enabled all the time. - The pin could also be enabled by an alarm, this is intentionally not checked + @details only checks if the CLKOUT pin is enabled/disabled via enableClkOut() and disableClkOut(). + When the clock is disabled, it can still be enabled via setAlarm + with event_type set to RV3032C7_EV_IntClock, this is intentionally not checked by isEnabledClkOut(); @return True if enabled otherwise false */ /**************************************************************************/ diff --git a/src/RTClib.h b/src/RTClib.h index 0422cf71..79ce2825 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -138,9 +138,9 @@ enum RV3032C7AlarmMode { /** RV3032C7 Event type */ enum RV3032C7EventType { - RV3032C7_EV_Poll = 0x00, /**< Polling, no interrupts */ + RV3032C7_EV_Poll = 0x00, /**< Polling via i2c, no interrupts */ RV3032C7_EV_Int = 0x01, /**< Trigger interrupt on INT pin */ - RV3032C7_EV_IntClock = 0x03, /**< Interrupt + clock */ + RV3032C7_EV_IntClock = 0x03, /**< Interrupt on INT pin + clock output on CLKOUT pin */ }; diff --git a/src/src.ino b/src/src.ino new file mode 100644 index 00000000..e69de29b From a778d02d8e3ea59bddec55dcf5d1e90ae0cd25d1 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Mon, 9 May 2022 19:20:03 +0200 Subject: [PATCH 27/50] Fixed clang formatting RTC_RV3032C7.cpp --- src/RTC_RV3032C7.cpp | 225 ++++++++++++++++++++++++------------------- 1 file changed, 124 insertions(+), 101 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 4cccfa6c..04613e5e 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -1,66 +1,71 @@ #include "RTClib.h" -// TODO: only what is needed in basic examples is implemented right now. +// TODO: only what is needed in basic examples is implemented right now. // The RV3032C7 chip supports a lot more functionality... //#define DEBUG_SERIAL Serial //#define DEBUG_SERIAL SerialUSB //#ifdef DEBUG_SERIAL // #include -//#endif +//#endif -#define RV3032C7_ADDRESS 0x51 ///< I2C address for RV3032C7 -#define RV3032C7_100TH_SEC 0x00 ///< Time - 100th seconds -#define RV3032C7_SECONDS 0x01 ///< time - seconds -#define RV3032C7_ALARM1 0x08 ///< Alarm 1 register - Minutes -#define RV3032C7_ALARM2 0x09 ///< Alarm 2 register - Hours -#define RV3032C7_ALARM3 0x0A ///< Alarm 2 register - Date -#define RV3032C7_STATUSREG 0x0D ///< Status register -#define RV3032C7_CONTROL1 0x10 ///< Control register -#define RV3032C7_CONTROL2 0x11 ///< Control register -#define RV3032C7_CONTROL3 0x12 ///< Control register -#define RV3032C7_INT_MASK 0x14 ///< Clock Interrupt Mask Register -#define RV3032C7_TEMPERATUREREG \ - 0x0E ///< Temperature register (bit 4-7 = lowest 4 bits. +#define RV3032C7_ADDRESS 0x51 ///< I2C address for RV3032C7 +#define RV3032C7_100TH_SEC 0x00 ///< Time - 100th seconds +#define RV3032C7_SECONDS 0x01 ///< time - seconds +#define RV3032C7_ALARM1 0x08 ///< Alarm 1 register - Minutes +#define RV3032C7_ALARM2 0x09 ///< Alarm 2 register - Hours +#define RV3032C7_ALARM3 0x0A ///< Alarm 2 register - Date +#define RV3032C7_STATUSREG 0x0D ///< Status register +#define RV3032C7_CONTROL1 0x10 ///< Control register +#define RV3032C7_CONTROL2 0x11 ///< Control register +#define RV3032C7_CONTROL3 0x12 ///< Control register +#define RV3032C7_INT_MASK 0x14 ///< Clock Interrupt Mask Register +#define RV3032C7_TEMPERATUREREG \ + 0x0E ///< Temperature register (bit 4-7 = lowest 4 bits. ///< high byte is at RV3032C7_TEMPERATURE8BIT), 12-bit ///< Temperature value -#define RV3032C7_TEMPERATURE8BIT 0x0F ///< 8-bit temperature value +#define RV3032C7_TEMPERATURE8BIT 0x0F ///< 8-bit temperature value // RAM Addresses that mirror EEPROM registers -#define RV3032C7_PMU 0xC0 ///< Power Management Unit (PMU) +#define RV3032C7_PMU 0xC0 ///< Power Management Unit (PMU) // Status register flags -#define RV3032C7_THF 0x80 ///< Temp. High -#define RV3032C7_TLF 0x40 ///< Temp. Low -#define RV3032C7_UF 0x20 ///< Periodic Time Update -#define RV3032C7_TF 0x10 ///< Periodic Coundown Timer -#define RV3032C7_AF 0x08 ///< Alarm -#define RV3032C7_EVF 0x04 ///< External Event -#define RV3032C7_PORF 0x02 ///< Power On Reset -#define RV3032C7_VLF 0x01 ///< Voltage Low +#define RV3032C7_THF 0x80 ///< Temp. High +#define RV3032C7_TLF 0x40 ///< Temp. Low +#define RV3032C7_UF 0x20 ///< Periodic Time Update +#define RV3032C7_TF 0x10 ///< Periodic Coundown Timer +#define RV3032C7_AF 0x08 ///< Alarm +#define RV3032C7_EVF 0x04 ///< External Event +#define RV3032C7_PORF 0x02 ///< Power On Reset +#define RV3032C7_VLF 0x01 ///< Voltage Low // Control register flags (some) -#define RV3032C7_XBIT 0x20 ///< Control1, "X" bit (must be set to 1) -#define RV3032C7_EERD 0x04 ///< Control1, ROM Memory Refresh Disable bit. -#define RV3032C7_STOP 0x01 ///< Control2, STOP bit -#define RV3032C7_EIE 0x04 ///< Control2, External Event Interrupt Enable bit -#define RV3032C7_AIE 0x08 ///< Control2, Alarm Interrupt Enable bit -#define RV3032C7_TIE 0x10 ///< Control2, Periodic Countdown Timer Interrupt Enable bit -#define RV3032C7_UIE 0x20 ///< Control2, Periodic Time Update Interrupt Enable bit -#define RV3032C7_CLKIE 0x40 ///< Control2, Interrupt Controlled Clock Output Enable bit - -//Clock Interrupt Mask register flags (only those used in this file) -#define RV3032C7_CAIE 0x10 ///begin()) return false; - - // Next we turn off automatic refresh from EEPROM to behave like other chips in RTClib. - // Future updates may add more explit control over EEPROM refreshes + + // Next we turn off automatic refresh from EEPROM to behave like other chips + // in RTClib. Future updates may add more explit control over EEPROM refreshes uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); - if ( (ctrl1 & RV3032C7_EERD) == 0 ) { - write_register(RV3032C7_CONTROL1, ctrl1 | RV3032C7_XBIT | RV3032C7_EERD); + if ((ctrl1 & RV3032C7_EERD) == 0) { + write_register(RV3032C7_CONTROL1, ctrl1 | RV3032C7_XBIT | RV3032C7_EERD); } // TODO: activate backup power source return true; @@ -86,20 +91,21 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { /*! @brief Check the status register PORF flag to see if the RV3032C7 stopped due to power loss. After Power On, this function will - continue to return true until the time is set via adjust() + continue to return true until the time is set via adjust() @return True if the oscillator stopped or false if it is - running since last time the time was set by adjust(). + running since last time the time was set by adjust(). */ /**************************************************************************/ bool RTC_RV3032C7::lostPower(void) { - //TODO: add an option to check for loss of precision (VLF flag) - return (read_register(RV3032C7_STATUSREG) & RV3032C7_PORF) != 0 ? true : false; + // TODO: add an option to check for loss of precision (VLF flag) + return (read_register(RV3032C7_STATUSREG) & RV3032C7_PORF) != 0 ? true + : false; } /**************************************************************************/ /*! - @brief Set the date and time. After this function returns, lostPower() will return false - until the next power loss + @brief Set the date and time. After this function returns, lostPower() will + return false until the next power loss @param dt DateTime object containing the date/time to set */ /**************************************************************************/ @@ -113,7 +119,7 @@ void RTC_RV3032C7::adjust(const DateTime &dt) { bin2bcd(dt.month()), bin2bcd(dt.year() - 2000U)}; i2c_dev->write(buffer, 8); - write_register(RV3032C7_STATUSREG, ~RV3032C7_PORF ); // clear PORF flag + write_register(RV3032C7_STATUSREG, ~RV3032C7_PORF); // clear PORF flag } /**************************************************************************/ @@ -140,88 +146,103 @@ DateTime RTC_RV3032C7::now() { */ /**************************************************************************/ float RTC_RV3032C7::getTemperature() { - uint8_t buffer1[2]; + uint8_t buffer1[2]; uint8_t buffer2[2]; - do { // no blocking, so read twice as suggested in the app. manual - buffer1[0] = buffer2[0] = RV3032C7_TEMPERATUREREG; - i2c_dev->write_then_read(buffer1, 1, buffer1, 2); - i2c_dev->write_then_read(buffer2, 1, buffer2, 2); - } while ( (buffer1[0] != buffer2[0]) || (buffer1[1] != buffer2[1]) ); - return float( int((int8_t) buffer1[1])*16 + (buffer1[0]>>4) ) * 0.0625f; + do { // no blocking, so read twice as suggested in the app. manual + buffer1[0] = buffer2[0] = RV3032C7_TEMPERATUREREG; + i2c_dev->write_then_read(buffer1, 1, buffer1, 2); + i2c_dev->write_then_read(buffer2, 1, buffer2, 2); + } while ((buffer1[0] != buffer2[0]) || (buffer1[1] != buffer2[1])); + return float(int((int8_t)buffer1[1]) * 16 + (buffer1[0] >> 4)) * 0.0625f; } /**************************************************************************/ /*! - @brief Set alarm for RV3032C7. - - If event_type is RV3032C7_EV_Poll the alarm status can be polled with alarmFired() - - If event_type is RV3032C7_EV_Int, in addition the INT PIN goes low (usually this is used to generate an interrupt) - - If event_type is RV3032C7_EV_IntClock, in addition to the INT PIN going low, the clock is output on the CLKOUT pin while the INT pin is low - (even if it was turned off via disableClkOut()). The clock will be output until the INT pin is cleared by clearAlarm() or disabled with disableAlarm(). - + @brief Set alarm for RV3032C7. + - If event_type is RV3032C7_EV_Poll the alarm status can be polled with + alarmFired() + - If event_type is RV3032C7_EV_Int, in addition the INT PIN goes low + (usually this is used to generate an interrupt) + - If event_type is RV3032C7_EV_IntClock, in addition to the INT PIN + going low, the clock is output on the CLKOUT pin while the INT pin is low + (even if it was turned off via disableClkOut()). The clock will be + output until the INT pin is cleared by clearAlarm() or disabled with + disableAlarm(). + @param dt DateTime object @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum @param event_type Desired event type, see RV3032C7EventTyp enum @return False if control register is not set, otherwise true */ /**************************************************************************/ -bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type) { +bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, + RV3032C7EventType event_type) { uint8_t A1M1 = (alarm_mode & 0x01) << 7; // Minutes bit 7. uint8_t A1M2 = (alarm_mode & 0x02) << 6; // Hour bit 7. uint8_t A1M3 = (alarm_mode & 0x04) << 5; // Day/Date bit 7. uint8_t buffer[4] = {RV3032C7_ALARM1, uint8_t(bin2bcd(dt.minute()) | A1M1), uint8_t(bin2bcd(dt.hour()) | A1M2), - uint8_t(bin2bcd(dt.day()) | A1M3 )}; + uint8_t(bin2bcd(dt.day()) | A1M3)}; uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - write_register(RV3032C7_CONTROL2, ctrl2 & (~RV3032C7_AIE) ); // Avoid spurious interrupts - write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag + write_register(RV3032C7_CONTROL2, + ctrl2 & (~RV3032C7_AIE)); // Avoid spurious interrupts + write_register(RV3032C7_STATUSREG, ~RV3032C7_AF); // clear Alarm flag i2c_dev->write(buffer, 4); if (event_type & 0x01) { // Enable Interrupt at alarm match - ctrl2 |= RV3032C7_AIE; - write_register(RV3032C7_CONTROL2, ctrl2 ); // Set AIE + ctrl2 |= RV3032C7_AIE; + write_register(RV3032C7_CONTROL2, ctrl2); // Set AIE } - if (event_type & 0x02) { // Enable Clock Output at alarm match and select alarm as interrupt source - ctrl2 |= RV3032C7_CLKIE; // Set CLKIE - write_register(RV3032C7_CONTROL2, ctrl2 ); // write ctrl2 to register - write_register(RV3032C7_INT_MASK, intmask | RV3032C7_CAIE ); // Set CAIE + if (event_type & 0x02) { // Enable Clock Output at alarm match and select + // alarm as interrupt source + ctrl2 |= RV3032C7_CLKIE; // Set CLKIE + write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register + write_register(RV3032C7_INT_MASK, intmask | RV3032C7_CAIE); // Set CAIE } else { // Disable Clock Output at alarm match to be sure - ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE - write_register(RV3032C7_CONTROL2, ctrl2 ); // write ctrl2 to register - write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE) ); // Clear CAIE + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register + write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE)); // Clear CAIE } - return true; // No check needed for now, may be added in the future + return true; // No check needed for now, may be added in the future } /**************************************************************************/ /*! @brief Disable alarm - @details this function disables the alarm and in addition clears it (same as clearAlarm()) + @details this function disables the alarm and in addition clears it (same as + clearAlarm()) */ /**************************************************************************/ void RTC_RV3032C7::disableAlarm(void) { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE) ); // Clear CAIE - // TODO: if we ever implement other functions that can set CLKIE then + write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE)); // Clear CAIE + // TODO: if we ever implement other functions that can set CLKIE then // check intmask to see if we are the last user left before clearing CLKIE - write_register(RV3032C7_CONTROL2, ctrl2 & (~(RV3032C7_AIE | ~RV3032C7_CLKIE)) ); // Disable Alarm Interrupts + write_register( + RV3032C7_CONTROL2, + ctrl2 & (~(RV3032C7_AIE | ~RV3032C7_CLKIE))); // Disable Alarm Interrupts clearAlarm(); } /**************************************************************************/ /*! @brief Clear status of alarm so that alarmFired() will return false - This also cause the INT PIN to go high (not active). If CLKOUT was activated by the alarm, it - will stop outputing the clock. + This also cause the INT PIN to go high (not active). If CLKOUT was activated + by the alarm, it will stop outputing the clock. */ /**************************************************************************/ void RTC_RV3032C7::clearAlarm(void) { - write_register(RV3032C7_STATUSREG, ~RV3032C7_AF ); // clear Alarm flag - // In addition we clear the CLKF flag since it can be set as well if RV3032C7_EV_IntClock - // TODO: if we ever implement other functions that can set CLKF then add option to clear only AF/CLKF - uint8_t treg = read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the temperature register - write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF) ); + write_register(RV3032C7_STATUSREG, ~RV3032C7_AF); // clear Alarm flag + // In addition we clear the CLKF flag since it can be set as well if + // RV3032C7_EV_IntClock + // TODO: if we ever implement other functions that can set CLKF then add + // option to clear only AF/CLKF + uint8_t treg = + read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the + // temperature register + write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); } /**************************************************************************/ @@ -237,9 +258,9 @@ bool RTC_RV3032C7::alarmFired(void) { /**************************************************************************/ /*! @brief Enable normal clock output on CLKOUT pin (default 32.768 kHz) - @details The CLKOUT output is enabled by default at power on. It is a push-pull output, - no pull-up resistor required. - TODO: Add option to set specific frequency + @details The CLKOUT output is enabled by default at power on. It is a + push-pull output, no pull-up resistor required. + TODO: Add option to set specific frequency */ /**************************************************************************/ void RTC_RV3032C7::enableClkOut(void) { @@ -251,11 +272,12 @@ void RTC_RV3032C7::enableClkOut(void) { /**************************************************************************/ /*! @brief Disable normal clock output on CLKOUT pin - @details Disable normal clock output on CLKOUT pin. - When the clock is disabled, it can still be enabled via setAlarm + @details Disable normal clock output on CLKOUT pin. + When the clock is disabled, it can still be enabled via setAlarm with event_type set to RV3032C7_EV_IntClock: - when the Alarm triggers CLKOUT is enabled. - It will remain enabled until the alarm is cleared by clearAlarm() or disabled with disableAlarm(). + when the Alarm triggers CLKOUT is enabled. + It will remain enabled until the alarm is cleared by clearAlarm() or + disabled with disableAlarm(). */ /**************************************************************************/ void RTC_RV3032C7::disableClkOut(void) { @@ -267,12 +289,13 @@ void RTC_RV3032C7::disableClkOut(void) { /**************************************************************************/ /*! @brief Get status of clock output on CLKOUT pin - @details only checks if the CLKOUT pin is enabled/disabled via enableClkOut() and disableClkOut(). - When the clock is disabled, it can still be enabled via setAlarm - with event_type set to RV3032C7_EV_IntClock, this is intentionally not checked by isEnabledClkOut(); + @details only checks if the CLKOUT pin is enabled/disabled via + enableClkOut() and disableClkOut(). When the clock is disabled, it can still + be enabled via setAlarm with event_type set to RV3032C7_EV_IntClock, this is + intentionally not checked by isEnabledClkOut(); @return True if enabled otherwise false */ /**************************************************************************/ bool RTC_RV3032C7::isEnabledClkOut(void) { - return (read_register(RV3032C7_PMU) & RV3032C7_NCLKE) == 0 ? true : false; + return (read_register(RV3032C7_PMU) & RV3032C7_NCLKE) == 0 ? true : false; } From 55c0cba454e6513ae4c194ee6e7a4c8b3e9fa048 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Mon, 9 May 2022 19:24:44 +0200 Subject: [PATCH 28/50] Fixed clang formatting for RV3032C7 in RTClib.h --- src/RTClib.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/RTClib.h b/src/RTClib.h index 79ce2825..735ef162 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -138,12 +138,12 @@ enum RV3032C7AlarmMode { /** RV3032C7 Event type */ enum RV3032C7EventType { - RV3032C7_EV_Poll = 0x00, /**< Polling via i2c, no interrupts */ - RV3032C7_EV_Int = 0x01, /**< Trigger interrupt on INT pin */ - RV3032C7_EV_IntClock = 0x03, /**< Interrupt on INT pin + clock output on CLKOUT pin */ + RV3032C7_EV_Poll = 0x00, /**< Polling via i2c, no interrupts */ + RV3032C7_EV_Int = 0x01, /**< Trigger interrupt on INT pin */ + RV3032C7_EV_IntClock = + 0x03, /**< Interrupt on INT pin + clock output on CLKOUT pin */ }; - /**************************************************************************/ /*! @brief Simple general-purpose date/time class (no TZ / DST / leap @@ -414,7 +414,6 @@ class RTC_DS3231 : RTC_I2C { static uint8_t dowToDS3231(uint8_t d) { return d == 0 ? 7 : d; } }; - /**************************************************************************/ /*! @brief RTC based on the PCF8523 chip connected via I2C and the Wire library @@ -462,7 +461,8 @@ class RTC_PCF8563 : RTC_I2C { /**************************************************************************/ /*! - @brief RTC based on the RV-3032-C7 chip connected via I2C and the Wire library + @brief RTC based on the RV-3032-C7 chip connected via I2C and the Wire + library */ /**************************************************************************/ class RTC_RV3032C7 : RTC_I2C { @@ -471,7 +471,8 @@ class RTC_RV3032C7 : RTC_I2C { void adjust(const DateTime &dt); bool lostPower(void); DateTime now(); - bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type = RV3032C7_EV_Int); + bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, + RV3032C7EventType event_type = RV3032C7_EV_Int); void disableAlarm(void); void clearAlarm(void); bool alarmFired(void); From 9d55296de321dd9b05a492740abea00f322d34fb Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Mon, 9 May 2022 19:46:13 +0200 Subject: [PATCH 29/50] Doxygen fix in RTC_RV3032C7.cpp --- src/RTC_RV3032C7.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 04613e5e..ef0296a2 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -168,7 +168,6 @@ float RTC_RV3032C7::getTemperature() { (even if it was turned off via disableClkOut()). The clock will be output until the INT pin is cleared by clearAlarm() or disabled with disableAlarm(). - @param dt DateTime object @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum @param event_type Desired event type, see RV3032C7EventTyp enum From d153478146b687c6c0e9cb9ad251e97034de7d03 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Mon, 9 May 2022 20:57:37 +0200 Subject: [PATCH 30/50] Update RTC_RV3032C7.cpp Doxygen fix in RTC_RV3032C7.cpp --- src/RTC_RV3032C7.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index ef0296a2..308efb72 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -169,9 +169,9 @@ float RTC_RV3032C7::getTemperature() { output until the INT pin is cleared by clearAlarm() or disabled with disableAlarm(). @param dt DateTime object - @param alarm_mode Desired mode, see Ds3231Alarm1Mode enum + @param alarm_mode Desired mode, see RV3032C7AlarmMode enum @param event_type Desired event type, see RV3032C7EventTyp enum - @return False if control register is not set, otherwise true + @return False if alarm registers are not set, otherwise true */ /**************************************************************************/ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, From b1eb37aa6085abf6320f7e1450f84708b7b12c6c Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Tue, 10 May 2022 22:06:32 +0200 Subject: [PATCH 31/50] RTC_RV3032C7.begin() now activates switchover to backup power --- src/RTC_RV3032C7.cpp | 15 ++++++-- src/src.ino | 86 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 308efb72..d3b01f53 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -54,9 +54,12 @@ // Clock Interrupt Mask register flags (only those used in this file) #define RV3032C7_CAIE 0x10 ///< Clock output when Alarm Interrupt Enable bit -// Clock Interrupt Mask register flags (only those used in this file) +// Power Management Unit (PMU) register flags (only those used in this file) #define RV3032C7_NCLKE \ 0x40 ///< Not CLKOUT Enable Bit in Power Management Unit (PMU) +#define RV3032C7_BSM \ + 0x30 ///< Backup Switchover Mode \ + // Temperature register flags (some flags ended up here, albeit unrelated to // temperature) @@ -83,7 +86,15 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { if ((ctrl1 & RV3032C7_EERD) == 0) { write_register(RV3032C7_CONTROL1, ctrl1 | RV3032C7_XBIT | RV3032C7_EERD); } - // TODO: activate backup power source + // Finally, we check if Backup Switchover Mode (BSM) is 00b in the PMU + // register (default for a new chip). If it is, we set it to Level Switching + // Mode (LSM) as this most users of this library expect backup power from a + // primary battery to work + uint8_t pmu = read_register(RV3032C7_PMU); + if ((pmu & RV3032C7_BSM) == 0) { // Backup Switchover is disabled + write_register(RV3032C7_PMU, + pmu | 0x20); // Enable Level Switching Mode (LSM) + } return true; } diff --git a/src/src.ino b/src/src.ino index e69de29b..f65f72f3 100644 --- a/src/src.ino +++ b/src/src.ino @@ -0,0 +1,86 @@ +// Date and time functions using a RV3032C7 RTC connected via I2C and Wire lib +#include "RTClib.h" + +RTC_RV3032C7 rtc; + +char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; + +void setup () { + Serial.begin(57600); + +#ifndef ESP8266 + while (!Serial); // wait for serial port to connect. Needed for native USB +#endif + + if (! rtc.begin()) { + Serial.println("Couldn't find RTC"); + Serial.flush(); + while (1) delay(10); + } + + if (rtc.lostPower()) { + Serial.println("RTC lost power, let's set the time!"); + // When time needs to be set on a new device, or after a power loss, the + // following line sets the RTC to the date & time this sketch was compiled + rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + // This line sets the RTC with an explicit date & time, for example to set + // January 21, 2014 at 3am you would call: + // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); + } + + // When time needs to be re-set on a previously configured device, the + // following line sets the RTC to the date & time this sketch was compiled + // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + // This line sets the RTC with an explicit date & time, for example to set + // January 21, 2014 at 3am you would call: + // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); +} + +void loop () { + DateTime now = rtc.now(); + + Serial.print(now.year(), DEC); + Serial.print('/'); + Serial.print(now.month(), DEC); + Serial.print('/'); + Serial.print(now.day(), DEC); + Serial.print(" ("); + Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); + Serial.print(") "); + Serial.print(now.hour(), DEC); + Serial.print(':'); + Serial.print(now.minute(), DEC); + Serial.print(':'); + Serial.print(now.second(), DEC); + Serial.println(); + + Serial.print(" since midnight 1/1/1970 = "); + Serial.print(now.unixtime()); + Serial.print("s = "); + Serial.print(now.unixtime() / 86400L); + Serial.println("d"); + + // calculate a date which is 7 days, 12 hours, 30 minutes, 6 seconds into the future + DateTime future (now + TimeSpan(7,12,30,6)); + + Serial.print(" now + 7d + 12h + 30m + 6s: "); + Serial.print(future.year(), DEC); + Serial.print('/'); + Serial.print(future.month(), DEC); + Serial.print('/'); + Serial.print(future.day(), DEC); + Serial.print(' '); + Serial.print(future.hour(), DEC); + Serial.print(':'); + Serial.print(future.minute(), DEC); + Serial.print(':'); + Serial.print(future.second(), DEC); + Serial.println(); + + Serial.print("Temperature: "); + Serial.print(rtc.getTemperature()); + Serial.println(" C"); + + Serial.println(); + delay(3000); +} From 9ff8a39ff3455fa50e937bc8fe317a3e37205381 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Tue, 10 May 2022 22:25:41 +0200 Subject: [PATCH 32/50] Minor improvement to doxygen for RTC_RV3032-C7.lostPower() --- src/RTC_RV3032C7.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index d3b01f53..629a0e8e 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -104,7 +104,7 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { stopped due to power loss. After Power On, this function will continue to return true until the time is set via adjust() @return True if the oscillator stopped or false if it is - running since last time the time was set by adjust(). + running without interruption since last time the time was set by adjust(). */ /**************************************************************************/ bool RTC_RV3032C7::lostPower(void) { From 67148a769e12fe15737beb06989c79c09c20bb13 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Tue, 10 May 2022 22:53:11 +0200 Subject: [PATCH 33/50] Minor update to RV3032C7_alarm.ino example --- examples/RV3032C7_alarm/RV3032C7_alarm.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/RV3032C7_alarm/RV3032C7_alarm.ino b/examples/RV3032C7_alarm/RV3032C7_alarm.ino index 399ba317..6fbef3d6 100644 --- a/examples/RV3032C7_alarm/RV3032C7_alarm.ino +++ b/examples/RV3032C7_alarm/RV3032C7_alarm.ino @@ -48,7 +48,7 @@ void setup() { )) { Serial.println("Error, alarm wasn't set!"); }else { - Serial.println("Alarm will happen in 60 seconds!"); + Serial.println("Alarm will happen within 60 seconds!"); } } From 2e617b94ee1d56794c854ba100f640b2d1a316df Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 11 May 2022 23:40:01 +0200 Subject: [PATCH 34/50] fixed a bug in RTC_RV3032C7::disableAlarm() causing INT to remain active --- src/RTC_RV3032C7.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 629a0e8e..a2fcee7c 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -230,9 +230,8 @@ void RTC_RV3032C7::disableAlarm(void) { write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE)); // Clear CAIE // TODO: if we ever implement other functions that can set CLKIE then // check intmask to see if we are the last user left before clearing CLKIE - write_register( - RV3032C7_CONTROL2, - ctrl2 & (~(RV3032C7_AIE | ~RV3032C7_CLKIE))); // Disable Alarm Interrupts + ctrl2 &= ~(RV3032C7_AIE | RV3032C7_CLKIE); + write_register(RV3032C7_CONTROL2, ctrl2); // Disable Alarm Interrupts clearAlarm(); } From a01813a524c63558d0cf59b1ecae25172b1cd8fb Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 11 May 2022 23:42:50 +0200 Subject: [PATCH 35/50] Delete src.ino --- src/src.ino | 86 ----------------------------------------------------- 1 file changed, 86 deletions(-) delete mode 100644 src/src.ino diff --git a/src/src.ino b/src/src.ino deleted file mode 100644 index f65f72f3..00000000 --- a/src/src.ino +++ /dev/null @@ -1,86 +0,0 @@ -// Date and time functions using a RV3032C7 RTC connected via I2C and Wire lib -#include "RTClib.h" - -RTC_RV3032C7 rtc; - -char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; - -void setup () { - Serial.begin(57600); - -#ifndef ESP8266 - while (!Serial); // wait for serial port to connect. Needed for native USB -#endif - - if (! rtc.begin()) { - Serial.println("Couldn't find RTC"); - Serial.flush(); - while (1) delay(10); - } - - if (rtc.lostPower()) { - Serial.println("RTC lost power, let's set the time!"); - // When time needs to be set on a new device, or after a power loss, the - // following line sets the RTC to the date & time this sketch was compiled - rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); - // This line sets the RTC with an explicit date & time, for example to set - // January 21, 2014 at 3am you would call: - // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); - } - - // When time needs to be re-set on a previously configured device, the - // following line sets the RTC to the date & time this sketch was compiled - // rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); - // This line sets the RTC with an explicit date & time, for example to set - // January 21, 2014 at 3am you would call: - // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0)); -} - -void loop () { - DateTime now = rtc.now(); - - Serial.print(now.year(), DEC); - Serial.print('/'); - Serial.print(now.month(), DEC); - Serial.print('/'); - Serial.print(now.day(), DEC); - Serial.print(" ("); - Serial.print(daysOfTheWeek[now.dayOfTheWeek()]); - Serial.print(") "); - Serial.print(now.hour(), DEC); - Serial.print(':'); - Serial.print(now.minute(), DEC); - Serial.print(':'); - Serial.print(now.second(), DEC); - Serial.println(); - - Serial.print(" since midnight 1/1/1970 = "); - Serial.print(now.unixtime()); - Serial.print("s = "); - Serial.print(now.unixtime() / 86400L); - Serial.println("d"); - - // calculate a date which is 7 days, 12 hours, 30 minutes, 6 seconds into the future - DateTime future (now + TimeSpan(7,12,30,6)); - - Serial.print(" now + 7d + 12h + 30m + 6s: "); - Serial.print(future.year(), DEC); - Serial.print('/'); - Serial.print(future.month(), DEC); - Serial.print('/'); - Serial.print(future.day(), DEC); - Serial.print(' '); - Serial.print(future.hour(), DEC); - Serial.print(':'); - Serial.print(future.minute(), DEC); - Serial.print(':'); - Serial.print(future.second(), DEC); - Serial.println(); - - Serial.print("Temperature: "); - Serial.print(rtc.getTemperature()); - Serial.println(" C"); - - Serial.println(); - delay(3000); -} From cd6216abd0f0b3bf1324b03ebfdfd2891844ec62 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 12 May 2022 20:56:09 +0200 Subject: [PATCH 36/50] Retry autodetect in RV3032C7.begin() if chip unresponsive --- src/RTC_RV3032C7.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index a2fcee7c..29435b36 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -77,8 +77,17 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { if (i2c_dev) delete i2c_dev; i2c_dev = new Adafruit_I2CDevice(RV3032C7_ADDRESS, wireInstance); - if (!i2c_dev->begin()) - return false; + i2c_dev->begin(false); // no detection as the I2C i/f might become + // unresponsive when switched from VDD to Vbackup + short retries = 0; + boolean detected = false; + while ( + !i2c_dev->detected()) { // retry 3 times to make sure we reinitialize an + // unresponsive chip (see RV3032C7 app. manual) + if (++retries >= 3) { + return false; + } + } // Next we turn off automatic refresh from EEPROM to behave like other chips // in RTClib. Future updates may add more explit control over EEPROM refreshes From c203971dee2fef84164cdf6a49fc134c449a666e Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 12 May 2022 21:00:23 +0200 Subject: [PATCH 37/50] Minor update to comment text --- src/RTC_RV3032C7.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 29435b36..894d04d2 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -97,8 +97,7 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { } // Finally, we check if Backup Switchover Mode (BSM) is 00b in the PMU // register (default for a new chip). If it is, we set it to Level Switching - // Mode (LSM) as this most users of this library expect backup power from a - // primary battery to work + // Mode (LSM) as most users of this library expect backup power to work uint8_t pmu = read_register(RV3032C7_PMU); if ((pmu & RV3032C7_BSM) == 0) { // Backup Switchover is disabled write_register(RV3032C7_PMU, From 916c84927860d3aa74dc2a36b70e12f9eb907192 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Thu, 12 May 2022 21:02:00 +0200 Subject: [PATCH 38/50] Removed unused variable --- src/RTC_RV3032C7.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 894d04d2..8fa1772c 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -80,7 +80,6 @@ boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { i2c_dev->begin(false); // no detection as the I2C i/f might become // unresponsive when switched from VDD to Vbackup short retries = 0; - boolean detected = false; while ( !i2c_dev->detected()) { // retry 3 times to make sure we reinitialize an // unresponsive chip (see RV3032C7 app. manual) From 54acc500e48b1e94fe1be91c9af1c0c472fc8fdd Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sat, 14 May 2022 17:17:01 +0200 Subject: [PATCH 39/50] Update src/RTC_RV3032C7.cpp boolean -> bool Thanks to edgar-bonet Co-authored-by: Edgar Bonet --- src/RTC_RV3032C7.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 8fa1772c..28372317 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -73,7 +73,7 @@ @return True if Wire can find RV3032C7 or false otherwise. */ /**************************************************************************/ -boolean RTC_RV3032C7::begin(TwoWire *wireInstance) { +bool RTC_RV3032C7::begin(TwoWire *wireInstance) { if (i2c_dev) delete i2c_dev; i2c_dev = new Adafruit_I2CDevice(RV3032C7_ADDRESS, wireInstance); From d4ed07bf2f25980ca4510f4e16c0272dff15e62a Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sat, 24 Sep 2022 15:10:57 +0200 Subject: [PATCH 40/50] RV3032C7: Add support for fetching alarm values This commit introduces 3 new methods to get Alarm values (in line with DS3231): DateTime getAlarm(); RV3032C7AlarmMode getAlarmMode(); RV3032C7EventType getAlarmEventType(); In addition, disableAlarm() has been enhanced to properly disable alarm. RV3032C7InvalidDate has been defined to check if the alarm is disabled. Keywords added Updated the RV3032C7_alarm example to fetch alarm1. Also improved the formatting of the serial logging and added the possibility to disable the alarm. --- examples/RV3032C7_alarm/RV3032C7_alarm.ino | 42 ++++++++++++-- keywords.txt | 3 + src/RTC_RV3032C7.cpp | 65 ++++++++++++++++++++++ src/RTClib.h | 5 ++ 4 files changed, 111 insertions(+), 4 deletions(-) diff --git a/examples/RV3032C7_alarm/RV3032C7_alarm.ino b/examples/RV3032C7_alarm/RV3032C7_alarm.ino index 6fbef3d6..d348d52e 100644 --- a/examples/RV3032C7_alarm/RV3032C7_alarm.ino +++ b/examples/RV3032C7_alarm/RV3032C7_alarm.ino @@ -57,23 +57,57 @@ void loop() { char date[10] = "hh:mm:ss"; rtc.now().toString(date); Serial.print(date); + + // the stored alarm value + mode + event type + DateTime alarm = rtc.getAlarm(); + if (alarm==RV3032C7InvalidDate) { + Serial.print(" [Alarm: off]"); + } else { + RV3032C7AlarmMode alarmMode = rtc.getAlarmMode(); + RV3032C7EventType eventType = rtc.getAlarmEventType(); + char alarmDate[12] = "DD hh:mm:ss"; + alarm.toString(alarmDate); + Serial.print(" [Alarm: "); + Serial.print(alarmDate); + Serial.print(", Mode: "); + switch (alarmMode) { + case RV3032C7_A_PerMinute: Serial.print("PerMinute"); break; + case RV3032C7_A_Minute: Serial.print("Minute"); break; + case RV3032C7_A_Hour: Serial.print("Hour"); break; + case RV3032C7_A_MinuteHour: Serial.print("Minute&Hour"); break; + case RV3032C7_A_Date: Serial.print("Date"); break; + case RV3032C7_A_MinuteDate: Serial.print("Minute&Date"); break; + case RV3032C7_A_HourDate: Serial.print("Hour&Date"); break; + case RV3032C7_A_All: Serial.print("Minute&Hour&Date"); break; + } + Serial.print(", Event: "); + switch (eventType) { + case RV3032C7_EV_Poll: Serial.print("Poll"); break; + case RV3032C7_EV_Int: Serial.print("Int"); break; + case RV3032C7_EV_IntClock: Serial.print("Int+Clock"); break; + } + Serial.print("]"); + } + // the value at INT-Pin (because of pullup 1 means no alarm) Serial.print(" INT: "); Serial.print(digitalRead(RTC_INTERRUPT_PIN)); // whether a alarm happened happened Serial.print(" Alarm: "); Serial.println(rtc.alarmFired()); + // status register values (see https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-3028-C7_App-Manual.pdf page 22) // Serial.print(" Control: 0d"); // Serial.println(read_i2c_register(0x51, 0xd), BIN); // resetting INT and alarm 1 flag // using setAlarm, the next alarm could now be configured - if(rtc.alarmFired()) { - rtc.clearAlarm(); - Serial.println(); Serial.println("Alarm cleared"); Serial.println(); + if (rtc.alarmFired()) { + rtc.clearAlarm(); Serial.println(" - Alarm cleared"); + //rtc.disableAlarm(); Serial.println(" - Alarm disabled"); // uncomment to disable further alarms } - + Serial.println(); + delay(2000); } diff --git a/keywords.txt b/keywords.txt index 1c846208..5456f737 100644 --- a/keywords.txt +++ b/keywords.txt @@ -59,6 +59,9 @@ toString KEYWORD2 readnvram KEYWORD2 writenvram KEYWORD2 setAlarm KEYWORD2 +getAlarm KEYWORD2 +getAlarmMode KEYWORD2 +getAlarmEventType KEYWORD2 setAlarm1 KEYWORD2 setAlarm2 KEYWORD2 disableAlarm KEYWORD2 diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 28372317..7163852b 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -224,6 +224,66 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, return true; // No check needed for now, may be added in the future } +/**************************************************************************/ +/*! + @brief Get the date/time value of the Alarm + @return DateTime object with the Alarm data set in the + day, hour, minutes, and seconds fields + + At power on and after disableAlarm() returns RV3032C7InvalidDate +*/ +/**************************************************************************/ +DateTime RTC_RV3032C7::getAlarm() { + uint8_t buffer[3] = {RV3032C7_ALARM1, 0, 0}; + i2c_dev->write_then_read(buffer, 1, buffer, 3); + + uint8_t minutes = bcd2bin(buffer[0] & 0x7F); + uint8_t hour = bcd2bin(buffer[1] & 0x3F); // Only 24 hour format supported by RV3032C7 (same as this library) + uint8_t day = bcd2bin(buffer[2] & 0x3F); + + // Chosen in order to match the year and month returned by RTC_DS3231::getAlarm(); + return DateTime(2000, 5, day, hour, minutes); +} + +/**************************************************************************/ +/*! + @brief Get the mode for the Alarm + @return RV3032C7AlarmMode enum value for the current Alarm mode +*/ +/**************************************************************************/ +RV3032C7AlarmMode RTC_RV3032C7::getAlarmMode() { + uint8_t buffer[3] = {RV3032C7_ALARM1, 0, 0}; + i2c_dev->write_then_read(buffer, 1, buffer, 3); + uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A1M1 - Minutes bit + | (buffer[1] & 0x80) >> 6 // A1M2 - Hour bit + | (buffer[2] & 0x80) >> 5; // A1M3 - Date bit + return (RV3032C7AlarmMode)alarm_mode; // No need to check because all possible values are valid +} + +/**************************************************************************/ +/*! + @brief Get the event type for the Alarm + @return RV3032C7EventType enum value for the current Alarm event type +*/ +/**************************************************************************/ +RV3032C7EventType RTC_RV3032C7::getAlarmEventType() { + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + uint8_t event_type= (ctrl2 & RV3032C7_AIE) >> 3; + if ( ((intmask & RV3032C7_CAIE) != 0) && ((ctrl2 & RV3032C7_AIE) != 0) ) { + event_type |= 0x02; + } + switch(event_type) { + case RV3032C7_EV_Poll: + case RV3032C7_EV_Int: + case RV3032C7_EV_IntClock: + return (RV3032C7EventType) event_type; + default: + return RV3032C7_EV_Poll; + } +} + + /**************************************************************************/ /*! @brief Disable alarm @@ -239,6 +299,11 @@ void RTC_RV3032C7::disableAlarm(void) { // check intmask to see if we are the last user left before clearing CLKIE ctrl2 &= ~(RV3032C7_AIE | RV3032C7_CLKIE); write_register(RV3032C7_CONTROL2, ctrl2); // Disable Alarm Interrupts + + // reset to power on default, preventing any further match + uint8_t buffer[4] = {RV3032C7_ALARM1, 0x00, 0x00, 0x00}; + i2c_dev->write(buffer, 4); + clearAlarm(); } diff --git a/src/RTClib.h b/src/RTClib.h index 7f1946a7..23116d8a 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -144,6 +144,8 @@ enum RV3032C7EventType { 0x03, /**< Interrupt on INT pin + clock output on CLKOUT pin */ }; +#define RV3032C7InvalidDate DateTime(2000, 5, 0x00, 0x00, 0x00) + /**************************************************************************/ /*! @brief Simple general-purpose date/time class (no TZ / DST / leap @@ -473,6 +475,9 @@ class RTC_RV3032C7 : RTC_I2C { DateTime now(); bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type = RV3032C7_EV_Int); + DateTime getAlarm(); + RV3032C7AlarmMode getAlarmMode(); + RV3032C7EventType getAlarmEventType(); void disableAlarm(void); void clearAlarm(void); bool alarmFired(void); From 1d66ee309aa36bde425ab7191bd3b775ca7f73e5 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 28 Sep 2022 15:10:23 +0200 Subject: [PATCH 41/50] RV3032C7: Initial implementation of Periodic Countdown Timer --- src/RTC_RV3032C7.cpp | 143 +++++++++++++++++++++++++++++++++++++++---- src/RTClib.h | 18 ++++++ 2 files changed, 149 insertions(+), 12 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 7163852b..30b0f65e 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -14,6 +14,9 @@ #define RV3032C7_ALARM1 0x08 ///< Alarm 1 register - Minutes #define RV3032C7_ALARM2 0x09 ///< Alarm 2 register - Hours #define RV3032C7_ALARM3 0x0A ///< Alarm 2 register - Date +#define RV3032C7_TIMER0 0x0B ///< Timer Value 0 reg. lower 8 bits +#define RV3032C7_TIMER1 0x0C ///< Timer Value 1 reg. upper 4 bits + #define RV3032C7_STATUSREG 0x0D ///< Status register #define RV3032C7_CONTROL1 0x10 ///< Control register #define RV3032C7_CONTROL2 0x11 ///< Control register @@ -38,8 +41,10 @@ #define RV3032C7_PORF 0x02 ///< Power On Reset #define RV3032C7_VLF 0x01 ///< Voltage Low -// Control register flags (some) +// Control register flags/fields (some) #define RV3032C7_XBIT 0x20 ///< Control1, "X" bit (must be set to 1) +#define RV3032C7_TE 0x08 ///< Control1, Periodic Countdown Timer Enable bit +#define RV3032C7_TD 0x03 ///< Control1, Timer Clock Frequency selection #define RV3032C7_EERD 0x04 ///< Control1, ROM Memory Refresh Disable bit. #define RV3032C7_STOP 0x01 ///< Control2, STOP bit #define RV3032C7_EIE 0x04 ///< Control2, External Event Interrupt Enable bit @@ -53,6 +58,7 @@ // Clock Interrupt Mask register flags (only those used in this file) #define RV3032C7_CAIE 0x10 ///< Clock output when Alarm Interrupt Enable bit +#define RV3032C7_CTIE 0x08 ///< Clock output when Periodic Countdown Timer Interrupt Enable bit // Power Management Unit (PMU) register flags (only those used in this file) #define RV3032C7_NCLKE \ @@ -217,9 +223,12 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register write_register(RV3032C7_INT_MASK, intmask | RV3032C7_CAIE); // Set CAIE } else { // Disable Clock Output at alarm match to be sure - ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE - write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register - write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE)); // Clear CAIE + intmask &= ~RV3032C7_CAIE; + write_register(RV3032C7_INT_MASK, intmask); // Clear CAIE + if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register + } } return true; // No check needed for now, may be added in the future } @@ -270,7 +279,7 @@ RV3032C7EventType RTC_RV3032C7::getAlarmEventType() { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); uint8_t event_type= (ctrl2 & RV3032C7_AIE) >> 3; - if ( ((intmask & RV3032C7_CAIE) != 0) && ((ctrl2 & RV3032C7_AIE) != 0) ) { + if ( ((intmask & RV3032C7_CAIE) != 0) && ((ctrl2 & RV3032C7_CLKIE) != 0) ) { event_type |= 0x02; } switch(event_type) { @@ -283,7 +292,6 @@ RV3032C7EventType RTC_RV3032C7::getAlarmEventType() { } } - /**************************************************************************/ /*! @brief Disable alarm @@ -294,16 +302,18 @@ RV3032C7EventType RTC_RV3032C7::getAlarmEventType() { void RTC_RV3032C7::disableAlarm(void) { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CAIE)); // Clear CAIE - // TODO: if we ever implement other functions that can set CLKIE then - // check intmask to see if we are the last user left before clearing CLKIE - ctrl2 &= ~(RV3032C7_AIE | RV3032C7_CLKIE); - write_register(RV3032C7_CONTROL2, ctrl2); // Disable Alarm Interrupts - // reset to power on default, preventing any further match uint8_t buffer[4] = {RV3032C7_ALARM1, 0x00, 0x00, 0x00}; i2c_dev->write(buffer, 4); + intmask &= ~RV3032C7_CAIE; // Clear CAIE + write_register(RV3032C7_INT_MASK, intmask); // write register + if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + } + ctrl2 &= ~RV3032C7_AIE; // clear Alarm Interrupt Enable (AIE) + write_register(RV3032C7_CONTROL2, ctrl2); // write register + clearAlarm(); } @@ -336,6 +346,115 @@ bool RTC_RV3032C7::alarmFired(void) { return (read_register(RV3032C7_STATUSREG) & RV3032C7_AF) != 0 ? true : false; } +/**************************************************************************/ +/*! + @brief Enable Periodic Countdown Timer on the RV3032C7. + - If event_type is RV3032C7_EV_Poll the alarm status can be polled with + CountdownTimerFired() + - If event_type is RV3032C7_EV_Int, in addition the INT PIN goes low + (usually this is used to generate an interrupt) + - If event_type is RV3032C7_EV_IntClock, in addition to the INT PIN + going low, the clock is output on the CLKOUT pin while the INT pin is low + (even if it was turned off via disableClkOut()). The clock will be + output until the INT pin is cleared by clearCountdownTimer() or disabled with + disableCountdownTimer(). + @param clkFreq One of the RV3032C7's Periodic Countdown Timer Clock Frequencies. + See the #RV3032C7TimerClockFreq enum for options and associated time ranges. + @param numPeriods The number of clkFreq periods (1-4095) to count down. + @param event_type Desired event type, see #RV3032C7EventTyp enum +*/ +/**************************************************************************/ +void RTC_RV3032C7::enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t numPeriods, RV3032C7EventType event_type) { + uint8_t buffer[3] = { RV3032C7_TIMER0, lowByte(numPeriods), highByte(numPeriods) }; + + uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + + ctrl1 &= ~RV3032C7_TE; // clear TE bit + write_register(RV3032C7_CONTROL2, ctrl1); // Disable Countdown Timer + ctrl2 &= ~RV3032C7_TIE; // clear TIE bit + write_register(RV3032C7_CONTROL2, ctrl2); // Disable Timer Interrupt + write_register(RV3032C7_STATUSREG, ~RV3032C7_TF); // clear Timer flag + + ctrl1 = (ctrl1 & (~RV3032C7_TD)) | (clkFreq & RV3032C7_TD); + write_register(RV3032C7_CONTROL2, ctrl1); // Set TD field + i2c_dev->write(buffer, 3); // Write Timer Value (12 bits) + + if (event_type & 0x01) { // Enable Interrupt at alarm match + ctrl2 |= RV3032C7_TIE; //set Timer Interrupt Enable (TIE) + write_register(RV3032C7_CONTROL2, ctrl2); //enable Timer interrupt + } + if (event_type & 0x02) { // Enable Clock Output at timer interrupt + ctrl2 |= RV3032C7_CLKIE; // Set CLKIE + write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register + write_register(RV3032C7_INT_MASK, intmask | RV3032C7_CTIE); // Set CTIE + } else { // Disable Clock Output at alarm match to be sure + intmask &= ~RV3032C7_CTIE; + write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CTIE)); // Clear CTIE + if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register + } + } + write_register(RV3032C7_CONTROL2, ctrl1 | RV3032C7_TE); // Enable Countdown Timer +} + +/**************************************************************************/ +/*! + @brief Get the value of the Periodic Countdown Timer + @return the number of clkFreq periods to count down (uint16_t). Range: 0-4095 + + The preset value of the countdown timer is returned and not the actual value (which is not possible to read). + At power on returns 0, otherwise it will return the last value set (valid values 1-4095) +*/ +/**************************************************************************/ +uint16_t RTC_RV3032C7::getCountdownTimer() { + uint8_t buffer[3] = { RV3032C7_TIMER0, 0}; + i2c_dev->write_then_read(buffer, 1, buffer, 2); + uint16_t numPeriods = ((uint16_t)buffer[1])<<8 | buffer[0]; + return numPeriods; +} + +/**************************************************************************/ +/*! + @brief Get the mode for the Periodic Countdown Timer + @return RV3032C7's Periodic Countdown Timer Clock Frequency. See the #RV3032C7TimerClockFreq enum for options and associated time ranges. +*/ +/**************************************************************************/ +RV3032C7TimerClockFreq RTC_RV3032C7::getCountdownTimerClock() { + uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); + return (RV3032C7TimerClockFreq) (ctrl1 & RV3032C7_TD); + +} + +/**************************************************************************/ +/*! + @brief Get the event type for the Periodic Countdown Timer + @return RV3032C7EventType enum value for the current Periodic Countdown Timer event type +*/ +/**************************************************************************/ +RV3032C7EventType getCountdownTimerEventType() { + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + uint8_t event_type= (ctrl2 & RV3032C7_TIE) >> 4; + if ( ((intmask & RV3032C7_CTIE) != 0) && ((ctrl2 & RV3032C7_CLKIE) != 0) ) { + event_type |= 0x02; + } + switch(event_type) { + case RV3032C7_EV_Poll: + case RV3032C7_EV_Int: + case RV3032C7_EV_IntClock: + return (RV3032C7EventType) event_type; + default: + return RV3032C7_EV_Poll; + } +} + +void RTC_RV3032C7::disableCountdownTimer(void); +void RTC_RV3032C7::clearCountdownTimer(void); +bool RTC_RV3032C7::CountdownTimerFired(void); + /**************************************************************************/ /*! @brief Enable normal clock output on CLKOUT pin (default 32.768 kHz) diff --git a/src/RTClib.h b/src/RTClib.h index b41ac2bc..4e94d4cb 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -136,6 +136,14 @@ enum RV3032C7AlarmMode { RV3032C7_A_All = 0x00, /**< Alarm when minutes, hours & date match */ }; +/** RV3032C7 Countdown Timer Clock frequency*/ +enum RV3032C7TimerClockFreq { + RV3032C7_Frequency4096Hz = 0x00, /**< 4096 Hz */ + RV3032C7_Frequency64Hz = 0x01, /**< 64 Hz */ + RV3032C7_FrequencySeconds = 0x02, /**< T=1s or 1 Hz */ + RV3032C7_CFrequencyMinutes = 0x03, /**< T=60s or 1/60 Hz */ +}; + /** RV3032C7 Event type */ enum RV3032C7EventType { RV3032C7_EV_Poll = 0x00, /**< Polling via i2c, no interrupts */ @@ -477,6 +485,7 @@ class RTC_RV3032C7 : RTC_I2C { void adjust(const DateTime &dt); bool lostPower(void); DateTime now(); + bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type = RV3032C7_EV_Int); DateTime getAlarm(); @@ -485,6 +494,15 @@ class RTC_RV3032C7 : RTC_I2C { void disableAlarm(void); void clearAlarm(void); bool alarmFired(void); + + void enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t numPeriods, RV3032C7EventType event_type = RV3032C7_EV_Int); + uint16_t getCountdownTimer(); + RV3032C7TimerClockFreq getCountdownTimerClock(); + RV3032C7EventType getCountdownTimerEventType(); + void disableCountdownTimer(void); + void clearCountdownTimer(void); + bool CountdownTimerFired(void); + void enableClkOut(void); void disableClkOut(void); bool isEnabledClkOut(void); From b80ef44911bb23d2de34dc22d954eea058700421 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Wed, 28 Sep 2022 21:58:54 +0200 Subject: [PATCH 42/50] RTC_RV3032C7: complete support for Periodic Countdown Timer --- src/RTC_RV3032C7.cpp | 76 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 30b0f65e..bb81aac9 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -64,8 +64,7 @@ #define RV3032C7_NCLKE \ 0x40 ///< Not CLKOUT Enable Bit in Power Management Unit (PMU) #define RV3032C7_BSM \ - 0x30 ///< Backup Switchover Mode \ - + 0x30 ///< Backup Switchover Mode // Temperature register flags (some flags ended up here, albeit unrelated to // temperature) @@ -328,12 +327,11 @@ void RTC_RV3032C7::clearAlarm(void) { write_register(RV3032C7_STATUSREG, ~RV3032C7_AF); // clear Alarm flag // In addition we clear the CLKF flag since it can be set as well if // RV3032C7_EV_IntClock - // TODO: if we ever implement other functions that can set CLKF then add - // option to clear only AF/CLKF - uint8_t treg = - read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the - // temperature register - write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + if (intmask & RV3032C7_CAIE) { + uint8_t treg = read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the temperature register + write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); + } } /**************************************************************************/ @@ -434,7 +432,7 @@ RV3032C7TimerClockFreq RTC_RV3032C7::getCountdownTimerClock() { @return RV3032C7EventType enum value for the current Periodic Countdown Timer event type */ /**************************************************************************/ -RV3032C7EventType getCountdownTimerEventType() { +RV3032C7EventType RTC_RV3032C7::getCountdownTimerEventType() { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); uint8_t event_type= (ctrl2 & RV3032C7_TIE) >> 4; @@ -451,9 +449,63 @@ RV3032C7EventType getCountdownTimerEventType() { } } -void RTC_RV3032C7::disableCountdownTimer(void); -void RTC_RV3032C7::clearCountdownTimer(void); -bool RTC_RV3032C7::CountdownTimerFired(void); +/**************************************************************************/ +/*! + @brief Disable Periodic Countdown Timer + @details this function disables the Periodic Countdown Timer and in addition clears it (same as + clearCountdownTimer() +*/ +/**************************************************************************/ +void RTC_RV3032C7::disableCountdownTimer(void) { + uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + + // disable Periodic Countdown Timer + ctrl1 &= ~RV3032C7_TE; // clear TE bit + write_register(RV3032C7_CONTROL1, ctrl1); // write register + + // disable Clock output when Periodic Countdown Timer Interrupt + intmask &= ~RV3032C7_CTIE; // Clear CTIE + write_register(RV3032C7_INT_MASK, intmask); // write register + if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + } + + // clear Periodic Countdown Timer Interrupt Enable bit (TIE) + ctrl2 &= ~RV3032C7_TIE; // clear TIE bit + write_register(RV3032C7_CONTROL2, ctrl2); // write register + + clearCountdownTimer(); + +} + +/**************************************************************************/ +/*! + @brief Clear status of Periodic Countdown Timer so that CountdownTimerFired() will return false + This also cause the INT PIN to go high (not active). If CLKOUT was activated by the timer, it will stop outputing the clock. +*/ +/**************************************************************************/ +void RTC_RV3032C7::clearCountdownTimer(void) { + write_register(RV3032C7_STATUSREG, ~RV3032C7_TF); // clear Timer flag + // In addition we clear the CLKF flag since it can be set as well if + // RV3032C7_EV_IntClock + uint8_t intmask = read_register(RV3032C7_INT_MASK); + if (intmask & RV3032C7_CTIE) { + uint8_t treg = read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the temperature register + write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); + } +} + +/**************************************************************************/ +/*! + @brief Get status of the Periodic Countdown Timer + @return True if alarm has been fired otherwise false +*/ +/**************************************************************************/ +bool RTC_RV3032C7::CountdownTimerFired(void) { + return (read_register(RV3032C7_STATUSREG) & RV3032C7_TF) != 0 ? true : false; +} /**************************************************************************/ /*! From 53a1f53e065002704f7296b2df3fbf0e7e2c2d13 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 09:44:03 +0200 Subject: [PATCH 43/50] RTC_RV3032C7: Added deconfigureAllTimers() Added deconfigureAllTimers(), similar to RTC_PCF8523 disableCountdownTimer will disable the timer but leave all other settings as they are enableCountdownTimer() withouit parameters will re-enable the timer using previous settings Improved doxygen documentation --- src/RTC_RV3032C7.cpp | 96 +++++++++++++++++++++++++++++++------------- src/RTClib.h | 2 + 2 files changed, 69 insertions(+), 29 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index bb81aac9..3353e954 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -113,10 +113,9 @@ bool RTC_RV3032C7::begin(TwoWire *wireInstance) { /**************************************************************************/ /*! @brief Check the status register PORF flag to see if the RV3032C7 - stopped due to power loss. After Power On, this function will - continue to return true until the time is set via adjust() - @return True if the oscillator stopped or false if it is - running without interruption since last time the time was set by adjust(). + stopped due to power loss. + @details After Power On, this function will continue to return true until the time is set via adjust() + @return True if the oscillator stopped or false if it is running without interruption since last time the time was set by adjust(). */ /**************************************************************************/ bool RTC_RV3032C7::lostPower(void) { @@ -127,8 +126,8 @@ bool RTC_RV3032C7::lostPower(void) { /**************************************************************************/ /*! - @brief Set the date and time. After this function returns, lostPower() will - return false until the next power loss + @brief Set the date and time. + @details After this function returns, lostPower() will return false until the next power loss @param dt DateTime object containing the date/time to set */ /**************************************************************************/ @@ -164,7 +163,7 @@ DateTime RTC_RV3032C7::now() { /**************************************************************************/ /*! @brief Get the current temperature from the RV3032C7's temperature sensor. - The resoluton is 12 bits (corresponding to 0.0625 C) + @details The resoluton is 12 bits (corresponding to 0.0625 C) @return Current temperature (float) */ /**************************************************************************/ @@ -182,6 +181,7 @@ float RTC_RV3032C7::getTemperature() { /**************************************************************************/ /*! @brief Set alarm for RV3032C7. + @details set and enable the Alarm function on the RV3032C7 - If event_type is RV3032C7_EV_Poll the alarm status can be polled with alarmFired() - If event_type is RV3032C7_EV_Int, in addition the INT PIN goes low @@ -238,7 +238,7 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, @return DateTime object with the Alarm data set in the day, hour, minutes, and seconds fields - At power on and after disableAlarm() returns RV3032C7InvalidDate + @details At power on and after disableAlarm() returns RV3032C7InvalidDate */ /**************************************************************************/ DateTime RTC_RV3032C7::getAlarm() { @@ -319,7 +319,7 @@ void RTC_RV3032C7::disableAlarm(void) { /**************************************************************************/ /*! @brief Clear status of alarm so that alarmFired() will return false - This also cause the INT PIN to go high (not active). If CLKOUT was activated + @details This also cause the INT PIN to go high (not active). If CLKOUT was activated by the alarm, it will stop outputing the clock. */ /**************************************************************************/ @@ -344,6 +344,22 @@ bool RTC_RV3032C7::alarmFired(void) { return (read_register(RV3032C7_STATUSREG) & RV3032C7_AF) != 0 ? true : false; } +/**************************************************************************/ +/*! + @brief Enable Periodic Countdown Timer on the RV3032C7. Frequency etc. will be the last one configured. + @details At power on and after deconfigureAllTimers() the timer is set as following: + - clock frequency = 4096 Hz + - num. periods = 0 (resulting in 4096 periods?) + - Event type = polling via i2c, no interrupts + + The function has no effect if the timer is already enabled +*/ +/**************************************************************************/ +void RTC_RV3032C7::enableCountdownTimer() { + uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); + write_register(RV3032C7_CONTROL2, ctrl1 | RV3032C7_TE); // Enable Countdown Timer +} + /**************************************************************************/ /*! @brief Enable Periodic Countdown Timer on the RV3032C7. @@ -358,7 +374,7 @@ bool RTC_RV3032C7::alarmFired(void) { disableCountdownTimer(). @param clkFreq One of the RV3032C7's Periodic Countdown Timer Clock Frequencies. See the #RV3032C7TimerClockFreq enum for options and associated time ranges. - @param numPeriods The number of clkFreq periods (1-4095) to count down. + @param numPeriods The number of clkFreq periods (0-4095) to count down. @param event_type Desired event type, see #RV3032C7EventTyp enum */ /**************************************************************************/ @@ -403,8 +419,8 @@ void RTC_RV3032C7::enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t @brief Get the value of the Periodic Countdown Timer @return the number of clkFreq periods to count down (uint16_t). Range: 0-4095 - The preset value of the countdown timer is returned and not the actual value (which is not possible to read). - At power on returns 0, otherwise it will return the last value set (valid values 1-4095) + @details The preset value of the countdown timer is returned and not the actual value (which is not possible to read). + At power on returns 0, otherwise it will return the last value set (valid values 0-4095) */ /**************************************************************************/ uint16_t RTC_RV3032C7::getCountdownTimer() { @@ -423,7 +439,6 @@ uint16_t RTC_RV3032C7::getCountdownTimer() { RV3032C7TimerClockFreq RTC_RV3032C7::getCountdownTimerClock() { uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); return (RV3032C7TimerClockFreq) (ctrl1 & RV3032C7_TD); - } /**************************************************************************/ @@ -454,36 +469,23 @@ RV3032C7EventType RTC_RV3032C7::getCountdownTimerEventType() { @brief Disable Periodic Countdown Timer @details this function disables the Periodic Countdown Timer and in addition clears it (same as clearCountdownTimer() + */ /**************************************************************************/ void RTC_RV3032C7::disableCountdownTimer(void) { uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); - uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); - uint8_t intmask = read_register(RV3032C7_INT_MASK); // disable Periodic Countdown Timer ctrl1 &= ~RV3032C7_TE; // clear TE bit write_register(RV3032C7_CONTROL1, ctrl1); // write register - // disable Clock output when Periodic Countdown Timer Interrupt - intmask &= ~RV3032C7_CTIE; // Clear CTIE - write_register(RV3032C7_INT_MASK, intmask); // write register - if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register - ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE - } - - // clear Periodic Countdown Timer Interrupt Enable bit (TIE) - ctrl2 &= ~RV3032C7_TIE; // clear TIE bit - write_register(RV3032C7_CONTROL2, ctrl2); // write register - clearCountdownTimer(); - } /**************************************************************************/ /*! @brief Clear status of Periodic Countdown Timer so that CountdownTimerFired() will return false - This also cause the INT PIN to go high (not active). If CLKOUT was activated by the timer, it will stop outputing the clock. + @details This also cause the INT PIN to go high (not active). If CLKOUT was activated by the timer, it will stop outputing the clock. */ /**************************************************************************/ void RTC_RV3032C7::clearCountdownTimer(void) { @@ -500,13 +502,49 @@ void RTC_RV3032C7::clearCountdownTimer(void) { /**************************************************************************/ /*! @brief Get status of the Periodic Countdown Timer - @return True if alarm has been fired otherwise false + @return True if count has reach zero, otherwise false */ /**************************************************************************/ bool RTC_RV3032C7::CountdownTimerFired(void) { return (read_register(RV3032C7_STATUSREG) & RV3032C7_TF) != 0 ? true : false; } +/**************************************************************************/ +/*! + @brief Stop all timers, clears their flags and settings on the RV3032C7. + @details This includes the Countdown Timer, Timer 2, and any + square wave configured with enableClkOut(). + + Tipically this function is called at startup, to ensure the timers have a known state (since the state of the timer is preserved when backup power is used). + + Note: Currently the Timer 2 is not implemented (will be implemented using the periodic time update interrupt function) +*/ +/**************************************************************************/ +void RTC_RV3032C7::deconfigureAllTimers() { + uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); + uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); + uint8_t intmask = read_register(RV3032C7_INT_MASK); + + // disable Periodic Countdown Timer + ctrl1 &= ~RV3032C7_TE; // clear TE bit + write_register(RV3032C7_CONTROL1, ctrl1); // write register + // disable Clock output when Periodic Countdown Timer Interrupt + intmask &= ~RV3032C7_CTIE; // Clear CTIE + write_register(RV3032C7_INT_MASK, intmask); // write register + // clear Periodic Countdown Timer Interrupt Enable bit (TIE) + ctrl2 &= ~RV3032C7_TIE; // clear TIE bit + write_register(RV3032C7_CONTROL2, ctrl2); // write register + clearCountdownTimer(); + + // disable Clock Output + RTC_RV3032C7::disableClkOut(); + + //clear CLKIE if no users left in clock output mask register + if ( (intmask & 0x1F) == 0x00) { // If no user left + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + } +} + /**************************************************************************/ /*! @brief Enable normal clock output on CLKOUT pin (default 32.768 kHz) diff --git a/src/RTClib.h b/src/RTClib.h index 4e94d4cb..2aff9280 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -495,6 +495,7 @@ class RTC_RV3032C7 : RTC_I2C { void clearAlarm(void); bool alarmFired(void); + void enableCountdownTimer(); void enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t numPeriods, RV3032C7EventType event_type = RV3032C7_EV_Int); uint16_t getCountdownTimer(); RV3032C7TimerClockFreq getCountdownTimerClock(); @@ -502,6 +503,7 @@ class RTC_RV3032C7 : RTC_I2C { void disableCountdownTimer(void); void clearCountdownTimer(void); bool CountdownTimerFired(void); + void deconfigureAllTimers(); void enableClkOut(void); void disableClkOut(void); From 903f36a239b707866dc3402e4d189b05d539f919 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 09:55:50 +0200 Subject: [PATCH 44/50] Fixed Clang/Doxygen issues --- src/RTC_RV3032C7.cpp | 234 ++++++++++++++++++++++++------------------- src/RTClib.h | 12 ++- 2 files changed, 140 insertions(+), 106 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index 3353e954..bf5ca701 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -15,7 +15,7 @@ #define RV3032C7_ALARM2 0x09 ///< Alarm 2 register - Hours #define RV3032C7_ALARM3 0x0A ///< Alarm 2 register - Date #define RV3032C7_TIMER0 0x0B ///< Timer Value 0 reg. lower 8 bits -#define RV3032C7_TIMER1 0x0C ///< Timer Value 1 reg. upper 4 bits +#define RV3032C7_TIMER1 0x0C ///< Timer Value 1 reg. upper 4 bits #define RV3032C7_STATUSREG 0x0D ///< Status register #define RV3032C7_CONTROL1 0x10 ///< Control register @@ -43,8 +43,8 @@ // Control register flags/fields (some) #define RV3032C7_XBIT 0x20 ///< Control1, "X" bit (must be set to 1) -#define RV3032C7_TE 0x08 ///< Control1, Periodic Countdown Timer Enable bit -#define RV3032C7_TD 0x03 ///< Control1, Timer Clock Frequency selection +#define RV3032C7_TE 0x08 ///< Control1, Periodic Countdown Timer Enable bit +#define RV3032C7_TD 0x03 ///< Control1, Timer Clock Frequency selection #define RV3032C7_EERD 0x04 ///< Control1, ROM Memory Refresh Disable bit. #define RV3032C7_STOP 0x01 ///< Control2, STOP bit #define RV3032C7_EIE 0x04 ///< Control2, External Event Interrupt Enable bit @@ -58,13 +58,13 @@ // Clock Interrupt Mask register flags (only those used in this file) #define RV3032C7_CAIE 0x10 ///< Clock output when Alarm Interrupt Enable bit -#define RV3032C7_CTIE 0x08 ///< Clock output when Periodic Countdown Timer Interrupt Enable bit +#define RV3032C7_CTIE \ + 0x08 ///< Clock output when Periodic Countdown Timer Interrupt Enable bit // Power Management Unit (PMU) register flags (only those used in this file) #define RV3032C7_NCLKE \ 0x40 ///< Not CLKOUT Enable Bit in Power Management Unit (PMU) -#define RV3032C7_BSM \ - 0x30 ///< Backup Switchover Mode +#define RV3032C7_BSM 0x30 ///< Backup Switchover Mode // Temperature register flags (some flags ended up here, albeit unrelated to // temperature) @@ -113,9 +113,11 @@ bool RTC_RV3032C7::begin(TwoWire *wireInstance) { /**************************************************************************/ /*! @brief Check the status register PORF flag to see if the RV3032C7 - stopped due to power loss. - @details After Power On, this function will continue to return true until the time is set via adjust() - @return True if the oscillator stopped or false if it is running without interruption since last time the time was set by adjust(). + stopped due to power loss. + @details After Power On, this function will continue to return true until the + time is set via adjust() + @return True if the oscillator stopped or false if it is running without + interruption since last time the time was set by adjust(). */ /**************************************************************************/ bool RTC_RV3032C7::lostPower(void) { @@ -126,8 +128,9 @@ bool RTC_RV3032C7::lostPower(void) { /**************************************************************************/ /*! - @brief Set the date and time. - @details After this function returns, lostPower() will return false until the next power loss + @brief Set the date and time. + @details After this function returns, lostPower() will return false until + the next power loss @param dt DateTime object containing the date/time to set */ /**************************************************************************/ @@ -193,7 +196,7 @@ float RTC_RV3032C7::getTemperature() { disableAlarm(). @param dt DateTime object @param alarm_mode Desired mode, see RV3032C7AlarmMode enum - @param event_type Desired event type, see RV3032C7EventTyp enum + @param event_type Desired event type, see RV3032C7EventType enum @return False if alarm registers are not set, otherwise true */ /**************************************************************************/ @@ -224,9 +227,10 @@ bool RTC_RV3032C7::setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, } else { // Disable Clock Output at alarm match to be sure intmask &= ~RV3032C7_CAIE; write_register(RV3032C7_INT_MASK, intmask); // Clear CAIE - if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register - ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE - write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register + if ((intmask & 0x1F) == + 0x00) { // No user left in clock output mask register + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register } } return true; // No check needed for now, may be added in the future @@ -246,10 +250,13 @@ DateTime RTC_RV3032C7::getAlarm() { i2c_dev->write_then_read(buffer, 1, buffer, 3); uint8_t minutes = bcd2bin(buffer[0] & 0x7F); - uint8_t hour = bcd2bin(buffer[1] & 0x3F); // Only 24 hour format supported by RV3032C7 (same as this library) + uint8_t hour = bcd2bin( + buffer[1] & + 0x3F); // Only 24 hour format supported by RV3032C7 (same as this library) uint8_t day = bcd2bin(buffer[2] & 0x3F); - // Chosen in order to match the year and month returned by RTC_DS3231::getAlarm(); + // Chosen in order to match the year and month returned by + // RTC_DS3231::getAlarm(); return DateTime(2000, 5, day, hour, minutes); } @@ -265,7 +272,8 @@ RV3032C7AlarmMode RTC_RV3032C7::getAlarmMode() { uint8_t alarm_mode = (buffer[0] & 0x80) >> 7 // A1M1 - Minutes bit | (buffer[1] & 0x80) >> 6 // A1M2 - Hour bit | (buffer[2] & 0x80) >> 5; // A1M3 - Date bit - return (RV3032C7AlarmMode)alarm_mode; // No need to check because all possible values are valid + return (RV3032C7AlarmMode) + alarm_mode; // No need to check because all possible values are valid } /**************************************************************************/ @@ -277,17 +285,17 @@ RV3032C7AlarmMode RTC_RV3032C7::getAlarmMode() { RV3032C7EventType RTC_RV3032C7::getAlarmEventType() { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - uint8_t event_type= (ctrl2 & RV3032C7_AIE) >> 3; - if ( ((intmask & RV3032C7_CAIE) != 0) && ((ctrl2 & RV3032C7_CLKIE) != 0) ) { - event_type |= 0x02; + uint8_t event_type = (ctrl2 & RV3032C7_AIE) >> 3; + if (((intmask & RV3032C7_CAIE) != 0) && ((ctrl2 & RV3032C7_CLKIE) != 0)) { + event_type |= 0x02; } - switch(event_type) { - case RV3032C7_EV_Poll: - case RV3032C7_EV_Int: - case RV3032C7_EV_IntClock: - return (RV3032C7EventType) event_type; - default: - return RV3032C7_EV_Poll; + switch (event_type) { + case RV3032C7_EV_Poll: + case RV3032C7_EV_Int: + case RV3032C7_EV_IntClock: + return (RV3032C7EventType)event_type; + default: + return RV3032C7_EV_Poll; } } @@ -301,17 +309,17 @@ RV3032C7EventType RTC_RV3032C7::getAlarmEventType() { void RTC_RV3032C7::disableAlarm(void) { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - // reset to power on default, preventing any further match + // reset to power on default, preventing any further match uint8_t buffer[4] = {RV3032C7_ALARM1, 0x00, 0x00, 0x00}; i2c_dev->write(buffer, 4); - - intmask &= ~RV3032C7_CAIE; // Clear CAIE + + intmask &= ~RV3032C7_CAIE; // Clear CAIE write_register(RV3032C7_INT_MASK, intmask); // write register - if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register - ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + if ((intmask & 0x1F) == 0x00) { // No user left in clock output mask register + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE } ctrl2 &= ~RV3032C7_AIE; // clear Alarm Interrupt Enable (AIE) - write_register(RV3032C7_CONTROL2, ctrl2); // write register + write_register(RV3032C7_CONTROL2, ctrl2); // write register clearAlarm(); } @@ -319,8 +327,8 @@ void RTC_RV3032C7::disableAlarm(void) { /**************************************************************************/ /*! @brief Clear status of alarm so that alarmFired() will return false - @details This also cause the INT PIN to go high (not active). If CLKOUT was activated - by the alarm, it will stop outputing the clock. + @details This also cause the INT PIN to go high (not active). If CLKOUT was + activated by the alarm, it will stop outputing the clock. */ /**************************************************************************/ void RTC_RV3032C7::clearAlarm(void) { @@ -329,8 +337,10 @@ void RTC_RV3032C7::clearAlarm(void) { // RV3032C7_EV_IntClock uint8_t intmask = read_register(RV3032C7_INT_MASK); if (intmask & RV3032C7_CAIE) { - uint8_t treg = read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the temperature register - write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); + uint8_t treg = + read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the + // temperature register + write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); } } @@ -346,8 +356,10 @@ bool RTC_RV3032C7::alarmFired(void) { /**************************************************************************/ /*! - @brief Enable Periodic Countdown Timer on the RV3032C7. Frequency etc. will be the last one configured. - @details At power on and after deconfigureAllTimers() the timer is set as following: + @brief Enable Periodic Countdown Timer on the RV3032C7. Frequency etc. will + be the last one configured. + @details At power on and after deconfigureAllTimers() the timer is set as + following: - clock frequency = 4096 Hz - num. periods = 0 (resulting in 4096 periods?) - Event type = polling via i2c, no interrupts @@ -357,7 +369,8 @@ bool RTC_RV3032C7::alarmFired(void) { /**************************************************************************/ void RTC_RV3032C7::enableCountdownTimer() { uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); - write_register(RV3032C7_CONTROL2, ctrl1 | RV3032C7_TE); // Enable Countdown Timer + write_register(RV3032C7_CONTROL2, + ctrl1 | RV3032C7_TE); // Enable Countdown Timer } /**************************************************************************/ @@ -372,32 +385,36 @@ void RTC_RV3032C7::enableCountdownTimer() { (even if it was turned off via disableClkOut()). The clock will be output until the INT pin is cleared by clearCountdownTimer() or disabled with disableCountdownTimer(). - @param clkFreq One of the RV3032C7's Periodic Countdown Timer Clock Frequencies. - See the #RV3032C7TimerClockFreq enum for options and associated time ranges. + @param clkFreq One of the RV3032C7's Periodic Countdown Timer Clock + Frequencies. See the #RV3032C7TimerClockFreq enum for options and associated + time ranges. @param numPeriods The number of clkFreq periods (0-4095) to count down. - @param event_type Desired event type, see #RV3032C7EventTyp enum + @param event_type Desired event type, see #RV3032C7EventType enum */ /**************************************************************************/ -void RTC_RV3032C7::enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t numPeriods, RV3032C7EventType event_type) { - uint8_t buffer[3] = { RV3032C7_TIMER0, lowByte(numPeriods), highByte(numPeriods) }; +void RTC_RV3032C7::enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, + uint8_t numPeriods, + RV3032C7EventType event_type) { + uint8_t buffer[3] = {RV3032C7_TIMER0, lowByte(numPeriods), + highByte(numPeriods)}; uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); - uint8_t intmask = read_register(RV3032C7_INT_MASK); + uint8_t intmask = read_register(RV3032C7_INT_MASK); - ctrl1 &= ~RV3032C7_TE; // clear TE bit - write_register(RV3032C7_CONTROL2, ctrl1); // Disable Countdown Timer - ctrl2 &= ~RV3032C7_TIE; // clear TIE bit - write_register(RV3032C7_CONTROL2, ctrl2); // Disable Timer Interrupt + ctrl1 &= ~RV3032C7_TE; // clear TE bit + write_register(RV3032C7_CONTROL2, ctrl1); // Disable Countdown Timer + ctrl2 &= ~RV3032C7_TIE; // clear TIE bit + write_register(RV3032C7_CONTROL2, ctrl2); // Disable Timer Interrupt write_register(RV3032C7_STATUSREG, ~RV3032C7_TF); // clear Timer flag ctrl1 = (ctrl1 & (~RV3032C7_TD)) | (clkFreq & RV3032C7_TD); write_register(RV3032C7_CONTROL2, ctrl1); // Set TD field - i2c_dev->write(buffer, 3); // Write Timer Value (12 bits) - + i2c_dev->write(buffer, 3); // Write Timer Value (12 bits) + if (event_type & 0x01) { // Enable Interrupt at alarm match - ctrl2 |= RV3032C7_TIE; //set Timer Interrupt Enable (TIE) - write_register(RV3032C7_CONTROL2, ctrl2); //enable Timer interrupt + ctrl2 |= RV3032C7_TIE; // set Timer Interrupt Enable (TIE) + write_register(RV3032C7_CONTROL2, ctrl2); // enable Timer interrupt } if (event_type & 0x02) { // Enable Clock Output at timer interrupt ctrl2 |= RV3032C7_CLKIE; // Set CLKIE @@ -406,86 +423,94 @@ void RTC_RV3032C7::enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t } else { // Disable Clock Output at alarm match to be sure intmask &= ~RV3032C7_CTIE; write_register(RV3032C7_INT_MASK, intmask & (~RV3032C7_CTIE)); // Clear CTIE - if ( (intmask & 0x1F) == 0x00) { // No user left in clock output mask register - ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE - write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register + if ((intmask & 0x1F) == + 0x00) { // No user left in clock output mask register + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register } } - write_register(RV3032C7_CONTROL2, ctrl1 | RV3032C7_TE); // Enable Countdown Timer + write_register(RV3032C7_CONTROL2, + ctrl1 | RV3032C7_TE); // Enable Countdown Timer } /**************************************************************************/ /*! @brief Get the value of the Periodic Countdown Timer - @return the number of clkFreq periods to count down (uint16_t). Range: 0-4095 + @return the number of clkFreq periods to count down (uint16_t). Range: + 0-4095 - @details The preset value of the countdown timer is returned and not the actual value (which is not possible to read). - At power on returns 0, otherwise it will return the last value set (valid values 0-4095) + @details The preset value of the countdown timer is returned and not the + actual value (which is not possible to read). At power on returns 0, + otherwise it will return the last value set (valid values 0-4095) */ /**************************************************************************/ uint16_t RTC_RV3032C7::getCountdownTimer() { - uint8_t buffer[3] = { RV3032C7_TIMER0, 0}; + uint8_t buffer[3] = {RV3032C7_TIMER0, 0}; i2c_dev->write_then_read(buffer, 1, buffer, 2); - uint16_t numPeriods = ((uint16_t)buffer[1])<<8 | buffer[0]; + uint16_t numPeriods = ((uint16_t)buffer[1]) << 8 | buffer[0]; return numPeriods; } /**************************************************************************/ /*! @brief Get the mode for the Periodic Countdown Timer - @return RV3032C7's Periodic Countdown Timer Clock Frequency. See the #RV3032C7TimerClockFreq enum for options and associated time ranges. + @return RV3032C7's Periodic Countdown Timer Clock Frequency. See the + #RV3032C7TimerClockFreq enum for options and associated time ranges. */ /**************************************************************************/ RV3032C7TimerClockFreq RTC_RV3032C7::getCountdownTimerClock() { uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); - return (RV3032C7TimerClockFreq) (ctrl1 & RV3032C7_TD); + return (RV3032C7TimerClockFreq)(ctrl1 & RV3032C7_TD); } /**************************************************************************/ /*! @brief Get the event type for the Periodic Countdown Timer - @return RV3032C7EventType enum value for the current Periodic Countdown Timer event type + @return RV3032C7EventType enum value for the current Periodic Countdown + Timer event type */ /**************************************************************************/ RV3032C7EventType RTC_RV3032C7::getCountdownTimerEventType() { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - uint8_t event_type= (ctrl2 & RV3032C7_TIE) >> 4; - if ( ((intmask & RV3032C7_CTIE) != 0) && ((ctrl2 & RV3032C7_CLKIE) != 0) ) { - event_type |= 0x02; + uint8_t event_type = (ctrl2 & RV3032C7_TIE) >> 4; + if (((intmask & RV3032C7_CTIE) != 0) && ((ctrl2 & RV3032C7_CLKIE) != 0)) { + event_type |= 0x02; } - switch(event_type) { - case RV3032C7_EV_Poll: - case RV3032C7_EV_Int: - case RV3032C7_EV_IntClock: - return (RV3032C7EventType) event_type; - default: - return RV3032C7_EV_Poll; + switch (event_type) { + case RV3032C7_EV_Poll: + case RV3032C7_EV_Int: + case RV3032C7_EV_IntClock: + return (RV3032C7EventType)event_type; + default: + return RV3032C7_EV_Poll; } } /**************************************************************************/ /*! @brief Disable Periodic Countdown Timer - @details this function disables the Periodic Countdown Timer and in addition clears it (same as - clearCountdownTimer() + @details this function disables the Periodic Countdown Timer and in addition + clears it (same as clearCountdownTimer() */ /**************************************************************************/ void RTC_RV3032C7::disableCountdownTimer(void) { uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); - - // disable Periodic Countdown Timer - ctrl1 &= ~RV3032C7_TE; // clear TE bit - write_register(RV3032C7_CONTROL1, ctrl1); // write register + + // disable Periodic Countdown Timer + ctrl1 &= ~RV3032C7_TE; // clear TE bit + write_register(RV3032C7_CONTROL1, ctrl1); // write register clearCountdownTimer(); } /**************************************************************************/ /*! - @brief Clear status of Periodic Countdown Timer so that CountdownTimerFired() will return false - @details This also cause the INT PIN to go high (not active). If CLKOUT was activated by the timer, it will stop outputing the clock. + @brief Clear status of Periodic Countdown Timer so that + CountdownTimerFired() will return false + @details This also cause the INT PIN to go high (not active). If CLKOUT was + activated by the timer, it will stop outputing the clock. */ /**************************************************************************/ void RTC_RV3032C7::clearCountdownTimer(void) { @@ -494,8 +519,10 @@ void RTC_RV3032C7::clearCountdownTimer(void) { // RV3032C7_EV_IntClock uint8_t intmask = read_register(RV3032C7_INT_MASK); if (intmask & RV3032C7_CTIE) { - uint8_t treg = read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the temperature register - write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); + uint8_t treg = + read_register(RV3032C7_TEMPERATUREREG); // CLKF happens to be in the + // temperature register + write_register(RV3032C7_TEMPERATUREREG, treg & (~RV3032C7_CLKF)); } } @@ -506,7 +533,7 @@ void RTC_RV3032C7::clearCountdownTimer(void) { */ /**************************************************************************/ bool RTC_RV3032C7::CountdownTimerFired(void) { - return (read_register(RV3032C7_STATUSREG) & RV3032C7_TF) != 0 ? true : false; + return (read_register(RV3032C7_STATUSREG) & RV3032C7_TF) != 0 ? true : false; } /**************************************************************************/ @@ -514,10 +541,13 @@ bool RTC_RV3032C7::CountdownTimerFired(void) { @brief Stop all timers, clears their flags and settings on the RV3032C7. @details This includes the Countdown Timer, Timer 2, and any square wave configured with enableClkOut(). - - Tipically this function is called at startup, to ensure the timers have a known state (since the state of the timer is preserved when backup power is used). - - Note: Currently the Timer 2 is not implemented (will be implemented using the periodic time update interrupt function) + + Tipically this function is called at startup, to ensure the timers have a + known state (since the state of the timer is preserved when backup power is + used). + + Note: Currently the Timer 2 is not implemented (will be implemented using the + periodic time update interrupt function) */ /**************************************************************************/ void RTC_RV3032C7::deconfigureAllTimers() { @@ -525,23 +555,23 @@ void RTC_RV3032C7::deconfigureAllTimers() { uint8_t ctrl2 = read_register(RV3032C7_CONTROL2); uint8_t intmask = read_register(RV3032C7_INT_MASK); - // disable Periodic Countdown Timer - ctrl1 &= ~RV3032C7_TE; // clear TE bit - write_register(RV3032C7_CONTROL1, ctrl1); // write register + // disable Periodic Countdown Timer + ctrl1 &= ~RV3032C7_TE; // clear TE bit + write_register(RV3032C7_CONTROL1, ctrl1); // write register // disable Clock output when Periodic Countdown Timer Interrupt - intmask &= ~RV3032C7_CTIE; // Clear CTIE + intmask &= ~RV3032C7_CTIE; // Clear CTIE write_register(RV3032C7_INT_MASK, intmask); // write register // clear Periodic Countdown Timer Interrupt Enable bit (TIE) - ctrl2 &= ~RV3032C7_TIE; // clear TIE bit - write_register(RV3032C7_CONTROL2, ctrl2); // write register + ctrl2 &= ~RV3032C7_TIE; // clear TIE bit + write_register(RV3032C7_CONTROL2, ctrl2); // write register clearCountdownTimer(); - // disable Clock Output + // disable Clock Output RTC_RV3032C7::disableClkOut(); - //clear CLKIE if no users left in clock output mask register - if ( (intmask & 0x1F) == 0x00) { // If no user left - ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE + // clear CLKIE if no users left in clock output mask register + if ((intmask & 0x1F) == 0x00) { // If no user left + ctrl2 &= (~RV3032C7_CLKIE); // clear CLKIE } } diff --git a/src/RTClib.h b/src/RTClib.h index 2aff9280..11a89d3e 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -152,7 +152,10 @@ enum RV3032C7EventType { 0x03, /**< Interrupt on INT pin + clock output on CLKOUT pin */ }; -#define RV3032C7InvalidDate DateTime(2000, 5, 0x00, 0x00, 0x00) +#define RV3032C7InvalidDate \ + DateTime(2000, 5, 0x00, 0x00, \ + 0x00) /**< Invalid date, returned by RTC_RV3032C7::getAlarm() when \ + the alarm is disabled */ /**************************************************************************/ /*! @@ -485,7 +488,7 @@ class RTC_RV3032C7 : RTC_I2C { void adjust(const DateTime &dt); bool lostPower(void); DateTime now(); - + bool setAlarm(const DateTime &dt, RV3032C7AlarmMode alarm_mode, RV3032C7EventType event_type = RV3032C7_EV_Int); DateTime getAlarm(); @@ -494,9 +497,10 @@ class RTC_RV3032C7 : RTC_I2C { void disableAlarm(void); void clearAlarm(void); bool alarmFired(void); - + void enableCountdownTimer(); - void enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t numPeriods, RV3032C7EventType event_type = RV3032C7_EV_Int); + void enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t numPeriods, + RV3032C7EventType event_type = RV3032C7_EV_Int); uint16_t getCountdownTimer(); RV3032C7TimerClockFreq getCountdownTimerClock(); RV3032C7EventType getCountdownTimerEventType(); From e415395ef6626650c7247e7892e9698341b29333 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 10:35:06 +0200 Subject: [PATCH 45/50] RV3032C7: spelling of RV3032C7TimerClockFreq enum --- src/RTClib.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RTClib.h b/src/RTClib.h index 11a89d3e..ec15b562 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -140,8 +140,8 @@ enum RV3032C7AlarmMode { enum RV3032C7TimerClockFreq { RV3032C7_Frequency4096Hz = 0x00, /**< 4096 Hz */ RV3032C7_Frequency64Hz = 0x01, /**< 64 Hz */ - RV3032C7_FrequencySeconds = 0x02, /**< T=1s or 1 Hz */ - RV3032C7_CFrequencyMinutes = 0x03, /**< T=60s or 1/60 Hz */ + RV3032C7_FrequencySecond = 0x02, /**< T=1s or 1 Hz */ + RV3032C7_FrequencyMinute = 0x03, /**< T=60s or 1/60 Hz */ }; /** RV3032C7 Event type */ From 9a33dfe8d22dbc6f8c2799886081ab72f3a03f4d Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 10:36:01 +0200 Subject: [PATCH 46/50] RV3032C7: Added new keywords Plus fixed formatting for exiting keywords --- keywords.txt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/keywords.txt b/keywords.txt index 5456f737..d169ed96 100644 --- a/keywords.txt +++ b/keywords.txt @@ -25,6 +25,7 @@ Pcf8523OffsetMode KEYWORD1 Pcf8563SqwPinMode KEYWORD1 RV3032C7AlarmMode KEYWORD1 RV3032C7EventType KEYWORD1 +RV3032C7TimerClockFreq KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -73,15 +74,20 @@ initialized KEYWORD2 enableSecondTimer KEYWORD2 disableSecondTimer KEYWORD2 enableCountdownTimer KEYWORD2 +getCountdownTimer KEYWORD2 +getCountdownTimerClock KEYWORD2 +getCountdownTimerEventType KEYWORD2 +clearCountdownTimer KEYWORD2 +CountdownTimerFired KEYWORD2 disableCountdownTimer KEYWORD2 deconfigureAllTimers KEYWORD2 calibrate KEYWORD2 -enable32K KEYWORD2 -disable32K KEYWORD2 -isEnabled32K KEYWORD2 -enableClkOut KEYWORD2 -disableClkOut KEYWORD2 -isEnabledClkOut KEYWORD2 +enable32K KEYWORD2 +disable32K KEYWORD2 +isEnabled32K KEYWORD2 +enableClkOut KEYWORD2 +disableClkOut KEYWORD2 +isEnabledClkOut KEYWORD2 ####################################### # Constants (LITERAL1) From 87bff46b385b836e402e606b82f3109585289166 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 15:12:27 +0200 Subject: [PATCH 47/50] RV3032C7: correct initial capital for countdownTimerFired --- keywords.txt | 2 +- src/RTC_RV3032C7.cpp | 6 +++--- src/RTClib.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/keywords.txt b/keywords.txt index d169ed96..b67a5752 100644 --- a/keywords.txt +++ b/keywords.txt @@ -78,7 +78,7 @@ getCountdownTimer KEYWORD2 getCountdownTimerClock KEYWORD2 getCountdownTimerEventType KEYWORD2 clearCountdownTimer KEYWORD2 -CountdownTimerFired KEYWORD2 +countdownTimerFired KEYWORD2 disableCountdownTimer KEYWORD2 deconfigureAllTimers KEYWORD2 calibrate KEYWORD2 diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index bf5ca701..dba5fec7 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -377,7 +377,7 @@ void RTC_RV3032C7::enableCountdownTimer() { /*! @brief Enable Periodic Countdown Timer on the RV3032C7. - If event_type is RV3032C7_EV_Poll the alarm status can be polled with - CountdownTimerFired() + countdownTimerFired() - If event_type is RV3032C7_EV_Int, in addition the INT PIN goes low (usually this is used to generate an interrupt) - If event_type is RV3032C7_EV_IntClock, in addition to the INT PIN @@ -508,7 +508,7 @@ void RTC_RV3032C7::disableCountdownTimer(void) { /**************************************************************************/ /*! @brief Clear status of Periodic Countdown Timer so that - CountdownTimerFired() will return false + countdownTimerFired() will return false @details This also cause the INT PIN to go high (not active). If CLKOUT was activated by the timer, it will stop outputing the clock. */ @@ -532,7 +532,7 @@ void RTC_RV3032C7::clearCountdownTimer(void) { @return True if count has reach zero, otherwise false */ /**************************************************************************/ -bool RTC_RV3032C7::CountdownTimerFired(void) { +bool RTC_RV3032C7::countdownTimerFired(void) { return (read_register(RV3032C7_STATUSREG) & RV3032C7_TF) != 0 ? true : false; } diff --git a/src/RTClib.h b/src/RTClib.h index ec15b562..cd3150e4 100644 --- a/src/RTClib.h +++ b/src/RTClib.h @@ -506,7 +506,7 @@ class RTC_RV3032C7 : RTC_I2C { RV3032C7EventType getCountdownTimerEventType(); void disableCountdownTimer(void); void clearCountdownTimer(void); - bool CountdownTimerFired(void); + bool countdownTimerFired(void); void deconfigureAllTimers(); void enableClkOut(void); From 8ef285dace7f8effdcd8e04cd0d6af687eb93b29 Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 15:13:13 +0200 Subject: [PATCH 48/50] RV3032C7 Minor formatting correction in example --- examples/RV3032C7_alarm/RV3032C7_alarm.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/RV3032C7_alarm/RV3032C7_alarm.ino b/examples/RV3032C7_alarm/RV3032C7_alarm.ino index d348d52e..a304a85f 100644 --- a/examples/RV3032C7_alarm/RV3032C7_alarm.ino +++ b/examples/RV3032C7_alarm/RV3032C7_alarm.ino @@ -24,7 +24,7 @@ void setup() { while (1) delay(10); } - if(rtc.lostPower()) { + if (rtc.lostPower()) { // this will adjust to the date and time at compilation rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); } From 3d79fd7204b17e79edd930adf0dcbc1143693f8e Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 21:18:41 +0200 Subject: [PATCH 49/50] RV3032C7 Bug fixes affecting Timers Wrong register written, fixed --- src/RTC_RV3032C7.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/RTC_RV3032C7.cpp b/src/RTC_RV3032C7.cpp index dba5fec7..a586ae93 100644 --- a/src/RTC_RV3032C7.cpp +++ b/src/RTC_RV3032C7.cpp @@ -369,7 +369,7 @@ bool RTC_RV3032C7::alarmFired(void) { /**************************************************************************/ void RTC_RV3032C7::enableCountdownTimer() { uint8_t ctrl1 = read_register(RV3032C7_CONTROL1); - write_register(RV3032C7_CONTROL2, + write_register(RV3032C7_CONTROL1, ctrl1 | RV3032C7_TE); // Enable Countdown Timer } @@ -403,13 +403,13 @@ void RTC_RV3032C7::enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, uint8_t intmask = read_register(RV3032C7_INT_MASK); ctrl1 &= ~RV3032C7_TE; // clear TE bit - write_register(RV3032C7_CONTROL2, ctrl1); // Disable Countdown Timer + write_register(RV3032C7_CONTROL1, ctrl1); // Disable Countdown Timer ctrl2 &= ~RV3032C7_TIE; // clear TIE bit write_register(RV3032C7_CONTROL2, ctrl2); // Disable Timer Interrupt write_register(RV3032C7_STATUSREG, ~RV3032C7_TF); // clear Timer flag ctrl1 = (ctrl1 & (~RV3032C7_TD)) | (clkFreq & RV3032C7_TD); - write_register(RV3032C7_CONTROL2, ctrl1); // Set TD field + write_register(RV3032C7_CONTROL1, ctrl1); // Set TD field i2c_dev->write(buffer, 3); // Write Timer Value (12 bits) if (event_type & 0x01) { // Enable Interrupt at alarm match @@ -429,7 +429,7 @@ void RTC_RV3032C7::enableCountdownTimer(RV3032C7TimerClockFreq clkFreq, write_register(RV3032C7_CONTROL2, ctrl2); // write ctrl2 to register } } - write_register(RV3032C7_CONTROL2, + write_register(RV3032C7_CONTROL1, ctrl1 | RV3032C7_TE); // Enable Countdown Timer } From eac0654fb579ce071cb3b601eced553d4403e7ec Mon Sep 17 00:00:00 2001 From: alx2009 <100997527+alx2009@users.noreply.github.com> Date: Sun, 2 Oct 2022 21:19:15 +0200 Subject: [PATCH 50/50] RV3032C7: new example showing timers usage --- examples/RV3032C7_timers/RV3032C7_timers.ino | 228 +++++++++++++++++++ 1 file changed, 228 insertions(+) create mode 100644 examples/RV3032C7_timers/RV3032C7_timers.ino diff --git a/examples/RV3032C7_timers/RV3032C7_timers.ino b/examples/RV3032C7_timers/RV3032C7_timers.ino new file mode 100644 index 00000000..6210820a --- /dev/null +++ b/examples/RV3032C7_timers/RV3032C7_timers.ino @@ -0,0 +1,228 @@ +/**************************************************************************/ +/* + Timer examples using a RV3032C7 RTC connected via I2C and Wire lib + with the INT pin wired to an interrupt-capable input. + + According to the application manual, the RV3032C7 countdown timer can count from 244.14 microseconds to 4095 minutes (almost 3 days): + https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-3032-C7_App-Manual.pdf + + This sketch sets a countdown timer, and executes code when it reaches 0, + then blinks the built-in LED like BlinkWithoutDelay, but without millis()! + + NOTE: + You must connect the RV3032C7's INT pin to your Arduino or other + microcontroller on an input pin that can handle interrupts, and that has a + pullup resistor. The pin will be briefly pulled low each time the countdown + reaches 0. This example will not work without the interrupt pin connected! + + On boards that defines PIN_NEOPIXEL (such as the Adafruit QT Py) the neopixel will be blinked rather than the LED_BUILTIN + +*/ +/**************************************************************************/ + +#include "RTClib.h" + +#ifdef PIN_NEOPIXEL +#include +// create a pixel strand with 1 pixel on PIN_NEOPIXEL +Adafruit_NeoPixel pixels(1, PIN_NEOPIXEL); +const uint32_t neopixel_on = pixels.Color(255, 0, 0); +#endif //PIN_NEOPIXEL + +RTC_RV3032C7 rtc; + +// Input pin with interrupt capability +const int timerInterruptPin = 2; // Most Arduinos, Adafruit Qt Py +//const int timerInterruptPin = 5; // Adafruit Feather M0/M4/nRF52840 + +// Variables modified during an interrupt must be declared volatile +volatile bool countdownInterruptTriggered = false; +volatile int numCountdownInterrupts = 0; + +void setup () { + Serial.begin(57600); + +#ifndef ESP8266 + while (!Serial); // wait for serial port to connect. Needed for native USB +#endif + + if (! rtc.begin()) { + Serial.println("Couldn't find RTC"); + Serial.flush(); + while (1) delay(10); + } + //dumpRegisters(); + + if (rtc.lostPower()) { + // this will adjust to the date and time at compilation + rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); + } + + //we don't need the CLKOUT Pin, so disable it + rtc.disableClkOut(); + +# ifdef PIN_NEOPIXEL + pixels.begin(); // initialize the pixel +# else + pinMode(LED_BUILTIN, OUTPUT); +# endif //PIN_NEOPIXEL + + // Set the pin attached to RV3032C7 INT to be an input with pullup to HIGH. + // The RV3032C7 interrupt pin will pull it LOW at the end of a given + // countdown period, then it will be released to be pulled HIGH again when clearCountdownTimer() is called. + pinMode(timerInterruptPin, INPUT_PULLUP); + + Serial.println(F("\nStarting RV3032C7 Periodic Countdown Timer example.")); + Serial.print(F("Configured to expect RV3032C7 INT pin connected to input pin: ")); + Serial.println(timerInterruptPin); + Serial.println(F("This example will not work without the interrupt pin connected!\n\n")); + + // Timer configuration is not cleared on an RTC reset due to battery backup! + rtc.deconfigureAllTimers(); + + Serial.println(F("First, use the RV3032C7's 'Countdown Timer' with an interrupt.")); + Serial.println(F("Set the countdown for 10 seconds and we'll let it run for 2 rounds.")); + + //dumpRegisters(); + Serial.println(F("Starting Countdown Timer now...")); + + // These are the RV3032C7's built-in "Timer Clock Frequency selection field TD". + // They are predefined time periods you choose as your base unit of time, + // depending on the length of countdown timer you need. + // The minimum length of your countdown is 1 time period. + // The maximum length of your countdown is 4095 time periods. + // + // RV3032C7_FrequencyMinute = 1 minute, max 4095 minutes (68 hours and 15 minutes) + // RV3032C7_FrequencySecond = 1 second, max 4095 seconds (68 minutes and 15 seconds) + // RV3032C7_Frequency64Hz = 1/64 of a second (15.625 milliseconds), max approx 64 seconds + // RV3032C7_Frequency4096Hz = 1/4096 of a second (244 microseconds), max approx 1 second + // + // Uncomment an example below: + // rtc.enableCountdownTimer(RV3032C7_FrequencyMinute, 150); // 2.5 hours + rtc.enableCountdownTimer(RV3032C7_FrequencySecond, 10); // 10 seconds + // rtc.enableCountdownTimer(RV3032C7_Frequency64Hz, 32); // 1/2 second + // rtc.enableCountdownTimer(RV3032C7_Frequency64Hz, 16); // 1/4 second + // rtc.enableCountdownTimer(RV3032C7_Frequency4096Hz, 4095); // slightly below 1 second + dumpRegisters(); + + attachInterrupt(digitalPinToInterrupt(timerInterruptPin), countdownOver, FALLING); + + // This message proves we're not blocked while counting down! + Serial.println(F(" While we're waiting, a word of caution:")); + Serial.println(F(" When starting a new countdown timer, the first time period is not of fixed")); + Serial.println(F(" duration. The amount of inaccuracy for the first time period is up to one full")); + Serial.println(F(" clock frequency. Example: just the first second of the first round of a new")); + Serial.println(F(" countdown based on RV3032C7_FrequencySecond may be off by as much as 1 second!")); + Serial.println(F(" See also the FIRST PERIOD DURATION chapter in the RV3032C7 Application Manual")); + Serial.println(F(" For critical timing, consider starting actions on the first interrupt.")); +} + +// Triggered by the RV3032C7 Countdown Timer interrupt at the end of a countdown +// period. Meanwhile, the RV3032C7 immediately starts the countdown again. +void countdownOver () { + // Set a flag to run code in the loop(): + countdownInterruptTriggered = true; + numCountdownInterrupts++; +} + +// Triggered by the RV3032C7 Second Timer every second. +void toggleLed () { + // Run certain types of fast executing code here: +# ifdef PIN_NEOPIXEL + if (pixels.getPixelColor(0) == neopixel_on) { + pixels.clear(); + } else { + pixels.setPixelColor(0, neopixel_on); + } + pixels.show(); +# else + digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); +# endif //PIN_NEOPIXEL +} + +void loop () { + if (countdownInterruptTriggered && numCountdownInterrupts == 1) { + Serial.println(F("1st countdown interrupt triggered. Accurate timekeeping starts now.")); + countdownInterruptTriggered = false; // don't come in here again + } else if (countdownInterruptTriggered && numCountdownInterrupts == 2) { + Serial.println(F("2nd countdown interrupt triggered. Disabling countdown and detaching interrupt.\n\n")); + rtc.disableCountdownTimer(); + detachInterrupt(digitalPinToInterrupt(timerInterruptPin)); + delay(2000); + + // TODO: 2nd timer not implemented - enable when implemented + /* + Serial.println(F("Now, set up the RV3032C7's 'Second Timer' to toggle the built-in LED at 1Hz...")); + attachInterrupt(digitalPinToInterrupt(timerInterruptPin), toggleLed, FALLING); + rtc.enableSecondTimer(); + Serial.println(F("Look for the built-in LED to flash 1 second ON, 1 second OFF, repeat. ")); + Serial.println(F("Meanwhile this program will use delay() to block code execution briefly")); + Serial.println(F("before moving on to the last example. Notice the LED keeps blinking!\n\n")); + delay(20000); // less accurate, blocks execution here. Meanwhile Second Timer keeps running. + rtc.disableSecondTimer(); + detachInterrupt(digitalPinToInterrupt(timerInterruptPin)); + */ + + Serial.println(F("Lastly, set up a Countdown Timer that works without using the RV3032C INT pin (Polling via i2c)...")); + rtc.enableCountdownTimer(RV3032C7_Frequency64Hz, 32, RV3032C7_EV_Poll); + dumpRegisters(); + Serial.println(F("Look for the LED to toggle every 1/2 second")); + Serial.println(F("The countdown was set to a source clock frequency of 64 Hz (1/64th of a second)")); + Serial.println(F("for a length of 32 time periods. 32 * 1/64th of a second is 1/2 of a second.")); + Serial.println(F("When the timer fires the led is toggled.")); + Serial.println(F("The loop() polls the RV3032C7 via i2c to detect the timer event. When detected the timer is cleared and the led is toggled.")); + + countdownInterruptTriggered = false; // don't come in here again + } else if (rtc.countdownTimerFired()) { // detect the timer event reading the Timer Flag (TF) via i2c + rtc.clearCountdownTimer(); // clears the flag, until the next time + toggleLed(); + } +} + +void dumpRegisters(void) { + Serial.println(F("Alarm registers:")); + print_i2c_register_hex(0x08); + print_i2c_register_hex(0x09); + print_i2c_register_hex(0x0A); + + Serial.println(); + Serial.println(F("Status register:")); + print_i2c_register_bin(0x0D); + Serial.println(F("Control registers:")); + print_i2c_register_bin(0x10); + print_i2c_register_bin(0x11); + print_i2c_register_bin(0x12); + Serial.println(F("Clock INT mask:")); + print_i2c_register_bin(0x14); + + Serial.println(); + Serial.println(F("EEPROM MIRROR:")); + print_i2c_register_bin(0xC0); + print_i2c_register_bin(0xC1); + print_i2c_register_bin(0xC2); + print_i2c_register_bin(0xC3); +} + +static uint8_t read_i2c_register(uint8_t reg) { + Wire.beginTransmission(0x51); + Wire.write((byte)reg); + Wire.endTransmission(); + + Wire.requestFrom(0x51, (byte)1); + return Wire.read(); +} + +static void print_i2c_register_bin(uint8_t reg) { + Serial.print(F("REG ")); + Serial.print(reg, HEX); + Serial.print(F(" = ")); + Serial.print(read_i2c_register(reg), BIN); + Serial.println(F(" b")); +} + +static void print_i2c_register_hex(uint8_t reg) { + Serial.print(F("REG 0x")); + Serial.print(reg, HEX); + Serial.print(F(" = 0x")); + Serial.println(read_i2c_register(reg), HEX); +}