chipKIT® Development Platform

Inspired by Arduino™

Reading SD card works on arduino, same not on chipkit

Created Sun, 09 Sep 2012 20:45:13 +0000 by educa


educa

Sun, 09 Sep 2012 20:45:13 +0000

Hi,

I can succesfully read from my SD card, but now I would like to read every time 6 bytes from a file.

I do realize that this will have a performance hit and won't be as fast as reading in larger chunks of data at once, but I just need it working, not ultrafast.

So I tried the following code which works perfectly on arduino

#include "plib.h"
#include <SD.h>
const int chipSelect = 53;

#define BUFFER_SIZE 6

uint32_t s1;
uint32_t s2;

void setup()
{
  byte buff[BUFFER_SIZE];
  Serial.begin(115200);
  Serial.print("Initializing SD card...");
  pinMode(53, OUTPUT);
  
  //SPI.setClockDivider(SPI_CLOCK_DIV2); 
  
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    return;
  }
  Serial.println("card initialized.");
  File dataFile = SD.open("data.txt");
  s1=ReadCoreTimer(); 
  if (dataFile) {
   
    dataFile.read((char*)buff,BUFFER_SIZE);

    dataFile.close();
  s2=ReadCoreTimer(); 
  Serial.println(s1);
  Serial.println(s2);
  }  
  else {
    Serial.println("error opening data.txt");
  } 
}

void loop()
{
}

What I try to do here is read in 6 bytes from the datafile (datafile is much bigger then 6 bytes) to the array of byte called buff.

On arduino this compiles, but on chipkit (IDE 0023-20120811) it tells me

[color=#FF0000]error: no matching function for call to 'File::read(char*, int)' [/color]

Anyone have an idea what I have to change to make this work ?

Thanks,

Bart


rasmadrak

Sun, 09 Sep 2012 22:32:14 +0000

Hi there!

You will probably need to make this function public (or at least available to the wrapper code):

SdFat.h, row 241: int16_t read(void* buf, uint16_t nbyte);


educa

Sun, 09 Sep 2012 22:39:18 +0000

Hi rasmadrac and would you have any idea how I would have to do that ?

Kind regards,

Bart

PS. I'm using the standard sd library from the mpide


rasmadrak

Mon, 10 Sep 2012 01:23:10 +0000

Untested, but compiles and should work:

Insert the following row into file SD.h after the normal read() function:

virtual int16_t read(void* buf, uint16_t nbyte);

Add this to File.cpp

int16_t File:: read(void* buf, uint16_t nbyte) {
  return SD.file.read(buf, nbyte);
}

educa

Tue, 11 Sep 2012 15:25:07 +0000

Thank you,

I tried but somehow it didn't work out for me.

I tried the following code

#include <SPI.h>
#include <SD.h>

#define BUFFER_SIZE 512
#define SD_SS 53

long begintijd;


void setup()
{
    Serial.begin(115200);
    SD.begin(SD_SS);
    
    digitalWrite(SD_SS,HIGH);
}

void loop()
{
    byte buff[BUFFER_SIZE];
    Serial.print ("START\n");
    begintijd=micros();
      File f = SD.open("data.bin");
      if (f) {
        while (true) {
          //int16_t n = f.read((char*)buff,BUFFER_SIZE);
          int16_t n=f.read();
          if (!n)
          break;
        }
        f.close();
        Serial.print("STOP(");
        Serial.print(micros()-begintijd);
        Serial.print(")\n\n");
      }
}

The line[color=#FF0000] int16_t n=f.read(); [/color]does compile and reads a 16 bit integer from sd card. Even an int32_t compiles

But

[color=#FF0000]int16_t n = f.read((char*)buff,BUFFER_SIZE);[/color]

gives me the error

[color=#0040FF]sketch_sep11a.cpp:29:53: error: no matching function for call to 'File::read(char*, int)'

C:\chipkit.\hardware\pic32\libraries\SD/SD.h:32:15: note: candidate is: virtual int File::read()[/color]


rasmadrak

Tue, 11 Sep 2012 18:47:08 +0000

This row indicates you did not apply the changes to the SD library correctly: sketch_sep11a.cpp:29:53: error: no matching function for call to 'File::read(char*, int)'

Did you change the Chipkit library and not the Arduino?

Basically you could do either the following (works without editing the library):

uint8_t buff[BUFFER_SIZE];
File f = SD.open("data.bin");
for (int i=0; i < BUFFER_SIZE; i++)
{
   buff[i] = f.read();
}

This would read one byte at a time from the SD card = very slow.

Or you can modify the SD card library as I wrote above and do the following:

uint8_t buff[BUFFER_SIZE];
File f = SD.open("data.bin");
f.read( &buff[0] , BUFFER_SIZE );

This is much faster and only open the SD card for communication once and reads 32 bytes in one go. This is the way to go.

Look for the pic32 SD-library inside the MPIDE folder. If you're using Mac it's in "Contents/Resources/Java/hardware/pic32/libraries/SD"... If you're using PC or Linux I can't help you, I'm afraid.


educa

Tue, 11 Sep 2012 18:57:19 +0000

I changed \chipkit\libraries\SD and somehow this could indeed be wrong.

I found out now that there is also a \hardware\pic32\libraries\SD map.

Thanks for clarification


educa

Tue, 11 Sep 2012 22:46:11 +0000

I changed the correct libraries now and indeed this compiles.

My code currently looks like this

#include <SPI.h>
#include <SD.h>

#define BUFFER_SIZE 512
#define SD_SS 53

long begintime;
long endtime;

int16_t i;

void setup()
{
    Serial.begin(115200);
    SD.begin(SD_SS);
    
    digitalWrite(SD_SS,HIGH);

    byte buff[BUFFER_SIZE];
    Serial.print ("START\n");
      File f = SD.open("data.bin");
      if (f) {
        begintime=micros();
        while (true) {
          int16_t n = f.read((char*)buff,BUFFER_SIZE);
          if (!n)
          break;
        }
        endtime=micros();
        f.close();
        Serial.print("STOP(");
        Serial.print(endtime-begintime);
        Serial.print(")\n\n");
      }
}
void loop()
{
}

I checked it and it does indeed read data correctly into the byte array

It does 512 bytes in 3.828 milliseconds, which gives me a transfer rate of aprox. 133700 bytes per second. Thats not bad at all, but do you have any idea if I can speedup this by default?

I think I read somewhere that you might be able to speedup the SPI bus? Or am I wrong? I am allready very happy that this works now, just a little speedup would always be nice of course...

I allready tried to change SPI_HALF_SPEED to SPI_FULL_SPEED in sd.cpp , but that did not improve the speed at all. Maybe its just a limit ?

Kind regards, Bart


rasmadrak

Wed, 12 Sep 2012 10:55:47 +0000

Glad you got it working!

If you check further inside the SD-library, you'll see that the entire setClockSpeed-function (or something similar) is commented out. So there's no way of changing the speed unless you do it manually by updating the registers. I'm not that experienced in those registers thou.

I gained quite a lot of speed (almost 10x) by doing a simple (pseudo) change in a custom DSPI-based library: set_speed(slow); initialize_sd(); set_speed(high);

Although not the best there is, it gave me around 614 000 bytes/sec, which is roughly one third of what my card is capable of. Not bad, considering this is 1bit transfer and the max speed is achieved using 4bit transfer.


EDIT:

Remember that the card reads sectors of 512B, so if you read less than that you will not get the full speed possible, since the the rest of the bytes are just wasted (more or less). By reading a full 512byte sector you should get the highest possible speed.


educa

Wed, 12 Sep 2012 11:08:41 +0000

OK, as you can see I am reading 512 bytes.

I must say that reading 1 time 512 bytes takes a certain amount of time, but reading

64 times 8 bytes takes ALMOST te same time, so it seems like there is some kind of optimisation allready or maybe the library allready keeps the buffer to speed sequential reads.

Anyway, I think for my application that the speed will be enough. Maybe I could speedup but then I am afraid it would be too much tweaking in stuff I don't know too good yet :)

Thanks anyway for all help. I'm very happy that with chipkit I can make direct connection and that reading is reasonably fast.