Go Down

Topic: SPI problem with adafruit SD shield & Mega (Read 4581 times) previous topic - next topic

oscarcar

Jun 04, 2011, 02:45 am Last Edit: Jun 04, 2011, 02:55 am by oscarcar Reason: 1
I assembled one of the adafruit SD shields to use on my Arduino Mega board.

http://www.ladyada.net/make/logshield/sd.html

Example below (not mine):


I think my soldering job is pretty decent and I can't find a problem with the traces. Unfortunately I don't have an oscilliscope yet, which I really should get.

I'm having some difficulty understanding the SPI connection to the unit.

At first, I assumed that the shield would work cause I thought these shields were compatible.
I think compatible just means that it will connect up with the board, but the SPI pins won't match.

I can communicate with the board over USB, and it says it can't read the card.
It's probably not a card issue, cause I've used a couple, including a 16MB card that was specifically FAT-16 formatted.

From what I gather (which could be quite far off), is that I should use the ICSP header to connect up the SPI pins.

I can't determine which is pin1 on the ICSP header on the SD shield from any docs, to match them up. Now that I'm typing this I guess I should do a continuity test to figure it out.

Should I have not soldered on the header for pins 10,11,12,13? Cause then I would be bridging pins 10-13 with pins 50-53? If so, it would seem odd to design a board that way. Again, I'm likely misunderstanding something here.

By connecting the ICSP header on the SD shield, am I somehow bypassing pins 10-13, so that there isn't a bridge occurring?

Another thing is I've added this to the SPI.h header to match the SPI pins for the Mega:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1276117813

Code: [Select]
#if  defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
 #define SCK_PIN   13
 #define MISO_PIN  12
 #define MOSI_PIN  11
 #define SS_PIN    10
#endif

#if defined(__AVR_ATmega128__) || defined(__AVR_ATmega1280__)
 #define SCK_PIN   52
 #define MISO_PIN  50
 #define MOSI_PIN  51
 #define SS_PIN    53
#endif



Thanks for providing any clarity. I've been trying to read everything I can find on here and elsewhere.

edit: I realized I should of shown the code I was using:

Code: [Select]

/*
  SD card test
   
This example shows how use the utility libraries on which the'
SD library is based in order to get info about your SD card.
Very useful for testing a card when you're not sure whether its working or not.

The circuit:
  * SD card attached to SPI bus as follows:
** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
** CS - depends on your SD card shield or module


created  28 Mar 2011
by Limor Fried
*/
// include the SD library:
#include <SD.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
const int chipSelect = 10;

void setup()
{
  Serial.begin(9600);
  Serial.print("\nInitializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output
  // or the SD library functions will not work.
  //pinMode(10, OUTPUT);     // change this to 53 on a mega
  pinMode(53, OUTPUT);

  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
//  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
  if (!card.init(SPI_QUARTER_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
   Serial.println("Wiring is correct and a card is present.");
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
 
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

 
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
 
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
}


void loop(void) {
 
}





johnwasser

You should jumper from 11,12, and 13 to the corresponding SPI pins on your Mega (either 51, 50, and 52 or the three SPI pins of the ICSP header).  You should not use 11, 12, or 13 as outputs.  Leave them as inputs so they don't interfere with the Mega's SPI signals.

The Slave Select (SS) pin (10) is not controlled by the SPI hardware and can be ANY output pin.  The shield has SS connected to pin 10.  This is REGARDLESS of being a Mega or not.  No need to jumper that pin.  Make sure you don't set Pin 53 as an input because that will configure the Arduino Mega as an SPI slave device.
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

oscarcar

OK. Thanks for the guidance.

So, I can just use the jumper points on the board (holes adjacent to the header pins) to go to the Mega SPI pins?
I hope that's clear, I don't know the terminology for these things.

Is it better to just cut the header pins off for pins 11, 12, & 13? I hope to run this at some pretty high communicate rates, so would having those pins connected to other inputs have any undesirable effects?

Thanks.

johnwasser

> So, I can just use the jumper points on the board (holes adjacent to the header pins) to go to the Mega SPI pins?

Yes.

> Is it better to just cut the header pins off for pins 11, 12, & 13?

If you connect to the ICSP header (it IS connected through to the Arduino board, right?) then you can cut off the headers for 11-13 and still use the shield on a regular Arduino.

> I hope to run this at some pretty high communicate rates, so would having those pins connected to other inputs have any undesirable effects?

It should be OK with the Arduino Mega's input pins connected to 11-13.

Thanks.
[/quote]
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

oscarcar

Still no luck.

I did run a sketch and determined that the RTC seems to be OK on the board, which works over i2c.

I think I should get ANYTHING to run with SPI first to make sure that it's working, and that I understand it better.

What is the easiest way to test the SPI?
Should I hook it up to a 9-pin serial port to the SPI pins and connect it up to my PC?
Is it possible to do that easily or is there difficulties with the communication rates?

The digipot seems the best simple example I've seen.

johnwasser

Unfortunately an SPI device, other than an SD card, is not something you are likely to find sitting around the house.

Perhaps by modifying the SPI.h file you have caused the software to use pin 53 for the Slave Select pin instead of pin 10.

SPI is not an asynchronous serial connection so you can't just hook it up to a PC serial port with some level shifters.
Send Bitcoin tips to: 1L3CTDoTgrXNA5WyF77uWqt4gUdye9mezN
Send Litecoin tips to : LVtpaq6JgJAZwvnVq3ftVeHafWkcpmuR1e

oscarcar

Ok. I got a MCP3208 ADC chip working with SPI.

I can get real values and I'm communicating at 2Mhz.

Now back to the SD shield. I can try taking out the changes in SPI.h, but the MCP3208 worked fine,
and I actually pulled out the shield and routed everything exactly where I wanted it to go: 50-53 pins.

I'm going to play with the communication rate, as I read that the SD card can be touchy and only gets initialized at certain rates or something similar.

fat16lib

SD.h is a wrapper for my SdFat library.  SdFat can be used with no hardware mods on the Mega with the Adafruit shield.

SdFat has an option to use software SPI.  At about line 42 of Sd2Card.h set
Code: [Select]
#define MEGA_SOFT_SPI 1

If you use hardware SPI, SdFat sets SPI options independent of SPI.h since different speed is required for initialization and data transfer so you don't need to mess with SPI options.

oscarcar

Thanks for the info.

I'll try the soft SPI, and see if that works.

I don't know how much more overhead that is, hopefully it will be OK.

I'm unclear on what is meant by:

Quote

SdFat can be used with no hardware mods on the Mega with the Adafruit shield.


Do you mean that it has to be pins 10-13 for SPI, cause it's hardcoded somewhere in SdFat library that I'm not aware of?

I pulled off the shield and routed the headers to the 50-53 pins, and GND and 5V directly to the arduino.
I didn't think I needed the 3V pin connected, but I could be wrong about that.

oscarcar

I looked thru your SDfat code, and I'm not following it too well. I'm not used to reading #include guard but it looks to me that MEGA_SOFT_SPI is zero, so SOFTWARE_SPI is also undefined, which then calls the SOFTWARE_SPI commented section, which hardcodes to pins 10-13.

In short, it seems that the SOFTWARE_SPI section of hardcoding the pins, only gets called if MEGA_SOFT_SPI is set to zero. If it was set to non-zero, it would use the SPI pins for the board.

Code: [Select]

/**
* Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos.
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
*
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
* on Mega Arduinos.  Software SPI works well with GPS Shield V1.1
* but many SD cards will fail with GPS Shield V1.0.
*/
#define MEGA_SOFT_SPI 0
//------------------------------------------------------------------------------
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
#define SOFTWARE_SPI
#endif  // MEGA_SOFT_SPI
//------------------------------------------------------------------------------
// SPI pin definitions
//
#ifndef SOFTWARE_SPI
// hardware pin defs
/**
* SD Chip Select pin
*
* Warning if this pin is redefined the hardware SS will pin will be enabled
* as an output by init().  An avr processor will not function as an SPI
* master unless SS is set to output mode.
*/
/** The default chip select pin for the SD card is SS. */
uint8_t const  SD_CHIP_SELECT_PIN = SS_PIN;
// The following three pins must not be redefined for hardware SPI.
/** SPI Master Out Slave In pin */
uint8_t const  SPI_MOSI_PIN = MOSI_PIN;
/** SPI Master In Slave Out pin */
uint8_t const  SPI_MISO_PIN = MISO_PIN;
/** SPI Clock pin */
uint8_t const  SPI_SCK_PIN = SCK_PIN;
/** optimize loops for hardware SPI */
#define OPTIMIZE_HARDWARE_SPI

#else  // SOFTWARE_SPI
// define software SPI pins so Mega can use unmodified GPS Shield
/** SPI chip select pin */
uint8_t const SD_CHIP_SELECT_PIN = 10;
/** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = 11;
/** SPI Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = 12;
/** SPI Clock pin */
uint8_t const SPI_SCK_PIN = 13;
#endif  // SOFTWARE_SPI
//------------------------------------------------------------------------------

fat16lib

#10
Jun 10, 2011, 01:45 pm Last Edit: Jun 10, 2011, 01:48 pm by fat16lib Reason: 1
If you define MEGA_SOFT_SPI nonzero, software SPI will be used on ATmega1280 and ATmega2560 processors.  You can then use the Adafruit Data Logging Shield with no hardware mods.  No extra wires connecting the shield SPI pins to the Mega hardware SPI pins 50, 51, 52, 53.  You must use pin 10 as chip select in your begin/init call.

Software SPI is highly optimized and runs fast enough for most data logging applications.  I tested an Adafruit Data Logging Shield with a Mega 2560.

I ran the SdFat benchmark sketch with two mods.  I set MEGA_SOFT_SPI = 1 and used pin 10 for chip select in the init call.  The result was:
Quote
Type any character to start
Free RAM: 6757
Type is FAT16
File size 5MB
Starting write test.  Please wait up to a minute
Write 81.18 KB/sec

Starting read test.  Please wait up to a minute
Read 102.04 KB/sec
Done


If you wish to use the hardware SPI pins don't modify SdFat or anything else like SPI.h.  Just connect MISO, MOSI, and CLK on the shield to the mega pins 50, 51, and 52.

You can then use any pin for chip select.  If you run a wire to Slave Select, SS, on the Mega use pin 53 in your begin/init call.  If you don't run an extra wire and use the Adafruit pin, use pin 10 in the begin/init call.

Hardware avr SPI uses 5 pins.  MISO, MOSI, CLK, SS, and chip select.  SdFat sets SS, Slave Select, to an output even if it is not used as chip select since the avr hardware SPI will not function in master mode if SS is an input and goes low.

oscarcar

#11
Jun 10, 2011, 11:20 pm Last Edit: Jun 10, 2011, 11:36 pm by oscarcar Reason: 1
Ok, I reverted everything back and tried the soft spi first. It works!

That's a relief. The LEDs don't do anything, so maybe I burned them out when soldering.

It didn't like a 16MB card I had, so I think that was also tripping me up.

I am going to end up pushing the limits of data logging, so do you have any idea of how much would be gained by using hardware SPI? I will be sampling an ADC over hardware spi and trying to grab as many samples as possible and push them to the SD card.

And, would it work to seperate these out to test for SPI connectivity and separately card compatibility?
Or are they tied inextricably?

Code: [Select]

boolean SDClass::begin(uint8_t csPin) {
 /*                                                                            
                                                                               
   Performs the initialisation required by the sdfatlib library.              
                                                                               
   Return true if initialization succeeds, false otherwise.                    
                                                                               
  */
 return card.init(SPI_HALF_SPEED, csPin) &&
        volume.init(card) &&
        root.openRoot(volume);
}


I tried to see if I could test for SPI connectivity with the card it didn't like (but was formatted by my PC ),
but it seems to fail SPI test too.

Thanks again!

edit: Nevermind on the LEDs, I see that they are for use by one's own project not for indicating read/writes.

fat16lib

#12
Jun 11, 2011, 12:10 am Last Edit: Jun 11, 2011, 12:14 am by fat16lib Reason: 1
The 16 MB card may have been formatted FAT12.  The SD standard requires 16 MB cards to be FAT12 and I don't support FAT12.

You can reformat it FAT16 and the best way is to this is to use the formatter in the new beta of SdFat here http://code.google.com/p/beta-lib/downloads/list.

You will never log data very fast if you share the SPI bus between an ADC and a SD card so software SPI should be used for either the ADC or SD card.

To log data fast you need to read the ADC in an interrupt routine and buffer data to be sent to the SD card.

I wrote a library to record/play audio at 44100 8-bit samples per second using the Arduino ADC for record and a SPI DAC for play.  This library reads the ADC and write the DAC in an interrupt routine.  The library is here http://code.google.com/p/waverp/.  You can't use it for your app but could look at its structure.

I use special raw I/O to contiguous files for max speed.  These are not available in the Arduino SD.h wrapper so you may want to use SdFat directly.  The new beta has better diagnostics for initialization problems.

See this also http://arduino.cc/forum/index.php/topic,63100.0.html.

oscarcar

I did have it formatted for FAT-12, but I also changed the partition to FAT-16 & formatted for dos. Still no go.

I'll try what you suggest.

I've gotten a 12-bit ADC to sample at about 40Khz over SPI, and I only want about 4Khz.
I'm hoping to buffer several 2-byte samples and then write out chunks to the SD card.

I'm not sure how to keep the samples evenly spaced in time, if I occasionally am writing out chunks to the SD card.

I'll take a look at your code for a better idea of how to do this.

fat16lib

To get even time spacing I use timer one to drive the read interrupt.

You need to buffer 512 byte blocks.  This matches the size of SD blocks and will avoid rewrite of SD flash which kills performance.

Go Up