Try SdFat, a Library for SD Cards

Hi
I am newbie with particle products but I try to use the photon with a SdCard datalogger ( like Sparkfun Logomatic )
The purpose is to save the serial signal from a Gps on the datalogger (done) when offline , and then use the photon to see ( and download ) on the cloud, the different generated txt files .
I tought that the SDFAT library could help me but if I use the defaut SPI_configuration 0 , with correct hardware junction between SCK => A3, MISO => A4, MOSI => A5, SS => A2 and the correspondant pin on the datalogger, I got " the SD errorCode: 0X1,0XFF" .
Could you help where I am wrong ? Thanks

Is this datalogger meant for 5V?
The SPI pins on the Photon only provide 3.3V, so you might have more luck if you just use a plain SdCard breakout that’s meant for 3.3V (which is native voltage for SD cards anyway).

thank you ScruffR for your reply
The datalogger has both 5V and 3V VCCin . I tested already with both ( I have an extra 5V Step-Up Voltage Regulator for 5V test and I used the 3V3 pin for 3V test ) and no difference . Always same trouble with ā€œSD errorCode: 0X1,0XFFā€

Hi
I didn’t find yet the solution to work with the logomatic v2 and Particle Photon and Sdfat but I found a maybe original solution using a simple MiniSD/MicroSd SDC adapter . It could be a very cheap solution to add a Sd card option to the Photon.
Sdfat is then working like a charm with that option. need stil to investigate for my purpose.

I use this module with ARM boards like Photon and Electron.

Under $1.00 with shipping on ebay.

Some have the resistor pack and some have individual pull-up resistors.

2 Likes

Hi
I tried to save a serial TX/RX signal on a photon on my Sd card with a simple modification of the original TrymeFirst + a Myfile.sync option.
Of course SD can’t be written fast enough and the result is not satisfying.
I would like then need to use the buffer of the Photon. I looked at the LowLatencyLogger.cpp but it is look like we need to use a SPI data as input and not the RX pin.
Many thanks for your advices

here is my actual Bench result


FreeMemory: 29692
Type is FAT16
Card size: 2.00 GB (GB = 1E9 bytes)

Manufacturer ID: 0X3
OEM ID: SD
Product: SMI
              Version: 1.0
Serial number: 0X6E760000
Manufacturing date: 10/2015

File size 5 MB
              Buffer size 32768 bytes
                                     Starting write test, please wait.

write speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
1764.34,216185,13042,18522

Starting read test, please wait.

read speed and latency
speed,max,min,avg
KB/Sec,usec,usec,usec
3082.14,13203,10594,10634

Hey guys,
I’m totally stumped. :sweat: I’m trying to read a microSD card in the Adafruit 2.8" TFT Resistive Touchscreen/TFT/microSD combo.

Since the shield is made for Arduino, I’m using the Shield Shield to attach to my Photon. Therefore, I have to use SPI1 (CS for microSD is Arduino 4 = Photon D6).

When I first got the thing (months ago), I tested it using an Arduino and it worked great…SD.h and a little Adafruit_GFX.h and voila…reading bmp’s, displaying on the screen. Albeit slowly, but it worked great.

But now here I am, trying to get anything to load from the SD and nada. I’ve tried a version of SdFat, but can’t get the card to read. I’ve tried slowing the clock down to SPI_CLOCK_DIV16, and ramped it up to SPI_FULL_SPEED.

Getting these errors:

Can't access SD card. Do not reformat.
No card, wrong chip select pin, or SPI problem?
SD errorCode: 0X1,0XFF

From SdInfo.h, these errors are:

/** timeout error for command CMD0 (initialize card in SPI mode) */
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;

…and perhaps (though realizing this is not 0XFF, but that does not exist):

/** card returned an error token instead of read data */
uint8_t const SD_CARD_ERROR_READ = 0XF;

I’ve seen on this forum that @whg mentioned SdFat has problems with DMA on SPI1, but that’s for Electron…is this also an issue on Photon?

I guess the long and the short of the question is:
How can I load bmp’s from a microSD card, attached to SPI1 on a Photon, and display them on the ILI9341 screen. :grin: :grin: I’m at wits end.

@peekay123 I know you’ve done some work on the SD libraries…do you have a silver bullet laying around?

Thanks so much guys-
Jeremy

Ps - Forgot to mention, I’m working in DEV

All devices on the Adafruit shield share the same hardware SPI lines but have different CS lines. Let’s review the adafruit-to-shield-to-photon mapping:

TFT          S_SHIELD     PHOTON
SCLK           13           D4         // SPI_3 SCK
MISO           12           D3         // SPI_3 MISO
MOSI           11           D2         // SPI_3 MOSI
TFT_CS         10           D5         // SPI_3 SS
TFT_DC          9           A4
RT_CS           8           A5
CARD_CS         4           D6
BKLIGHT         3           WKP

As we know, SPI_3 is really SPI1 on the Photon. So how are you instantiating the different TFT objects - display, touch and SD? Can you post that part of your code?

Thanks for your reply, @peekay123.

At this point, I’m trying to get back to basics and run the TryMeFirst.cpp code, just to get the SD card talking.

Here is that example code:

#include "SdFat.h"

// Pick an SPI configuration.
// See SPI configuration section below (comments are for photon).
#define SPI_CONFIGURATION 1
//------------------------------------------------------------------------------
// Setup SPI configuration.
#if SPI_CONFIGURATION == 0
// Primary SPI with DMA
// SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default)
SdFat sd;
const uint8_t chipSelect = SS;
#elif SPI_CONFIGURATION == 1
// Secondary SPI with DMA
// SCK => D4, MISO => D3, MOSI => D2, SS => D1
SdFat sd(1);
// const uint8_t chipSelect = D1;
const uint8_t chipSelect = D6;
#elif SPI_CONFIGURATION == 2
// Primary SPI with Arduino SPI library style byte I/O.
// SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default)
SdFatLibSpi sd;
const uint8_t chipSelect = SS;
#elif SPI_CONFIGURATION == 3
// Software SPI.  Use any digital pins.
// MISO => D5, MOSI => D6, SCK => D7, SS => D0
SdFatSoftSpi<D5, D6, D7> sd;
const uint8_t chipSelect = D0;
// const uint8_t chipSelect = D6;
#endif  // SPI_CONFIGURATION
//------------------------------------------------------------------------------

File myFile;

void setup() {
  Serial.begin(9600);
  // Wait for USB Serial
  while (!Serial) {
    SysCall::yield();
  }

  Serial.println("Type any character to start");
  while (Serial.read() <= 0) {
    SysCall::yield();
  }

  // Initialize SdFat or print a detailed error message and halt
  // Use half speed like the native library.
  // Change to SPI_FULL_SPEED for more performance.
  if (!sd.begin(chipSelect, SPI_CLOCK_DIV16)) {
    sd.initErrorHalt();
  }

  // open the file for write at end like the "Native SD library"
  if (!myFile.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
    sd.errorHalt("opening test.txt for write failed");
  }
  // if the file opened okay, write to it:
  Serial.print("Writing to test.txt...");
  myFile.println("testing 1, 2, 3.");
  myFile.printf("fileSize: %d\n", myFile.fileSize());

  // close the file:
  myFile.close();
  Serial.println("done.");

  // re-open the file for reading:
  if (!myFile.open("test.txt", O_READ)) {
    sd.errorHalt("opening test.txt for read failed");
  }
  Serial.println("test.txt content:");

  // read from the file until there's nothing else in it:
  int data;
  while ((data = myFile.read()) >= 0) {
    Serial.write(data);
  }
  // close the file:
  myFile.close();
}

void loop() {
  // nothing happens after setup
}

In my main code (which I’ll eventually add this SD capability), I’m using the following definitions:

// DEFINE PINS //
// #define SD_CS D6      // SD Card CS           = Arduino 4   = Particle D6
#define TFT_DC A4       // TFT Data/Command     = Arduino 9   = Particle A4
#define STMPE_CS A5     // Touch CS             = Arduino 8   = Particle A5
#define Buzzer WKP      // Piezo Buzzer OUTPUT
#define TFT_CS D5       // TFT CS               = Arduino 10  = Particle D5
#define SS_PIN D6       // RC522 Chip Select
#define RST_PIN D7      // RC522 Reset Pin

// CREATE OBJECTS FOR SPI DEVICES //
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, -1);
RFID RC522(SS_PIN, RST_PIN);    // Hardware SPI

My SPI configurations are set up within the .h and .cpp library files, and they are working just fine on SPI1. I haven’t tried to merge these two sketches together just yet… still trying to get the SD to read first.

Do you think I need to define all of these pins in TryMeFirst.cpp to make sure there aren’t other floating CS/SS pins interfering with the SD?

EDIT: I just bought another microSD card to try that, but same result.

@jeremywmccarter, thinking about this, I now realize that all the libraries are hard coded to use the SPI object and not the SPI1 object. Furthermore, there is no way to specify that in their constructor. So unless you change the code in all libraries, don’t expect things to work!

@peekay123 Oh man… :cry: But doesn’t the SPI_CONFIGURATION line in the TryMeFirst example elude to it being specified?

#define SPI_CONFIGURATION 1
//------------------------------------------------------------------------------
// Setup SPI configuration.
#if SPI_CONFIGURATION == 0
// Primary SPI with DMA
// SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default)
SdFat sd;
const uint8_t chipSelect = SS;
#elif SPI_CONFIGURATION == 1
// Secondary SPI with DMA
// SCK => D4, MISO => D3, MOSI => D2, SS => D1
SdFat sd(1);
// const uint8_t chipSelect = D1;
const uint8_t chipSelect = D6;
#elif SPI_CONFIGURATION == 2
// Primary SPI with Arduino SPI library style byte I/O.
// SCK => A3, MISO => A4, MOSI => A5, SS => A2 (default)
SdFatLibSpi sd;
const uint8_t chipSelect = SS;

@peekay123 Is there another SD library that might work instead? Or am I SOL? :fearful:

@jeremywmccarter, for the SD library yes, but not for the other libraries. Those devices may in fact interfere with the SD. Disconnect all other devices if you can and try just the SD hardware only.

@peekay123 I’ve been able to hard code the other libraries (Adafruit_ILI9341.h, Adafruit_STMPE610.h, and SparkFunSX1509.h) to use SPI1, and they are working.

I’m sort of remembering reading old forums weeks ago (before I’d received the TFT module, in fact) that said something about SD interfering with the others…it was either your post or @ScruffR. Ring any bells? I’ll do some digging…

@jeremywmccarter, the SDFat library keeps resetting the SPI mode settings whereas other libraries don’t. I have opened an issue to implement the arduino beginTransaction() and endTransaction() functions. Recently, I had to reset the SPI clock frequency prior to using SPI in my SharpMemory display library. It did not work at the high frequency that SDFat set.

@peekay123, Yeah I’m setting SPI settings each time I switch devices, which is annoying because it happens a lot:

SPI1.setDataMode(SPI_MODE0);          // Enable SPI1*/
SPI1.setBitOrder(MSBFIRST);           // Enable SPI1
SPI1.setClockDivider(SPI_CLOCK_DIV8); // Enable SPI1
SPI1.begin(SS_PIN);                         // Start SPI1

…but rather safe than sorry, right?

Any general advice to get the SD working in my configuration? Maybe an off-board (non-Shield) SD card slot? It would have to use I2C, because my SPI (not SPI1) pins are taken by some of the TFT Shield pins. I don’t really want to cut pins off the Shield and re-route… Just brainstorming here…

@jeremywmccarter, you may not need to set the SPI mode or bitorder and you shouldn’t call begin() every time. All you may need is to set the clock divider. I’ll have to look at the libraries to make sure.

@peekay123 Ok, I’ll try to pare it down a bit. Thank you for that!

@jeremywmccarter, all devices run SPI_MODE0 and MSBFIRST. However, the clock settings differ. For the ili9341, the library calls for SPI_CLOCK_DIV2 (18MHz on older Core), and for the touch library, it calls for SPI_CLOCK_DIV16 (1MHz on arduino). I suggest adding a line of code to each library’s SPI read and write functions (eg. readRegister()/writeRegister() or spiread()/spiwrite()) of each library to set the correct SPI speed. That should be all you need.

ili9341 SPI.setClockSpeed(18, MHZ); // You could also try 30 MHZ!
STMPE610 SPI.setClockSpeed(1, MHZ);

:smile:

@peekay123 Here is the post from @ScruffR that caused me to add those begin() calls...but perhaps I misunderstood his meaning...