diff --git a/examples/Example3-Trickle_Charging/Example3-Trickle_Charging.ino b/examples/Example3-Trickle_Charging/Example3-Trickle_Charging.ino index 1018321..a89c74a 100644 --- a/examples/Example3-Trickle_Charging/Example3-Trickle_Charging.ino +++ b/examples/Example3-Trickle_Charging/Example3-Trickle_Charging.ino @@ -28,20 +28,23 @@ void setup() { } else Serial.println("RTC online!"); - Serial.println(); + Serial.println(); //Trickle Charger - Serial.print("Config EEPROM 0x37 before: "); - Serial.println(rtc.readConfigEEPROM_RAMmirror(0x37)); - - rtc.enableTrickleCharge(TCR_3K); //series resistor 3kOhm - //rtc.enableTrickleCharge(TCR_5K); //series resistor 5kOhm - //rtc.enableTrickleCharge(TCR_9K); //series resistor 9kOhm + rtc.disableTrickleCharge(); // disable trickle charger + Serial.print("Config EEPROM 0x37 before:\t0b"); + Serial.println(rtc.readConfigEEPROM_RAMmirror(0x37), BIN); + + + rtc.enableTrickleCharge(TCR_3K); //series resistor 3kOhm + //rtc.enableTrickleCharge(TCR_5K); //series resistor 5kOhm + //rtc.enableTrickleCharge(TCR_9K); //series resistor 9kOhm //rtc.enableTrickleCharge(TCR_15K); //series resistor 15kOhm - //rtc.disableTrickleCharge(); //Trickle Charger disabled + //rtc.disableTrickleCharge(); //Trickle Charger disabled - Serial.print("Config EEPROM 0x37 after: "); - Serial.println(rtc.readConfigEEPROM_RAMmirror(0x37)); + Serial.print("Config EEPROM 0x37 after:\t0b"); + Serial.println(rtc.readConfigEEPROM_RAMmirror(0x37), BIN); + Serial.println("\t\t(1 = ON) TCE_bit ^\t^^ TCR_bits (00 = 3k series resistor)"); //For more information see https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-3028-C7_App-Manual.pdf#page=48 } diff --git a/examples/Example6-Backup_Battery_Interrupt_Time_Stamp/Example6-Backup_Battery_Interrupt_Time_Stamp.ino b/examples/Example6-Backup_Battery_Interrupt_Time_Stamp/Example6-Backup_Battery_Interrupt_Time_Stamp.ino new file mode 100644 index 0000000..4a04ea8 --- /dev/null +++ b/examples/Example6-Backup_Battery_Interrupt_Time_Stamp/Example6-Backup_Battery_Interrupt_Time_Stamp.ino @@ -0,0 +1,125 @@ +/* + Battery Backup Interrupt Time Stamp Configuration of RV-3028-C7 Real Time Clock + By: Paolo Salvagione + Date: 6/15/2020 + License: This code is public domain. + + This example shows how to set the Battery Backup Interrupt Time Stamp + Configuration of RTC RV-3028-C7. Open the serial monitor at 115200 baud. + + For more information see + https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-3028-C7_App-Manual.pdf + + Assumptions, + 1) You've already set the RTC time. See the SetPrint_Time example. + 2) You have a backup battery, or capacitor, attached to the RTC's Vbackup pin. See datasheet. + 3) You're keeping the backup battery, or capacitor, topped off with the trickle charge feature + of the RTC. See Trickle_Charging example. + 4) The Vbackup supply, a battery or a capacitor, has enougth power to keep the RTC alive during + interrupt event. + 5) That you will unplug/plug the USB cable powering your microcontroller/Arduino to simulate + loss of power. + + Known Issues, + 1) Unplugging/plugging the RTC directly will bounce and the time stamp counter will count + each bounce as an event. + 2) Default call to rtc.begin disables trick charge settings. +*/ + +#include + +RV3028 rtc; + +void setup() { + + Serial.begin(115200); + while (!Serial); + Serial.println("Backup Battery Interrupt Time Stamp - RTC Example"); + + Wire.begin(); + if (rtc.begin() == false) { + Serial.println("Something went wrong, check wiring"); + while (1); + } else { + Serial.println("RTC online!"); + } + + // Enable Trickle Charger, see Trickle Charging example for complete list of settings. + rtc.enableTrickleCharge(TCR_3K); //series resistor 3kOhm + + // Time Stamp Interrupt settings + if (rtc.isInterruptTimeStampEnabled() == false) // allows settings to persist through reboot. + { + rtc.enableInterruptTimeStamp(backupBattery, lastEvent, clockOff); + //rtc.enableInterruptTimeStamp(backupBattery, firstEvent, clockOff); + } + + Serial.println("Unplug/plug the USB cable to simulate loss of power.\n"); + +} // end setup() + +void loop() { + // Print time stamp register + if (rtc.readInterruptTimeStamp() == false) + { + Serial.println("RTC failed to update."); + while (rtc.readInterruptTimeStamp() == false); + } + else if (rtc.readNumberOfInterrupts() !=0) + { + static String lastInterruptTime = ""; + String currentInterruptTime = rtc.stringTimeStamp(); + if (currentInterruptTime != lastInterruptTime) + { + Serial.print(currentInterruptTime); + Serial.print(" <<< interrupt time stamp, interrupted "); + Serial.print(rtc.readNumberOfInterrupts()); + Serial.println(" times."); + lastInterruptTime = currentInterruptTime; + } + } + + // Print time + if (rtc.updateTime() == false) //Updates the time variables from RTC. + { + Serial.println("RTC failed to update."); + while (rtc.updateTime() == false); + } + else + { + static String lastTime = ""; + String currentTime = rtc.stringTimeStamp(); + if (currentTime != lastTime) { + Serial.println(currentTime); + lastTime = currentTime; + } + } + + // Change time stamp register settings + if (Serial.available()) { + switch (Serial.read()) { + case 'c': + rtc.clearTimeStampRegister(); + Serial.println("Time stamp register cleared."); + break; + case 'f': + rtc.enableInterruptTimeStamp(backupBattery, firstEvent, clockOff); + Serial.println("Time stamp register cleared and set to store first interrupt time stamp."); + break; + case 'l': + rtc.enableInterruptTimeStamp(backupBattery, lastEvent, clockOff); + Serial.println("Time stamp register cleared and set to store last interrupt time stamp."); + break; + case '\n': + // trap returns + break; + default: + Serial.println("---------------------------------------------"); + Serial.println("c - Clears the Time Stamp Register"); + Serial.println("f - Stores first event in time stamp register"); + Serial.println("l - Stores last event in time stamp register"); + Serial.println("---------------------------------------------"); + break; + } + } +} // end loop() \ No newline at end of file diff --git a/src/RV-3028-C7.cpp b/src/RV-3028-C7.cpp index 41123f0..a02e39b 100644 --- a/src/RV-3028-C7.cpp +++ b/src/RV-3028-C7.cpp @@ -66,7 +66,6 @@ BUILD_MONTH_OCT | BUILD_MONTH_NOV | BUILD_MONTH_DEC RV3028::RV3028(void) { - } bool RV3028::begin(TwoWire &wirePort, bool set_24Hour, bool disable_TrickleCharge, bool set_LevelSwitchingMode) @@ -523,7 +522,6 @@ void RV3028::setTimer(bool timer_repeat, uint16_t timer_frequency, uint16_t time case 60000: // 1/60Hz // up to 7.813ms error on first time ctrl1_val |= 3; // Set both bits break; - } if (set_interrupt) @@ -637,7 +635,7 @@ void RV3028::enableTrickleCharge(uint8_t tcr) writeConfigEEPROM_RAMmirror(EEPROM_Backup_Register, EEPROMBackup); } -void RV3028::disableTrickleCharge() +void RV3028::disableTrickleCharge() // does not clear trickle charge resistor setting { //Read EEPROM Backup Register (0x37) uint8_t EEPROMBackup = readConfigEEPROM_RAMmirror(EEPROM_Backup_Register); @@ -647,6 +645,10 @@ void RV3028::disableTrickleCharge() writeConfigEEPROM_RAMmirror(EEPROM_Backup_Register, EEPROMBackup); } +bool RV3028::isTrickleChargeEnabled () +{ + return readBit(EEPROM_Backup_Register, EEPROMBackup_TCE_BIT); +} /********************************* 0 = Switchover disabled @@ -727,6 +729,70 @@ void RV3028::clearClockOutputInterruptFlag() clearBit(RV3028_STATUS, STATUS_CLKF); } +// interrupt time stamp functions +// step by step as described in data sheet +// https://www.microcrystal.com/fileadmin/Media/Products/RTC/App.Manual/RV-3028-C7_App-Manual.pdf#page=76 +void RV3028::enableInterruptTimeStamp(timeStampSource TSS, timeStampStore TSOW, clockOutputOnEvent CEIE) { + clearBit(RV3028_CTRL2, CTRL2_TSE); // clear Time Stamp Enable bit + clearBit(EEPROM_Backup_Register, + EEPROMBackup_BSIE_BIT); // clear Backup Switchover Interrupt Enable bit + clearBit(RV3028_STATUS, STATUS_BSF); // clear Backup Switch Flag + + if (TSS == backupBattery) { + setBit(RV3028_EVENTCTRL, ECR_TSS); // select battery switch over as Time Stamp Source + } else if (TSS == externalPin) { + clearBit(RV3028_EVENTCTRL, ECR_TSS); // select external pin as Time Stamp Source + } + + if (TSOW == lastEvent) { + setBit(RV3028_EVENTCTRL, ECR_TSOW); // stores time stamp of last event + } else if (TSOW == firstEvent) { + clearBit(RV3028_EVENTCTRL, ECR_TSOW); // stores time stamp of first event + } + + setBit(RV3028_EVENTCTRL, ECR_TSR); // reset Time Stamp Register + + if (CEIE == clockOn) { + setBit(RV3028_INT_MASK, IMT_MASK_CEIE); // Clock output on when Event Interrupt bit + } else if (CEIE == clockOff) { + clearBit(RV3028_INT_MASK, IMT_MASK_CEIE); // Clock output off when Event Interrupt bit + } + + setBit(RV3028_CTRL2, CTRL2_TSE); // set Time Stamp Enable bit + setBit(EEPROM_Backup_Register, + EEPROMBackup_BSIE_BIT); // set Backup Switchover Interrupt Enable bit +} + +bool RV3028::isInterruptTimeStampEnabled() { + return readBit(RV3028_CTRL2, CTRL2_TSE); +} + +void RV3028::disableInterruptTimeStamp () { + clearBit(RV3028_CTRL2, CTRL2_TSE); // clear Time Stamp Enable bit +} + +bool RV3028::readInterruptTimeStamp() { // reusing updateTime() function + if (readMultipleRegisters(RV3028_SECONDS_TS, _time, TIME_ARRAY_LENGTH) == false) + return(false); //Something went wrong + + if (is12Hour()) _time[TIME_HOURS] &= ~(1 << HOURS_AM_PM); //Remove this bit from value + + //shift values in array to account for the missing weekday register. + _time[6] = _time[5]; + _time[5] = _time[4]; + _time[4] = _time[3]; + _time[3] = 99; + return true; +} + +uint8_t RV3028::readNumberOfInterrupts(void) { + return(readRegister(RV3028_COUNT_TS)); +} + +void RV3028::clearTimeStampRegister() +{ + setBit(RV3028_EVENTCTRL, ECR_TSR); +} //Returns the status byte uint8_t RV3028::status(void) @@ -895,6 +961,5 @@ bool RV3028::readBit(uint8_t reg_addr, uint8_t bit_num) uint8_t value = readRegister(reg_addr); value &= (1 << bit_num); return value; - } diff --git a/src/RV-3028-C7.h b/src/RV-3028-C7.h index 0661304..e861a34 100644 --- a/src/RV-3028-C7.h +++ b/src/RV-3028-C7.h @@ -106,12 +106,12 @@ Distributed as-is; no warranty is given. //Bits in Status Register #define STATUS_EEBUSY 7 -#define STATUS_CLKF 6 -#define STATUS_BSF 5 -#define STATUS_UF 4 -#define STATUS_TF 3 -#define STATUS_AF 2 -#define STATUS_EVF 1 +#define STATUS_CLKF 6 // clock output interrupt flag +#define STATUS_BSF 5 // backup switch flag +#define STATUS_UF 4 // periodic time update flag +#define STATUS_TF 3 // periodic countdown timer flag +#define STATUS_AF 2 // alarm flag +#define STATUS_EVF 1 // event flag #define STATUS_PORF 0 //Bits in Control1 Register @@ -124,7 +124,7 @@ Distributed as-is; no warranty is given. #define CTRL1_TD0 0 //Bits in Control2 Register -#define CTRL2_TSE 7 +#define CTRL2_TSE 7 // Time Stamp Enable bit #define CTRL2_CLKIE 6 #define CTRL2_UIE 5 #define CTRL2_TIE 4 @@ -149,6 +149,7 @@ Distributed as-is; no warranty is given. #define EEPROMCMD_ReadSingle 0x22 //Bits in EEPROM Backup Register +#define EEPROMBackup_BSIE_BIT 6 //Backup Switchover Interrupt Enable bit #define EEPROMBackup_TCE_BIT 5 //Trickle Charge Enable Bit #define EEPROMBackup_FEDE_BIT 4 //Fast Edge Detection Enable Bit (for Backup Switchover Mode) #define EEPROMBackup_BSM_SHIFT 2 //Backup Switchover Mode shift @@ -179,11 +180,18 @@ Distributed as-is; no warranty is given. #define FD_CLKOUT_LOW 0b111 //CLKOUT = LOW -#define IMT_MASK_CEIE 3 //Clock output when Event Interrupt bit. -#define IMT_MASK_CAIE 2 //Clock output when Alarm Interrupt bit. -#define IMT_MASK_CTIE 1 //Clock output when Periodic Countdown Timer Interrupt bit. -#define IMT_MASK_CUIE 0 //Clock output when Periodic Time Update Interrupt bit. +#define IMT_MASK_CEIE 3 //Clock output when Event Interrupt bit +#define IMT_MASK_CAIE 2 //Clock output when Alarm Interrupt bit +#define IMT_MASK_CTIE 1 //Clock output when Periodic Countdown Timer Interrupt bit +#define IMT_MASK_CUIE 0 //Clock output when Periodic Time Update Interrupt bit +// Event control register (0x13) +// bit 7 not implimented +#define ECR_EHL 6 //Event High/Low Level +// bit 3 not implimented +#define ECR_TSR 2 //Time Stamp Reset bit +#define ECR_TSOW 1 //Time Stamp Overwrite bit, 0 = first event, 1 = last event +#define ECR_TSS 0 //Time Stamp Source Selection bit #define TIME_ARRAY_LENGTH 7 // Total number of writable values in device @@ -197,13 +205,28 @@ enum time_order { TIME_YEAR, // 6 }; +enum timeStampSource { + externalPin = 0, + backupBattery = 1 +}; + +enum timeStampStore { + firstEvent = 0, + lastEvent = 1, +}; + +enum clockOutputOnEvent { + clockOff = 0, + clockOn = 1, +}; + class RV3028 { public: RV3028(void); - bool begin(TwoWire &wirePort = Wire, bool set_24Hour = true, bool disable_TrickleCharge = true, bool set_LevelSwitchingMode = true); + bool begin(TwoWire &wirePort = Wire, bool set_24Hour = true, bool disable_TrickleCharge = false, bool set_LevelSwitchingMode = true); bool setTime(uint8_t sec, uint8_t min, uint8_t hour, uint8_t weekday, uint8_t date, uint8_t month, uint16_t year); bool setTime(uint8_t * time, uint8_t len); @@ -261,6 +284,8 @@ class RV3028 void enableTrickleCharge(uint8_t tcr = TCR_15K); //Trickle Charge Resistor default 15k void disableTrickleCharge(); + bool isTrickleChargeEnabled (); + bool setBackupSwitchoverMode(uint8_t val); void enableClockOut(uint8_t freq); @@ -269,6 +294,14 @@ class RV3028 bool readClockOutputInterruptFlag(); void clearClockOutputInterruptFlag(); + // Interrupt Time Stamp Functions + void enableInterruptTimeStamp(timeStampSource TSS, timeStampStore TSOW, clockOutputOnEvent CEIE); + void disableInterruptTimeStamp(); + bool isInterruptTimeStampEnabled(); + bool readInterruptTimeStamp(); + uint8_t readNumberOfInterrupts(); + void clearTimeStampRegister(); + uint8_t status(); //Returns the status byte void clearInterrupts();