chipKIT® Development Platform

Inspired by Arduino™

SD Examples Updated

Created Tue, 30 Apr 2013 14:06:49 +0000 by Jacob Christ


Jacob Christ

Tue, 30 Apr 2013 14:06:49 +0000

I recently changed the SD examples from something like this:

const int chipSelect = 8;

void setup() { Serial.begin(9600); Serial.print("\nInitializing SD card..."); pinMode(10, OUTPUT); // change this to 53 on a mega

to something like this (changed literal 10 to chipSelect):

const int chipSelect = 8;

void setup() { Serial.begin(9600); Serial.print("\nInitializing SD card..."); pinMode(chipSelect, OUTPUT); // change this to 53 on a mega

Talking with one of the guys I work with, he thinks that the pin 10 output is set to make sure the library works when you use the code with some Arduino boards. So I was thinking about changing it to something like this:

const int chipSelect = 8; // CS pin for SD card const int slaveSelect = 8; // Slave Select line (maybe same as CS or different)

void setup() { Serial.begin(9600); Serial.print("\nInitializing SD card..."); pinMode(chipSelect, OUTPUT); pinMode(slaveSelect, OUTPUT);

Any thoughts or suggestions?

Jacob


Jacob Christ

Thu, 02 May 2013 17:27:35 +0000

Here is a conversation between Keith (from Digilent) and myself on this topic...

Keith:

I looked at the schematics for an Arduino UNO at http://arduino.cc/en/uploads/Main/arduino-uno-schematic.pdf, you will notice that PIN10 is the CS line that is routed for external SPI CS control as well as to the CS on the Arduino SPI connector. Also notice that the chipKIT Uno32 does the same thing. Pin 10 is sort of the defacto SPI CS for Arduino SPI devices.

HOWEVER, for example, the WiFi shield has 2 SPI devices on it, the WiFi module AND the SD card; and they BOTH share SPI2. So they both could be used at the same time; 2 different CS had to be picked. By default the WiFi module got the typical pin10 CS signal that Arduino uses for most SPI devices; but the SD card got pin4, not the standard Arduino CS for a single SPI device. The assumption is… there very likely could be a second and shared SPI device on the standard Arduino SPI port and you need to make sure you DON’T select it while using the non-standard SD card. You can’t have the other CS line just float. So you want to explicitly hold that other SPI device’s CS HIGH (Deselected).

Now, for chipKIT and because of the WiFi Shield, we really should have code that looks like…

pinMode(4, OUTPUT);            // CS for the SD Card on a WiFi Shield
digitalWrite(4, HIGH);              // Start off deselected
pinMode(10, OUTPUT);          // Standard Arduio CS, used by the WiFi module on a WiFiShield
digitalWrite(10 HIGH);             // Start off deselected

Fortunately, both the SD and DWIFIcK libraries initialize deselected; but if you are not using one of the libraries AND you are using a WiFiShield, setting the pin as an OUTPUT WITHOUT setting it HIGH can be a real problem. It is better to leave it as an INPUT (tri-stated; do nothing) as there are pullup resistors on the WiFiShield to hold the devices deselected. But if you set it as an output, that pin gets driven and you might drive it LOW (selected) So if you are going to set pin 10 as an output, set it high too to deselect the WiFi module.

In general, Digilent has put all of the chipKIT SD card readers on CS pin 4 and leaving open the Arduino SPI capabilities on CS pin 10. And in general, the WiFi module is on pin10, Hmmm… maybe we should have moved that to a different CS pin as well… well, it is what it is…

Slave Select to me is when you are acting as a Slave, so this would be an INPUT not an OUTPUT. I do not think your second solution is correct. I think when using the SD card, I would just add:

pinMode(10, OUTPUT);          // Standard Arduio CS, used by the WiFi module on a WiFiShield
digitalWrite(10 HIGH);             // Start off deselected

to turn any other shared SPI device (such as the WiFi module or other defacto Arduino SPI usage) OFF and DESELECTED. In general, putting nothing in for the WiFiShield is fine, but you don’t know what other people have put on the Arduino SPI ports and if they have pull up resistors or not. So it would always be safe to define pin10 as an output as long as you drive it high.

Jacob:

Thanks Keith... Your right I meant SD, too many things floating around in my head.

I see where the problem comes from.

So my goal in modifying the examples is of course to make it easier to get an SD card up and running for a new user. I've been writing a lab for the Fubarino SD for using the SD and when you run through all the SD examples they need to be modified in different ways from example to example. This would be the same if you were using a Uno32 or a Max32. So I was just trying to get all the examples to be consistent.

I only modified the PIC32 SD examples, didn't touch the Arduino ones at this time.

So rather than chipSelect and slaveSelect variables, maybe:

const int chipSelect_SD_default = 10; // Make 10 on Uno and 53 on a Mega (Maybe this should be an ifdef for detecting board type) const int chipSelect_SD_mine = chipSelect_SD_default; // can be changed if you do not use default CS pin

and in setup()

pinMode(chipSelect_my_SD, OUTPUT);
  digitalWrite(chipSelect_my_SD, HIGH);

  pinMode(chipSelect_default_SD, OUTPUT);
  digitalWrite(chipSelect_default_SD, HIGH);

Keith:

And you already caught the slight error in my response, clearly the defacto default for the Mega is pin 53 not pin 10. Also I should point out that we (Digilent) are coming out with a board where the SD CS will NOT be on pin 4. We actually dedicated signals to the SD and the WiFi so they would not share the SPI port (and thus get rid of the interrupt problem with the WiFi SPI implementation). Which brings us to your second observation/suggestion. Somehow we need to have a board definition for some of these common signals, maybe in the variants file? We are now producing boards with SPI stuff on them, and hard wire signals; and I think there is a clean defacto standard for Arduino for the Uno and Mega, so I would be in favor of some kind of Default_SPI_CS in the variants; and IF the board has resources on it like SD or WiFi we should have some standard names for them as well like WiFi_SPI_CS or SD_SPI_CS. We also need to add something if SPI interrupts are going to be used like with the WIFI MRF24.

So here is a half-baked suggestion….

Let’s say in the variants Board_Defs .h you had:

#define                Default_SPI_CS                10                           // or 53 in a mega board
#define                Default_SPI_PORT          SPI2CON
 
#define                WIFI_SPI_CS                      10
#define                WiFi_SPI_PORT                 SPI2CON
 
#define                SD_SPI_CS                          4
#define                SD_SPI_PORT                    SPI2CON
 
#define                ALL_SPI_INT                      EXTERNAL_1_IRQ            // the WiFi SPI INT, if another INT is used for another SPI port, OR it in here

In your sketch code you could have some nasty thing like:

#ifdef Default_SPI_CS
pinMode(Default_SPI_CS, OUTPUT);
digitalWrite(Default_SPI_CS, HIGH);
#endif
 
#ifdef WIFI_SPI_CS
pinMode(WIFI_SPI_CS, OUTPUT);
digitalWrite(WIFI_SPI_CS, HIGH);
#endif
 
#ifdef SD_SPI_CS
pinMode(SD_SPI_CS, OUTPUT);
digitalWrite(SD_SPI_CS, HIGH);
#endif
 
And then in Sd2Card.cpp we could have something like:
 
//------------------------------------------------------------------------------
void Sd2Card::chipSelectHigh(void) {
  digitalWrite(chipSelectPin_, HIGH);
 
#if
#if defined (ALL_SPI_INT)
  if(fspi_state_saved)
  {
    SD_SPI_PORT = spi_state;
    fspi_state_saved = false;
    restoreIntEnable(ALL_SPI_INT, interrupt_state);
  }
#endif
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectLow(void) {
#if defined (ALL_SPI_INT)
    if(!fspi_state_saved)
    {
        interrupt_state = clearIntEnable(ALL_SPI_INT);
        spi_state = SD_SPI_PORT;
        SPI2CONbits.ON = 0;
        fspi_state_saved = true;
    }
#endif
  digitalWrite(chipSelectPin_, LOW);
}

Jacob Christ

Thu, 02 May 2013 17:32:42 +0000

Keith,

I like your idea of having some defines per board that identify pins and ports... But I prefer something like this:

#define  SPI_CS_Default       10                          
#define  SPI_PORT_Defualt    SPI2CON
 
#define  SPI_CS_WiFi            10
#define  SPI_PORT_WiFi        SPI2CON
 
#define  SPI_CS_SD             4
#define  SPI_PORT_SD          SPI2CON
 
#define  SPI_INT_ALL            EXTERNAL_1_IRQ            // the WiFi SPI INT, if another INT is used for another SPI port, OR it in here

Jacob


KeithV

Fri, 03 May 2013 17:25:43 +0000

Look good to me.... Make it so!


Jacob Christ

Sat, 25 May 2013 05:26:08 +0000

I just implemented this:

const int chipSelect_SD_default = 10; // Make 10 on Uno and 53 on a Mega const int chipSelect_SD = chipSelect_SD_default; 

// ... and in setup()

  pinMode(chipSelect_SD, OUTPUT);
  digitalWrite(chipSelect_SD, HIGH);

  pinMode(chipSelect_SD_default, OUTPUT);
  digitalWrite(chipSelect_SD_default, HIGH);

But didn't want to attack the board_def.h yet.