Is there a safe "latchable" way to cut power to SD cards on a data logger?

I have put together a low power logger with a Pro Mini, DS3231, and SD that only draws 68 micro-amps while sleeping.

I connected the DS3231 battery pin to 3.3V and left the DS3231 Vcc pin floating. The alarm interrupt works fine.

I wrote this file using the DS3231 to wake every 10 seconds. The total current into the 3.3 V regulator for the Pro Mini, SD card and DS3231 was about 68 micro-amps during the 10 second sleep periods.

2014-10-11 02:28:24
2014-10-11 02:28:34
2014-10-11 02:28:44
2014-10-11 02:28:54
2014-10-11 02:29:04
2014-10-11 02:29:14
2014-10-11 02:29:24
2014-10-11 02:29:34
2014-10-11 02:29:44
2014-10-11 02:29:54
2014-10-11 02:30:04
2014-10-11 02:30:14
2014-10-11 02:30:24
2014-10-11 02:30:34
2014-10-11 02:30:44
2014-10-11 02:30:54
2014-10-11 02:31:04
2014-10-11 02:31:14
2014-10-11 02:31:24
2014-10-11 02:31:34
2014-10-11 02:31:44

Here is the test program:

#include <Wire.h>
#include <DsRtc.h>
#include <SdFat.h>
#include <LowPower.h>
SdFat sd;
SdFile file;
DsRtc rtc;
time_t t;
//------------------------------------------------------------------------------
void rtcInterrupt() {
 detachInterrupt(0);
}
//------------------------------------------------------------------------------
void sleepUntil(time_t t) {
  if (!rtc.setAlarm1(t) ||
      !rtc.modify(DS3231_CONTROL_ADDRESS, 0XFF, 
                  DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE) ||
      !rtc.modify(DS3231_CONTROL_STATUS_ADDRESS,
                  DS3231_CONTROL_STATUS_A1F, 0)) {
    while(1);
  }
  attachInterrupt(0, rtcInterrupt, FALLING);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF); 
}
//------------------------------------------------------------------------------
void setup() {
  if (!sd.begin(SS) || !file.open("LOWPWR.TXT", O_RDWR | O_CREAT)){
    while(1) {}
  }
  Wire.begin();
  t = rtc.getTime();
  pinMode(2, INPUT);
  digitalWrite(2, 0);
}
//------------------------------------------------------------------------------
void loop() {
  t += 10;
  sleepUntil(t);
  rtc.printDateTime(&file);
  file.println();
  file.sync();  
}

I tried shutting down 32khz via the register, and it did not change the sleep current, nor did putting a pullup on 32khz line. Just thought that might have been a possible source of current drain.

From the datasheet:

"There are several modes of operation that affect the amount of VBAT current that is drawn. While the device is powered by VBAT and the serial interface is active, active battery current, IBATA (70μA at 3.3v - pg3 of datasheet), is drawn.

When the serial interface is inactive, timekeeping current IBATT (3.0μA at 3.3v), which includes the averaged temperature conversion current, IBATTC, is used.

Temperature conversion current, IBATTC (575μA at 3.3v), is specified since the system must be able to support the periodic higher current pulse and still maintain a valid voltage level. (refer to Application Note 3644: Power Considerations for Accurate Real-Time Clocks for details - for details on extending the time between temperature conversions to save power)."

If I assume that the eeprom is drawing 20μA, then 70μA for the rtc in active mode would explain my high current draw. But the mcu is sleeping in power down mode, so I have to find out why the clock thinks that I2C is still active while the units are sleeping. I did not find anything about I2C being forced active on Vcc in the data sheet…but I think your suggestion is a real possibility.

Or perhaps my ADXL or Eeprom is sending things along the I2C line, even when the mcu is asleep? and this keeps telling the rtc that the serial interface has to stay active?

Because of the way these boards are soldered, I would have to clip a pin on the IC to force the RTC to run on Vbat because I am using the vcc line as a pass through to power the other I2c devices. Will try that experiment and report back later.

Yep, if I simply cut the Vcc line to the RTC forcing it to run on Vbat , the logger draws 70uA less during sleep, but alarm functions and I2C comms still seem to be working.

So the question is, can I do this same thing less dramatically in software…

I connected Vcc to an Arduino pin and set that pin low during sleep. That way I can use a battery on Vbat. The DS3231 only draws high current, 78 μA, while the Arduino is awake.

I tried shutting down 32khz via the register, and it did not change the sleep current, nor did putting a pullup on 32khz line. Just thought that might have been a possible source of current drain.

I checked and the 32kHz doesn’t change the DS3231 battery current.

When the serial interface is inactive, timekeeping current IBATT (3.0μA at 3.3v), which includes the averaged temperature conversion current, IBATTC, is used.

My DS3231 is on a ChronDot board. It draws 0.85 μA except for the Temperature Conversion Current. I see the Temperature Conversion Current but can’t measure it since it is for a very short time period once every 64 seconds.

The datasheet claims the Temperature Conversion Time is typically 125 ms and draws 575 μA

The average Temperature Conversion Current is (0.125*575)/64 = 1.12 μA so my average DS3231 current is about 2 μA while sleeping.

If I power the DS3231 on Vcc while sleeping, it draws 78.8 μA.

This is my low power test program. I logs the date, time and one analog pin. It still draws 68 μA while sleeping.

#include <Wire.h>
#include <DsRtc.h>
#include <SdFat.h>
#include <LowPower.h>
//
// SD card chip select pin.
const uint8_t SD_CS_PIN = 10;
//
// RTC INT/SQW pin.
const uint8_t RTC_INT_PIN = 2;
//
// RTC primary power pin.
const uint8_t RTC_VCC_PIN = 3;

SdFat sd;

SdFile file;

DsRtc rtc;

// Time to wake from sleep.
time_t t;
//------------------------------------------------------------------------------
#define SERIAL_DEBUG 0
#if SERIAL_DEBUG
#define dbgMsg(msg) {Serial.println(msg); Serial.flush();}
#define error(msg) {Serial.print(msg); while(1);}
#else
#define dbgMsg(msg)
#define error(msg) while(1)
#endif
//------------------------------------------------------------------------------
void rtcInterrupt() {
 detachInterrupt(0);
}
//------------------------------------------------------------------------------
void sleepUntil(time_t t) {
  uint8_t r[2];
  
  // Enable interrupt for alarm one.
  r[0] = DS3231_CONTROL_INTCN | DS3231_CONTROL_A1IE;
  
  // Clear status bits and disable 32 kHz output.
  r[1] = 0;
  if (!rtc.setAlarm1(t) || !rtc.write(DS3231_CONTROL_ADDRESS, r, 2)) {
    error("sleepUntil");
  }
  // RTC to low power battery mode.
  digitalWrite(RTC_VCC_PIN, LOW);
  
  attachInterrupt(0, rtcInterrupt, FALLING);
  LowPower.powerDown(SLEEP_FOREVER, ADC_OFF, BOD_OFF);
  digitalWrite(RTC_VCC_PIN, HIGH);
}
//------------------------------------------------------------------------------
void setup() {
#if SERIAL_DEBUG
  Serial.begin(9600);
#endif

  // Power RTC with digital pin while not sleeping.
  pinMode(RTC_VCC_PIN, OUTPUT);
  digitalWrite(RTC_VCC_PIN, HIGH);
  
  if (!sd.begin(SS) || !file.open("LOWPWR.TXT", O_RDWR | O_CREAT | O_TRUNC)){
    error("SD setup");
  }
  Wire.begin();
  t = rtc.getTime();
  // should check for error
}
//------------------------------------------------------------------------------
void loop() {
  dbgMsg("loop");
  t += 10;
  sleepUntil(t);
  rtc.printDateTime(&file);
  file.write(',');
  file.println(analogRead(1));
  file.sync();  
}

Nick Gammon gives an example of powering a 1307 from a pin at:
Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors (about 1/2 way down)

But he uses a decoupling capacitor and a limit resistor. Did you get stable operation without those?

I will have to check on my battery current when the power pin is low. I still have an I2C accelerometer running even when the logger is asleep (providing interrupts), and am wondering if that would be generating enough noise to make the RTC think it still has to keep the I2C interface active this might mean that the battery is providing 70uA, instead of the <3uA when Vcc is low

And

Since my loggers are in caves, and the temperature does not change very quickly in that environment, I am setting the temp conversion time to 512sec as per application note 3644

i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit4_MASK);
i2c_writeRegBits(DS3231_ADDRESS,DS3231_STATUS_REG,1,Bit5_MASK);

But he uses a decoupling capacitor and a limit resistor. Did you get stable operation without those?

I get stable operation. I have not had a problem with noise. But the datasheet says you should use a 0.1μF to 1.0μF decoupling cap.

I am setting the temp conversion time to 512sec as per application note 3644

I thought only the DS3232/DS3234 allowed setting the "Temperature Update Time".

The app note is not very clear. It states:

The DS3232/DS3234 provide a bit field in a user-programmable register that allows the time between temperature updates to be increased, thus reducing the average current requirement. Both devices provide the C_Rate bit field in the Control/Status Register, which provides four different periods between temperature updates. This register is detailed in Table 1.

My Rev 9; 1/13 version of the DS3231 datasheet just shows zeros for the C_Rate field.

I tested this pin → VCC idea, and monitored the battery current. No funny power spikes on the battery to 70uA, and as expected, battery current dropped to zero whenever the Arduino was awake, and driving the pin supplying Vcc high. So no problems for powering the RTC with this method, even with some interference from an always on I2C sensor.

Ooops… I did not catch the DS3232/4 distinction in that app note. Have not seen any problems trying to write the registers though on the DS3231 so its probably just ignoring the write attempts.

When powering the DS3231 via its Vcc the current might be easily 70uA as you power the internal circuitry related to the Vcc / Vbat switching. Not sure they use simple diodes for Vcc/Vbat switching, but rather a mosfet stuff. So powering it via Vcc does not guarantee the ~1-2uA current you would expect.