MCP7940 Tutorial 04: Battery Backup

Featured_Image-1-30

With the clock set and the oscillator adjusted to allow for accurate time keeping, we need to make sure we don’t lose these values when the power is removed from our RTC. Let’s explore the use of the battery backup.

Objectives

  1. Learn which registers are preserved on power down.
  2. Enable and disable the battery backup mode.
  3. Retrieve and display the power failure time stamps

Background
MCP7940 Functionality Overview
I2C Library Functions
I2C Signaling
Microchip MCP7940 RTC Datasheet

Schematic
Education Shield – MCP7940 RTCC Subsystem

Setup
For this module, you’ll need the following equipment:

1. Insert a CR2032 button cell battery in the battery holder on the edge of the Education Shield. It should be placed positive side up.

2. Mate the Education Shield with your Arduino UNO R3. If you’re using the MCP7940 Breakout Board with the Debounce Button Breakout Board, connect 5V to 5V, GND to GND, SCL to Analog 5, SDA to Analog 4 and MFP to Digital3 on the MCP7940 and connect 5V to 5V, GND to GND and B1 to Digital8.

3. Connect your Arduino to your USB cable, and use the Arduino IDE to upload the “Bare Minimum” sketch from the Basics section of the Examples.

Preserving Settings on the MCP7940

In the event of a power loss (like the USB cable being removed from your Arduino), the MCP7940 will automatically move to the battery backup, provided by the CR2032 on the Education Shield. In order for this to occur, you have to set the third bit, VBATEN, in the RTCWKDAY register.

A power failure for the RTC is defined as Vcc dropping below VTRIP, listed in the datasheet as 1.5V. While running on the battery, the RTC will draw roughly 925nA so you should be able to sit in a disconnected state for quite some time. The detected power failure will cause a final time stamp to be written to the PWRDN time stamp registers and the chip will enter shutdown. When power is restored, and voltage rises above VTRIP, a time stamp is written to the PWRUP time stamp registers and the PWRFAIL bit is set. As long as that bit is set, the failure time stamps are maintained, but when the bit is cleared, those registers are emptied so that the next failure can be logged.

While in power down, the following items are preserved…

  1. Timekeeping functionality.
  2. All alarm configurations.
  3. Any current alarm output state.
  4. Oscillator trimming values.
  5. All RTC register and SRAM contents.

However, no I2C communications will be acknowledged (NACK on ninth bit after address if the RTC address is sent) and square wave output or GPIO functionality on the Multifunction Pin will be discontinued. Essentially, the MFP will continue to function as an alarm interrupt trigger, but not as a representative of the oscillator.

Testing the MCP7940 Battery Backup

The first thing we’ll need to do is make sure we turn on the VBATEN bit in RTCWKDAY. Let’s modify the init_MCP7940 routine to accomplish that. Remember, it’s bit 3, so we’ll need to take care not to change anything else in the register. We keep stuffing things into the initialization function though, so let’s move the actual I2C commands out into their own section, and just keep some easier to read calls to that function in the init routine.

You can see we create the register configuration entry for the battery backup by creating a batEnable variable, and setting it to 1, and then sending it to REG_RTCWKDAY. This will make the RTC aware that the battery is present. Also note that I’ve preserved the oscillator trim settings from the previous module.

The rest of the sketch is just a copy of the SetGetTime sketch developed in the second module, combined with the oscillator trimming feature and the use of a button press to set the time (we don’t want it resetting everytime the serial monitor window opens). Here it is in full…

The test is simple, really. Upload the sketch with the setTime values ready for a button press, open the serial monitor to make sure that the clock is running, press the button to set the time and close the monitor window, then yank the power. Wait a while, plug it back in, open the serial monitor and make sure the time is still accurate. Based on my oscillator trimming adjustment, I know I should be directly in synch to the second, for at least 15 hours.

There’s a delay of 1 second in the loop that will affect the button press, so you might have to hold it down a moment. Using delay is crude, yes, but it’s a fast way to prototype. If this was real production code, I would opt for displaying the time every 1000ms instead of using a hard delay.

And the test I just ran showed that it worked. Power was gone for about 20 minutes, and when it was restored, it was still completely in synch.

Did The Power Go Out?

If the power goes out but is restored before you notice, how can you tell? The answer is by polling the PWRFAIL bit to see if it reads as a 0 or 1. Combine that with an “if” statement and you’ll be ready to take some form of action in the event of a power drop.

PWRFAIL is bit 4 in RTCWKDAY, so we’ll check that each time through our loop to check it’s state and take action if it reads as a “1”. I’ve created a function called “CheckPowerBit()” to do just that. There’s a small difference here between what we’re doing in this sketch, and what we would do in reality. Since all of our output is confined to the serial monitor, which resets our Arduino each time we open it, we have to make sure that we’re not overwriting any values on reset. If we polled for a power failure directly in the main loop, and included a bit reset with debug output, that would execute when you restore the power, well before you had an opportunity to open up the serial monitor to see it happen. So instead, we’ll just make CheckPowerBit an indicator and save the power failure reset for a button press.

The first function is the CheckPowerBit function, which we call every time we go through the loop.

We immediately check the bit in the REG_RTCWKDAY register, and isolate the bit with a little bit masking. If the bit is set, we print to the serial monitor, and then start the LED’s blinking. Pin definitions, states and the LED pattern are all set in the declarations and setup as you would expect (you’ll see them in the full code below, but you should be familiar with how this works by now).

The next function is ResetPowerFail, which we’ll tie to the LATCH button to actually reset the power failure subsystem and report the time stamps to the serial monitor. This only happens on button press, which will allow us to track the output in the serial monitor.

We retrieve the power down and power up time stamps from their registers, and write them to two byte arrays (could have used one with four positions, but this made for easier reading). Then we clear the power failure bit that was set by the RTC when the USB cable was pulled by using the “Configure Register” function normally used in the initialization. The rest is serial output and turning off the LEDs again.

Of course we have to tie this all into the loop, so as you would expect, there is a CheckPowerBit call in it now, and a button press check routine for the PowerFailReset call.

And pulling it all together into the final sketch…

The test method is as follows…

  1. Press the DATA button to set the time with the SetTime function.
  2. Verify the clock is running in the serial monitor.
  3. Close the serial monitor and pull the USB cable.
  4. Wait a while, then plug your Arduino back in. You should see the LEDs dancing.
  5. Open the serial monitor, and you should see the correct time with the power failure message.
  6. Press the LATCH button to display the power failure time stamps and clear the power failure bit.