Erriez / ErriezDS3231

DS3213 high precision RTC (Real Time Clock) library for Arduino
https://github.com/Erriez/ErriezArduinoLibrariesAndSketches
MIT License
22 stars 7 forks source link

How to correctly tell if the battery is drained or not? #10

Open zekageri opened 10 months ago

zekageri commented 10 months ago

I have an arduino project with ESP32 and I'm using this library ( which is great btw ). Currently on power on I'm doing the following

boolean RTC::begin(){
    Wire.begin(rtcSDA_Pin, rtcSCL_Pin);
    Wire.setClock(400000);
    if( !rtc.begin() ){
        Serial.printf("[RTC] - Failed to initialize RTC\n");
        return false;
    }
    Serial.printf("[RTC] - RTC initialized\n");
    checkBattery();
    rtc.clockEnable(true);
    return true;
}

void RTC::checkBattery(){
    Serial.printf("[RTC] - Battery is %s\n", rtc.isRunning()?"charged":"drained");
}

If i call rtc.clockEnable(true); the library will tell me that the battery is ok even if it is drained. But if i don't set the clock to true it will never be ok, even if i replace the battery.

What is the recommended way of handling the low battery? I want to report to the users that they should replace it even at runtime. So i would call the check battery function periodically.

Erriez commented 10 months ago

@zekageri Thanks for using my library.

The DS3231 datasheet contains more information about battery operation. For example function isRunning() returns the inverted value of bit OSF (Oscillator Status Flag) in the status register. When isRunning() returns false (OSF bit is set), it means:

  1. The first time power is applied. (Read: first time VBAT or VCC power is applied)
  2. The voltages present on both VCC and VBAT are insufficient to support oscillation. (In this case no I2C communication possible)
  3. The EOSC bit is turned off in battery-backed mode. (explicitly stop the oscillator by calling clockEnable(false))
  4. External influences on the crystal (i.e., noise, leakage, etc.) (not battery related)

You're checking the battery state correct in function checkBattery() at boottime. Only when the oscillator was stopped, function rtc.clockEnable(true) should be called (this starts the oscillator, bit EOSC set in control register) and the RTC date/time should be re-programmed. Function clockEnable(true) also clears the OSF status register here. That's the reason why the next rtc.isRunning() returns true.

Calling isRunning() periodically at run-time returns the oscillator state which may be stopped by points 3 and 4. Theoretically, I think there is no way to detect a low-battery state at run-time to inform users to replace the battery. The RTC keeps running as long as:

  1. VCC and or VBAT are powered and crystal works properly. After next power-cycle, the battery state can be read.
  2. The battery can be replaced at run-time when VCC is powered and no need to re-program date/time.

Maybe an idea to add an ADC to measure the battery voltage? I'm not sure how fast the ADC pin drains the battery.

Success!