Flash SD Card

Store up to 512 MB using SD Card libraries to this SPI Flash storage chip.   Handy when you need extra storage, small package, or you have a high vibration application and you don't want to use a regular SD card.  

Using a standard SD FAT library, I was able to write data at 2.74 ms/sample or 365 Hz if did a flush only after all of the data was written.   Writing followed by an immediate flush took 17 ms with a Feather 32u4 Basic Proto.  

Adafruit Product #4899

Adafruit Tutorial

Example code for running write test using SD Card library:


/*
  SD Card Speed Test Using Arduino Standard SD library

    NOTE: 
      Feather 32u4 Basic Proto:
        Typical SD write & flush takes 17 ms
        You can write multiple values over a period at 2.74 ms/sample 
        or 365 Hz if you flush only at the end of the period. 
 */

// In Arduino IDE, select 'Tools','Board','Adafruit Boards','Adafruit Feather 32u4'
// Find USB port in Windows by looking at ...

/////////////////////////////////////////////////////////////////////////
const byte pinBuiltInLED = 13;  

/////////////////////////////////////////////////////////////////////////
// blinkLEDnoDelay()
unsigned long LEDblinkPeriod = 8;
unsigned long LEDblinkLast = 0;
byte LEDblinkPWM = 0;
bool LEDblinkState = false;
byte LEDlastMode = 0;

void blinkLEDnoDelay(byte pin, byte mode) {
  // Blink the LED on 'pin' without using delay() according to
  // the 'mode' argument defined below. 
  // pin must support PWM. 
  // 
  // mode:
  //  0 = breathing
  //  1 = blink slow constantly
  //  2 = blink fast constantly
  //  3 = slow burst every 1 second
  //  4 = fast burst every 1 second
  //
  // Required global variables: LEDblinkPeriod, LEDblinkLast, LEDblinkPWM, LEDblinkState, LEDlastMode
  if (mode == 0) {
    // breathing
    LEDblinkPeriod = 8;
    if (LEDlastMode != mode) {
      LEDblinkPWM = 0;
      LEDblinkState = true;
      digitalWrite(pin, LOW);
    }
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        if (LEDblinkPWM > 254) LEDblinkState = false;
        if (LEDblinkPWM < 1) LEDblinkState = true;
        if (LEDblinkState) {
            LEDblinkPWM++;
        } else {
            LEDblinkPWM--;
        }
        analogWrite(pin, LEDblinkPWM);
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 1) {
    // blink slow constantly
    LEDblinkPeriod = 1000;
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        digitalWrite(pin, LEDblinkState);
        LEDblinkState = !LEDblinkState;
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 2) {
    // blink fast constantly
    LEDblinkPeriod = 100;
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        digitalWrite(pin, LEDblinkState);
        LEDblinkState = !LEDblinkState;
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 3) {
    // slow burst every 1 second
    // Slow 4 blinks (lazy burst) followed by 1 sec pause
    if (LEDlastMode != mode) {
      LEDblinkPWM = 0;
      LEDblinkState = true;
      LEDblinkPeriod = 100;
    }
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        if (LEDblinkPWM < 7) {
          if (LEDblinkPWM == 0) LEDblinkState = true;
          digitalWrite(pin, LEDblinkState);
          LEDblinkPeriod = 100;
          LEDblinkState = !LEDblinkState;
          LEDblinkPWM++;
        } else {
          digitalWrite(pin, LOW);
          LEDblinkPWM = 0;
          LEDblinkPeriod = 1000;
        }
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } else if (mode == 4) {
    // fast burst every 1 second
    // Fast 4 blinks (burst) followed by 1 sec pause
    if (LEDlastMode != mode) {
      LEDblinkPWM = 0;
      LEDblinkState = true;
      LEDblinkPeriod = 25;
    }
    if (millis() - LEDblinkLast >= LEDblinkPeriod) {
        if (LEDblinkPWM < 7) {
          if (LEDblinkPWM == 0) LEDblinkState = true;
          digitalWrite(pin, LEDblinkState);
          LEDblinkPeriod = 25;
          LEDblinkState = !LEDblinkState;
          LEDblinkPWM++;
        } else {
          digitalWrite(pin, LOW);
          LEDblinkPWM = 0;
          LEDblinkPeriod = 1000;
        }
        LEDlastMode = mode;
        LEDblinkLast = millis();
    }
  } // mode
}   // blinkLEDnoDelay()


void blinkLED(byte ledPIN){
  //  consumes 300 ms.
  for(int i = 5; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(30);
    digitalWrite(ledPIN, LOW);
    delay(30);
  }    
} //blinkLED()


void blinkERR(byte ledPIN){
  // S-O-S
  const int S = 150, O = 300;
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(O);
    digitalWrite(ledPIN, LOW);
    delay(O);
  }    
  delay(200);
  for(int i = 3; i>0; i--){
    digitalWrite(ledPIN, HIGH);
    delay(S);
    digitalWrite(ledPIN, LOW);
    delay(S);
  }    
  delay(200);
} // blinkERR()

/////////////////////////////////////////////////////////////////////////
// SD

// NOTE: Typical SD write & flush takes 20 to 30 ms

// Arduino standard SD library
#include <SPI.h>
#include <SD.h>
// SDCS (chip select) pin is #10 on 32u4
// SDCS (chip select) pin is #5 on M0 mounted to 480x320 TFT 3651 FeatherWing
const int SDchipSelect = 5;
File sdfile;
/////////////////////////////////////////////////////////////////////////

float fGetLgSignedRandFloat() {
  //long myLong = random(100, 999);
  long myLong = random(100000000, 999999999);
  long divisor;
  int expnt = random(2,6);
  switch (expnt) {
    case 2:
      divisor = 100;
      break;
    case 3:
      divisor = 1000;
      break;
    case 4:
      divisor = 10000;
      break;
    case 5:
      divisor = 100000;
    default:
      divisor = 10;
  }
  float f = (float)myLong / divisor;
  int sign = random(10);
  if (sign <= 5) {
    f = f * (-1.0);
  }
  
  return f;
}



/////////////////////////////////////////////////////////////////////////
// TimerA
// 10000000 us = 10000 ms = 10 sec = 0.1 Hz 
// 1000000 us = 1000 ms = 1 sec = 1 Hz
// 100000 us = 100 ms = 0.1 sec = 10 Hz
// 10000 us = 10 ms = 0.01 sec = 100 Hz
// 1000 us = 1 ms = 0.001 sec = 1 kHz
const unsigned long IntervalTimerA = 5000;  
unsigned long TimerALap = millis();  // timer

void TimerA() {
  if (TimerALap > millis())  TimerALap = millis();
  if (millis() - TimerALap > IntervalTimerA) { 
    // Write with immediate flush..
    digitalWrite(pinBuiltInLED, HIGH);
    unsigned long sdTimerStart = micros();
    unsigned long samples = 0;
    float f = fGetLgSignedRandFloat();
    sdfile.print(millis());
    sdfile.print(";");
    sdfile.println(f);
    unsigned long sdTimeElapsed = micros() - sdTimerStart;   
    // Execute a flush() to insure it is written since no sdfile.close() will be issued.
    sdfile.flush();  
    Serial.print(sdTimeElapsed); Serial.println(" us");
    Serial.print(float(sdTimeElapsed)/1000.0); Serial.println(" ms");
    Serial.print(1/(float(sdTimeElapsed)/1000.0/1000.0)); Serial.println(" Hz");
    Serial.println(" ");    
    digitalWrite(pinBuiltInLED, LOW);    
    TimerALap = millis(); // reset the timer
  }
} // TimerA()
/////////////////////////////////////////////////////////////////////////

void RecordEventToSdCard(unsigned long timerIntervalUs) {
  // Record an event of timerIntervalUs duration to the SD Card
  // (without flush between writing), then flush and report the
  // # samples written and the average sample rate. 
  
  unsigned long samples = 0;
  digitalWrite(pinBuiltInLED, HIGH);

  unsigned long sdTimerStart = micros();
  while (micros() - sdTimerStart < timerIntervalUs) {
    float f = fGetLgSignedRandFloat();
    sdfile.print(millis());
    sdfile.print(";");
    sdfile.println(f);
    samples++;
  } // while
  unsigned long sdTimeElapsed = micros() - sdTimerStart;
  
  // Execute a flush() to insure it is written since no sdfile.close() will be issued.
  sdfile.flush();

  Serial.print(samples); Serial.print(" samples in "); Serial.print(sdTimeElapsed); Serial.print(" us"); Serial.print("\t"); Serial.print(float(sdTimeElapsed)/float(samples)); Serial.println(" us/sample");
  Serial.print(samples); Serial.print(" samples in "); Serial.print(sdTimeElapsed/1000); Serial.print(" ms"); Serial.print("\t"); Serial.print(float(sdTimeElapsed)/1000.0/float(samples)); Serial.println(" ms/sample");
  Serial.print(samples); Serial.print(" samples in "); Serial.print(sdTimeElapsed/1000/1000); Serial.print(" s"); 
  Serial.print("\t"); Serial.print(1.0/(float(sdTimeElapsed)/1000.0/1000.0/float(samples))); Serial.println(" Hz");
  Serial.println(" ");
  
  digitalWrite(pinBuiltInLED, LOW);
  
} //RecordEventToSdCard();


void setup() {

  Serial.begin(115200);
  while (!Serial) {
    delay(1);
  }
  Serial.println("\nSerial ready");

  pinMode(pinBuiltInLED, OUTPUT);
  digitalWrite(pinBuiltInLED, LOW);
  
  if (!SD.begin(SDchipSelect)) {
    Serial.println("SD card failed, or not present");
    while (1) {
      blinkERR(pinBuiltInLED);
    }
  }
  Serial.println("SD card initialized.");
  // Create a filename reference to a file that doesn't exist 'ANALOG00.TXT'..'ANALOG99.TXT'
  char filename[15];
  strcpy(filename, "/ANALOG00.TXT");
  for (uint8_t i = 0; i < 100; i++) {
    filename[7] = '0' + i/10;
    filename[8] = '0' + i%10;
    // create if does not exist, do not open existing, write, sync after write
    if (SD.exists(filename)){
      Serial.print("File '");
      Serial.print(filename);
      Serial.println("' already exists");
    } else {
      Serial.print("New file will be '");
      Serial.print(filename);
      Serial.println("'");
      break;
    }
  }
  // Open file on SD Card for writing
  sdfile = SD.open(filename, FILE_WRITE);
  if (! sdfile) {
    Serial.print("ERROR - unable to create '");
    Serial.print(filename); Serial.println("'");
    while (1);
  }

  // Record an event to the SD Card and measure the average sample rate
  // (sample rate is limited by how fast the data can be written to the SD Card).
  // 10000000 us = 10000 ms = 10 sec
  unsigned long sampleDurationUs = 10000000;
  RecordEventToSdCard(sampleDurationUs);
    
  Serial.println("setup finished");
} // setup()


void loop() {

  blinkLEDnoDelay(pinBuiltInLED, 0);
  TimerA();

} // loop()

 


Do you need help developing or customizing a IoT product for your needs?   Send me an email requesting a free one hour phone / web share consultation.  

 

The information presented on this website is for the author's use only.   Use of this information by anyone other than the author is offered as guidelines and non-professional advice only.   No liability is assumed by the author or this web site.