Switching off SD cards for Low Power Data Logging

This composite graph compares logger current during identical sd.begin(), File Open & File Close sequences with two different Sandisk brand SD cards on the same datalogger. The 256MB card used less than 3mAs, while the 2GB card burned more than twice as much power during this initialization.

The tweaks I discuss in the  power optimization post bring sleep current on a typical build into the 0.1-0.12mA range; leaving the sleeping μSD cards  as the largest remaining power consumer on the Cave Pearl loggers.   And those cards have been a burr under my saddle for quite some time now, as they are probably responsible for most (if not all..) of the power consumption irregularities that were showing up in some of the battery voltage logs.

I already knew the various brands of SD cards could have dramatically different sleep current, but a comment in the Arduino.cc forum by William Greiman (the author of the SdFat library for Arduino) made me look a little deeper at what they were doing the rest of the time:

“Performance of microSD cards is not easy to predict on Arduino.  Arduino uses SPI to access the cards and the SD library has a single 512 byte cache. Modern SD cards are designed to be used on the high speed 4-bit SDIO bus with very large (16 KB or larger) multi-block writes and reads so they must emulate the single block access that Arduino libraries use.  This can mean much internal data movement, erasing of flash, and rewriting of data.”

This shows up clearly during data save events:

These screen captures of IDE serial potter output show current drawn during a data writing event with 256mB (left) and 2GB (right) Sandisk SD cards.  4kB of CSV format ASCII data was saved, and the gaps between the writing spikes were caused by i2c coms while SDfat’s cache was filled with data retrieved from the Eeprom on the RTC module. (click to enlarge)

After seeing that I tested a variety of different SD cards, finding that save event power use increased by more than 5x over the range from old 64 & 128mb Nokias to newer 2 & 4Gb Sandisk cards. 

It took me a good while to realize that I had fallen into yet another forest-for-the-trees situation, because even the worst offenders were only using ~30 mAs per save event, but all the cards were delivering similar sleep currents.  A day has 86,400 seconds in it, so the best sleepers, coming in around 70μA, were still burning six thousand milliamp seconds per day overall…

That brought me back to the question of de-powering those SD cards. I had been discouraged from trying this early in the project by some of Grieman’s other forum remarks where he suggested that there was nothing in the default SD library to support multiple shut downs & restarts safely.  But over time I found that Nick Gammon, and several others had card power control working with SdFat, and seeing the folks at OSBSS claim they had power cycled SD cards more than a hundred thousand times, was really the final straw.

As I had no logic level P-channel fets lying around I went with a garden variety 2n2222 BJT, configured as a ground side switch with a 30k pulldown. Driving it to saturation for 100mA loads using a 330 ohm base resistor would burn ten milliamp during the full second I needed to wait before pulling the plug:  Write latencies for SD cards can be quite large, and some cards have more than one stage of sleep, drawing around 1.0 ma for maybe a second before entering deep sleep.  But with 6000 mAs/day on the other side of the scale, I could afford the extravagance.

The cross leakage stuff I’d seen on EEVblog convinced me that I needed to actively pull up all of the SPI pins after the ground was disconnected. I cobbled together a set of  ON/OFF functions with pinmode commands, but it did not work reliably until I switched over to port manipulation (like they did at OSBSS), so the lines were all pulled simultaneously.  I was already disabling peripherals like the ADC with the PRR register, but that was just to save a little runtime power. Now it was required because when SPI is active, it controls MISO,MOSI & SCLK.  So you must shutdown the SPI interface before you set those pins directly.

#include <LowPower.h>
#include <avr/power.h>
#include <SPI.h>
#include <SdFat.h>
SdFat sd;                                   // Create the objects to talk to the SD card
SdFile file;
const byte slaveSelect = 10;   // sd card slave select on pin D10
#define SDpowerPin 9            // pin controlling the BJT on the ground line for the SD card
boolean SDcardOn = true;     // flag for error routines
byte  keep_SPCR;
// spacer comment for blog layout
void setup () {
keep_SPCR=SPCR;                  // save the default SPCR register contents
. . . }

void turnOnSDcard() 

 {
pinMode(SDpowerPin, OUTPUT); digitalWrite(SDpowerPin, HIGH); //turn on the BJT on SD ground line
delay(6);                                            // let the card settle
// some cards will fail on power-up unless SS is pulled up  ( &  D0/MISO as well? )
DDRB = DDRB | (1<<DDB5) | (1<<DDB3) | (1<<DDB2); // set SCLK(D13), MOSI(D11) & SS(D10) as OUTPUT
// Note: | is an OR operation so  the other pins stay as they were.                (MISO stays as INPUT) 
PORTB = PORTB & ~(1<<DDB5);  // disable pin 13 SCLK pull-up – leave pull-up in place on the other 3 lines
power_spi_enable();                      // enable the SPI clock 
SPCR=keep_SPCR;                          // enable SPI peripheral
delay(10);  SDcardOn = true;       // just a flag
}

void turnOffSDcard() 

 {
delay(6);
SPCR = 0;                                         // disable SPI
power_spi_disable();                     // disable SPI clock
DDRB &= ~((1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2));   // set All SPI pins to INPUT
PORTB |= ((1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (1<<DDB2));     // set ALL SPI pins HIGH (~30k pullup)
// Note: you must disconnect the LED on pin 13 or you’ll bleed current through the limit resistor
LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); // wait 1 second before pulling the plug!
delay(6);
pinMode(SDpowerPin, OUTPUT); digitalWrite(SDpowerPin, LOW);  //turn off BJT
delay(6); SDcardOn = false;


These two functions book-end any code that needs to write data to the SD cards:

turnOnSDcard();    flushEEpromBuffer();    turnOffSDcard();

All data saving functions start by checking the main battery to make sure there is enough power to save the data without a brown-out, and then re-initialize the cards with sd.begin before opening any files:

vBat = readBattery();   // This function shuts down the logger if the main battery is below 3.65V
if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
Serial.println(F(“Could NOT initialize SD Card”));Serial.flush();
error();  // note: the flag triggers:  if (SDcardOn) {turnOffSDcard();} in error function
}
delay(10);
file.open(FileName, O_WRITE | O_APPEND);  //see this post by Grieman
//…save your stuff…
file.close();


Looking at the datasheets for the Mic5205, or the Mcp1700,  you see the regulator dropouts can reach 300mV at 100mA+ currents you could see during SD card initialization, so your input cutoff for a 3.3V system needs to be above 3.65V to handle the load.   After the data is saved it is critical that all open files are closed properly before the turnOffSDcard function gets called, otherwise your data will be lost. The graphs tell me that a full one second delay before powering down the card is probably longer than it needs to be,  but in data logger applications it’s pays to err on the side of caution.

Lately I’ve been using these 60¢ SD adapters, and removing the bottom three 10k smds that these boards have on the SCLK, MOSI & MISO lines. (the other resistor keeps the ‘RSV’ pins from floating) Having a pullup on the clock line wasted power during mode o sleep as the clock idles low, but now that I’m cutting power rather than just sleeping the SD cards, I could leave those resistors in place…then I wouldn’t need to pull up those lines in the code, (though I’d still have to pull SS…)

Of course, it was pretty flakey the first few times I tried it. Half of the loggers seem to work, but the other half were restarting every time there was a data save event (killing off SD cards in the process…) This problem affected every logger built around the Rocket Scream Ultra, which has been one of my favorite small form factor boards.  Closer examination of the two-penny clones that were working ok revealed that they had 10μF tantalum capacitors beside the voltage regulator rather than the little 1μFs beside the Ultra’s MCP1700.  So those cards were hitting the rails pretty hard when the SD ground line was re-connected, and this caused brief transients that were low enough to restart the processor on half of my units. Some add a small (33Ω) resistor in series to limit these inrush currents, but I found that adding a 10μF (106) ceramic to buffer that spike got them all working ok, and for field deployment units I’ll probably add two.

I set a several units running on the bookshelf, with a rapid six second sampling interval. A couple of weeks later they were all still going, with some of them seeing more than 30,000 SD card power cycles without error. Given that the loggers normally see less than one save event per day, I’m calling that a successful test. If you run into issues, the first thing to try is extending that delay after sd.begin() and adding a few more delays throughout your functions. If you look at the spec you find that SD cards are allowed to take huge amounts of time for everything from initialization, to file open/close. While I did not see that in cards I used for my tests, these latencies are ‘officially’ allowed to stretch well beyond 100ms.

With both pin-powering on the RTC, and ground line switching on the SD card, the loggers get down to between 0.03-4mA between samples, which should push my operating lifespan into multi-year territory. Or, if I’m really lucky, they’ll make it through one winter-time deployment in Canada 🙂

I was also pleased to discover that the On/Off code seems to work on loggers that do not have the ground side switch installed provided I do not try to re-initialize the cards with sd.begin.  SPI shutdown & line pullup seems to cause the SD cards to enter sleep mode more quickly than they did before, and I have not seen any current leakage. So hopefully I won’t have to maintain vastly different code versions for older non-switched loggers. (Update 2017-06-12: Further tests of SPI shutdown, without the BJT to  disconnect power from the SD card have not been reliable. Some worked, some didn’t. When I figure out why that is I will post an update)

Addendum 2017-06-06

A commenter over at Dangerous Prototypes made a point about my use of the 2n2222 which is important enough that I should pass it on:

“I’m surprised he didn’t check the 2N2222. Look at its data sheet, the V(CE) performance is not great. Take 0.3V at 100mA, then the SD card would have been actually running at 3.0V, right at the -10% VCC rating edge. I’m surprised the problems are not worse. Of course it would be extremely sensitive to VCC sag…”

The drop across the collector-emitter was something I had simply missed, and I still struggle to read those datasheet graphs properly.  And I was so used to seeing card operating voltage specified between 2.7-3.6v, that I also missed the fact that in SPI mode, only 3.3v is officially supported. The net result is that I’m sailing closer to the wind here than I realized, and I’m going to call this technique “experimental” until I see real-world deployments saving more than a year of data safely. And if I stay with ground-side switching in future, I will start looking for a good logic level n-channel mosfet, with low on resistance, to replace that BJT.

This entry was posted in DIY Arduino Datalogger, The quest for low power. Bookmark the permalink.

15 Responses to Switching off SD cards for Low Power Data Logging

  1. zoomxx says:

    Great post, it’s long time that I am thinking about turning off the SD and have read about the problems about that. In this way you don’t need anymore to remove resistors from the adapter.

    • edmallon says:

      I think I will keep removing the 10K pullup resistors on MOSI, MISO & SCLK from that adapter, and using the internal pullups. Not that I really want to go through the headaches, but if I ever need to use SPI sensors (which might use any of the four different SPI modes), staying with processor side pullups leaves the the flexibility to change the configuration in future.

  2. moondrake says:

    Great Post!

    The ppl at OSBSS seem to require an older version of the SDlib to pull of the trick with shutting down reliably. I am doing the same with my own loggers now, but I would rather use the original library. Did you experience the same/ Could you comment on this?

    • edmallon says:

      Thank you for reminding me about versions!. I checked my sd fat version at: #define SD_FAT_VERSION 20160719, which is still the current one at github, and I’m using that with IDE version 1.6.9. I’m not sure what the differences are between the older vs newer SDfat libs, but I saw many people mention in the forums that they failed to get SD power control working with the default SD library that comes with with the IDE. If OSBSS did get it working with the default lib, then that’s the first time I’ve heard of it being done.

      WRT early vs later versions, I suspect that it all hinges on getting the timing right no matter what version you use, and that’s going to have as much to do with the SD card controller as anything on the Arduino side of things. According to Grieman, calling SD.begin at the wrong time always has the potential to smoke your card because it resets the controller. There are methods available to avoid problems like this in the SDIO spec, that can’t be implemented with SPI mode access that Arduinos use. When in doubt, add longer delays to let the card settle down before doing the next step.

      • zoomxx says:

        The default IDE library name is SD only, SDfat is another library. SD is derived from an older version of SDfat.

  3. moondrake says:

    Thanks for the reply. Interesting you got it to work with a recent version, because the OSBSS ppl insist it only works with < 20111205 (of the Grieman lib, not the really old SD lib that indeed had various problems). They offer a special download for this specific git checkout.

    There are problem reports in the OSBSS forums of ppl who tried with newer versions (though it also depends on the type of SD card it seems). So I guess I will have to run some test with the new version and sprinkle delays in case of problems. And perhaps you are doing something that makes it work better than the OSBSS code.

    I feel it is somewhat worrying the whole thing depends on timings so much.

    • edmallon says:

      Yep. And according to these folks, some cards require hundreds of ms between the moment they are powered up and the moment they are ready to communicate. Also, SD cards of all speeds and flavors, first wake up into the SPI mode, so my order here of powering the card before enabling SPI might be incorrect, though if those delays are really that long I’m probably fine with the timing anyway. I’m also generally using older 256mb uSD cards, and I think the older cards are more forgiving than the newer ones.

      I’ve also been wondering if I ought to set the bus to SPI_HALF_SPEED? Just for some safety margin?

      One factor that is repeatedly mentioned in the datasheets is that the power supply MUST be stable, but I already know from the restart problem that the v-regs on my Arduino boards struggle to handle the hit. And that’s not even mentioning all the other potential problems

  4. gerben123 says:

    Shouldn’t you turn off the BJT after you set the SPI pins to inputs with pull-up, instead of before?

    Any cross leakage will only be a few ns, but if done often enough, it might eventually damage the SD card. (Not sure how strong those clamping diodes are inside a SD card)

    • edmallon says:

      I think you are right, especially if SCLK is being held low in mode0 on idle by the SPI peripheral. Once the main ground is gone, then that becomes the only grounded line – I will do some trials with the SPI shutdown being done first and see how those loggers behave.

      Update 2017-05-30: My preliminary tests show that it works with SPI shutdown done before the BJT in the turnOffSDcard function. I’ve updated the code in the post to reflect that. More extensive tests underway now.

  5. Gabriel says:

    Hi Mr. Mallon,

    We are geography master students from Montreal university currently conducting some field work in the Arctic close to Iqaluit, Nunavut.

    We built some data loggers (Pro-mini AT mega328 3.3v, same cheap SD adapter presented on this page and rtc) and pressure sensor (MS-5803 5ba). We followed your tutorial and are really grateful for your amazing work. We use exactly the same wiring as you presented in that tutorial: https://edwardmallon.wordpress.com/2016/10/27/diy-arduino-promini-data-logger-2016-build-update/

    We are now struggling with power consumption problems and the sketch to put the sd.card adapter on sleep mode. We first tried this sketch :

    [ ———-pages of code removed here by Ed. M.———— ]

    But we still have the same problem, when we turn LOW the port D3 or SDpowerPin, the data stops being written on the sd card..

    Can you help us with that, do you have an idea of what could be the problem…

    • edmallon says:

      Hi Gabriel,
      Sorry for deleting your code here, but it was very long and would have prevented people from seeing the rest of the comments. In future try posting your code to GitHub, or some other platform like that so you can share big lumps of code more easily. There is also expert advice available over at the Arduino.cc forum as well, and their moderators have helped me many times.

      WRT the sd card saving, the most important part that you left out was that you did not re-initialize the SD card before trying to open the file:

      if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
      Serial.println(F(“Could NOT initialize SD Card”));error();

      //add your own error function
      }
      delay(10);

      If you de-power the SD cards you must call sd.begin BEFORE you try to open files with

      File dataFile = sd.open(“datalog.txt”, FILE_WRITE);

      Also, you are powering & depowering the SD card for every single reading, which from the looks of your loop delay, means you capture data every 8 seconds? I know that the folks at OSBSS saved data on every read cycle but I would only ever power cycle the SD cards that frequently for testing. On an actual deployment I buffer data to the EEprom on the RTC board so that data only gets written to the SD cards once per day. I don’t know how may power cycles the cards were designed for, but I’m sure 10,000 per day is too much.
      ———————–
      I’ve tried to convey that depowering the SD cards is the power saving technique with the highest potential risk, but if you are going to do it I’d reccomend that you implement it in three stages:

      1) first get your logger code working WITHOUT SD depowering at all, or SPI shutdown. Just let the cards sleep normally and see what kind of sleep current you get. Once you get below ~0.18 mA sleep current, then the logger will probably run for more than a year on 3AA batteries, and you might not even need to do the SD card shutdown at all. Adding a second parallel bank of batteries is also a simple solution with no risk to your data.

      2) Once your logger is capturing data, and saving it properly, the next step is to add ONLY the code for SD depowering (but not the BJT disconnecting the ground line) and see if you can get that working without calling sd.begin in your data writing functions. In my tests the code above works fine in loggers without the BJT installed, but I am also sleeping the loggers with Gammon’s sleep code (Sketch J) , because I did not know if the Rocketscream sleep library would try to turn the SPI peripheral back on when the unit woke up.

      3) If the SPI shut-down & Card Re-initialization work with the ground line still connected, then the last step would be to solder the BJT into place, so that the SD card ground line is actually disconnected while the logger is sleeping. Note that I am using old 256mb Sandisk cards, which might actually handle this depowering better than the newer high density cards.

      —————-

      P.S. I also noticed that you were shutting down timer0. Personally, I never mess with timer0 – it gets used in many important functions that are beyond my current coding ability to deal with if they stop working properly. Also be sure to use lithium AA batteries, rather than alkaline batteries, as they have much better cold weather performance.

  6. It’s nice, I’ve tried to do datalogger this way last year, it’s almost complete (I sort of lost intereset after building prototpe) and code is here: https://github.com/pavel-perina/weather_logger .

    I remember that I’ve used some P-MOSFET and NPN? to disconnect SD-Card module (with voltage regulator) from batteries and I’ve tested power consumption and ability to provide something over 150mA in ON state. Then I used this to shutdown power to SD card module, wired everything and left it to run for day. Then I measured that batteries won’t last week, build simple oscilloscope (arduino+INA219 chip sending measured current over serial line like crazy), used gnuplot to draw graph (here http://i.imgur.com/gfXQ0pZ.png ) and it seemed like power was not shut down once sd card was initialized. To my surprise, current was somehow able to flow through pins on sleeping arduino, through SD card and voltage regulator to ground (if I remember correctly.) Then I’ve changed SPI pins to input, waited shortly, shut down power to sd card module with transistors, put arduino to low power sleep, problem solved. I believe only remaining problems are mechanical and I remember I wanted to replace mosfet by another one that can operate at lower voltage.
    Now I decided to make it work again and to complete documentation. To my surprise you decide for the same approach
    ———–
    By the way have you tried to solve how to shutdown logger forever, once battery voltage drops below some threshold

    • edmallon says:

      With my sleep current being so low now I just to sleep with the brown out detection enabled when the main battery pack approaches the regulator’s input limit. That usually gives me many months before the cells get low enough to risk leaking. Trish never wants to wait much more than a year for her data anyway, so we rarely run the batteries to that point unless their is a sensor failure that somehow pulls the logger down.

      So I’m not implementing a full power shut down yet, but when I get there I’ll use something like Kevin Darrah’s kill power circuit, as that’s a nice straight forward implementation. But there are plenty of others out there to choose from. The key is making the circuit really stable/ON for loggers being bounced around on an installation dive.

  7. rocketscream says:

    Hi Edward,
    Great write up here (had the same struggle few years back while using SD card for logging). I personally would use serial flash for data logging due to it’s robustness and ultra low power (1-2 uA during sleep). Paul Stoffregen’s SerialFlash library would allow you to read/write files just exactly like how you did with the SD card. I’m not sure about the size you need though but 32MB is pretty easily available at decent price.
    Thanks for good word on the Mini Ultra!!!

    • edmallon says:

      Thanks for the tip about that library, which looks like it would make the transition from SD to EEPROM much easier. I’m pretty sure I could fit the data in there if I switch over to C-structs, but I’m still wrapping my head around that. The choice to use SD cards was largely driven by field logistics, where simply swapping batteries & cards makes on-site servicing (1 hour or more into a cave) much easier. The trifecta here will be when I transition to Serial flash, structs & an optical modem with a transfer window so I can retrieve the data from the units while they are still in place. But I’m probably a few years from pulling that all together, as current push is for new sensor development, and that is one long laundry-list of projects…

      With your power management library, the Mini Ultra has long been one of my two favorite compatibles, with the other being Felix’s Moteino Mega for situations where I need the 1284P’s ram for things like circular buffers, etc. The old guard seem to have a real dislike of the Arduino system, and they keep telling me to switch over to a raw AVR. But having the v-reg & caps in place, with the pins broken out, just makes the kind of loggers I’m assembling much easier. Like the eeprom change over, I will probably get to a custom PCB eventually, but if I do it will only be because I built on the work of others, and the wonderful variety of boards in the open source ecosystem.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s