Go Down

Topic: software SPI for mega with Sdfat library (Read 9904 times) previous topic - next topic


Jul 07, 2011, 03:18 pm Last Edit: Jul 07, 2011, 03:20 pm by VroomVroom Reason: 1
Hi all,

Just a question in regards to using software SPI on the mega with a sparkfun SD shield.. I have some code that worked with the deumi to get analogreads and store to sd card at 2.5kHz+. Just wanted to use the same shield with the mega as it provides more analog ins and ISR enabled digital pins.

Used the latest version of the Sdfat library with the removal of the // before #define MEGA_SOFT_SPI and setting it nonzero (in SdfatConfig.h) so it looks like this:
Code: [Select]
#define MEGA_SOFT_SPI 1

and ran following:
Code: [Select]
//Add the SdFat Libraries
#include <SdFat.h>
#include <SdFatUtil.h>
#include <ctype.h>

//Define Pins
int pot1Pin = 8;
int pot2Pin = 9;
int start;
long n = 0;

//Create the variables to be used by SdFat Library
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

char name[] = "log.csv";     //Array that contains name of file.
char contents[32];           //Data buffer for writing contents to the file.

#define FASTADC 1

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

void setup()
 pinMode(8, OUTPUT);       //Pin 8 must be set as an output for the SD communication to work on sparkfun shield.

 card.init();               //Initialize the SD card and configure the I/O pins.
 volume.init(card);         //Initialize a volume on the SD card.
 root.openRoot(volume);     //Open the root directory in the volume.
 // set prescale to 16
 sbi(ADCSRA,ADPS2) ;
 cbi(ADCSRA,ADPS1) ;
 cbi(ADCSRA,ADPS0) ;
 //Create header
     file.open(root, name, O_CREAT | O_APPEND | O_WRITE);    //Open or create the file 'name' in 'root' for writing to the end of the file.
     sprintf(contents, ", , \nPOT1, POT2");    
     file.println(contents);                                 //Write the 'contents' array to the end of the file.
 start = millis();

 while (millis()-start <= 1000){
     sprintf(contents, "%i, %i", analogRead(pot1Pin), analogRead(pot2Pin));;    

void loop(){

Tried the above as well as changing pin 10 to output (rather than pin8) and pin 53 as well just in case and still no file being written at all.


This is correct:
Code: [Select]
#define MEGA_SOFT_SPI 1
Remove this line
Code: [Select]
  pinMode(8, OUTPUT);       //Pin 8 must be set as an output for the SD communication to work on sparkfun shield.
and change this line
Code: [Select]
  card.init();               //Initialize the SD card and configure the I/O pins.
to this
Code: [Select]
  card.init(SPI_FULL_SPEED, 8);               //Initialize the SD card and configure the I/O pins.
The first argument, SPI_FULL_SPEED, does nothing in soft SPI mode.  Soft SPI goes as fast as it can no matter what the first argument is.

I checked this with the new SdFat, http://code.google.com/p/sdfatlib/downloads/list, but it should work with older versions also.


I was hoping you would reply, cheers mate! I tried what you suggested - didn't work as is. Tinkered around a bit more and added an extra line as follows:
Code: [Select]
card.init(SPI_FULL_SPEED, 8);              //Initialize the SD card and configure the I/O pins.
  volume.init(card);                         //Initialize a volume on the SD card.
  root.openRoot(volume);                     //Open the root directory in the volume.

and now it is going beautifully. Must be to do with the mega requiring pin53 to always be an output.

Continuing the discussion about read speeds and soft SPI, do you know what kind of speed differences there are between using this method to using jumpers between pins 50-53 and 10-13 on the mega to sd shield?

I read your waverp library and example which you mention on a few posts as a method where you've used interrupts and 512 byte buffers to write at high speeds to sd, however at this stage it requires more knowledge of C programming than I currently have :(.

A more detailed description of what I am trying to achieve overall is here: http://arduino.cc/forum/index.php/topic,65916.msg482948.html#msg482948

Are using interrupts for my application a good way to go? Debounce issues? and if they are fixed in software with delays will there be a limit to how quickly ISRs can run? Sorry for the barrage of questions, but any advice is much appreciated! (the software part of my project has to be completed in the next couple of weeks!)


SdFat does not touch pin 53 in soft SPI mode so output mode should not be needed.   You should never need to set pinMode for pins SdFat uses.

Your program runs fine on my Mega with the pin 53 line commented out.

A lot of topics have been posted about setting pinMode for SdFat but most are wrong. 

The only thing you need to do is set pinMode to output for other SPI device's chipSelect and set the other device's chipSelect high so they don't interfere with the SD.

There are some high speed data logging examples for the new version of SdFat here http://code.google.com/p/beta-lib/downloads/list.

Soft SPI mode runs about 1/3 as fast as hardware mode.

I suspect you will have latency problems if you need to log more than a few samples per second unless you use interrupts to capture data.


Ok cheers I will test that. And have a look at those examples.. Can you use interrupts to count the number of pulses on a digital pin? and will this type of sampling be evenly distributed in a given time period. The reason I ask is a hall effects sensor say, will pulse a pin 20+ times a second and if a counter measures this accurately over a given fixed time interval, I would be able to calculate and log an instantaneous angular velocity/acceleration. Depends really on whether interrupts can be made to work like that?


SdFat does not use or disable  interrupts with hardware SPI but does disable interrupts while sending one byte with software SPI. 

I don't thinks that will be a problem since it it takes about five microseconds to transfer a byte with software SPI. 

The Arduino timer zero interrupt probably adds more jitter to counting pulses.

Go Up