SD card read/write with Arduino

I started a topic in the development section a while ago about getting an excellent sd/mmc card library (www.roland-riegel.de - sd-reader: MMC/SD/SDHC card library) working in Arduino. After lots of tinkering, and some help from another user (strohhalm who found some fixes in the german forum for the roland-reigel library) it seems to work ok. FAT reading and writing will have to wait until some larger memory arduinos are available as it uses almost all of the memory, leaving no space for further code.

The schematic uses some resistors in a voltage divider to drop down the arduino 5v logic to the sd cards 3v3 logic. So all outgoing signals from the arduino are dropped to 3v3. Incoming signals to the arduino are fine because 3v3 is above logic 1 for arduino. The 3v3 voltage supply from the decimelia was used to supply power to the sd card.

The schematic (all top resistors are 1.8k, all bottom resistors are 3.3k):

The circuit built on a prototype board. I desoldered an sdcard socket from a broken memory card reader and then soldered pins onto the bottom. There is a thermistor connected to analog1 with some resistors for testing purposes. (The other stuff is a real time clock and its parts)

I've cutout all the unnecessary files from the roland reigel library and applied the fixes to leave just raw sd card reading and writing. This lets you write and read byte values from an sd card. It's very simple to use. I haven't tried to convert it to a cpp library. Copy the files into the library directory in the arduino build environment. (e.g. for me it is arduino-0011/hardware/libraries/SDcard ). Once you do that and restart the build environment you should be able to select SDcard as an added library and it will add the necessary includes.

The library can be downloaded here: http://www.mediafire.com/?2belzmmnzml

Here is the code for a very basic data logger which shows how to use the library. When the library starts it reads the card info and prints it out. It takes samples from analog in 1 and writes them to the sd card when you send an 's' over serial. You can read back the sd card by sending an 'r'. Sending 'q' stops sampling.

I haven't done much testing about read and write speeds or buffer size, in this example I'm only storing 2 bytes in a temporary buffer and then writing them to the card.

#include <sd-reader_config.h>
#include <sd_raw.h>
#include <sd_raw_config.h>





int print_disk_info();
int sample();
int readDisk();

byte incomingByte;
void printWelcome();
long int address;
byte tempBytes[2];


void setup()
{
  
  Serial.begin(9600);
  delay(1000);

  printWelcome();
  if(!sd_raw_init())
  {
     Serial.println("MMC/SD initialization failed");      
  }
  print_disk_info();
}



void loop()
{
    int i;    
    
    if(Serial.available()>0)
    {
         incomingByte=Serial.read();
     
       switch(incomingByte)
       {
           case 114:
                     readDisk();
                     break;
           case 115:
                     sample();
                     break;
           default:
                     break;
       }
    }    
}

int sample()
{
    int i,j;
    int temp;
    byte low;
    byte high;
    byte inByte;
    
    Serial.println();
    Serial.println();
    Serial.println("Sampling..");
    for(i=0;i<500;i=i+2)
    {
        if(Serial.available()>0)
        {
            inByte=Serial.read();
            if(inByte==113) return 0;
        }
        temp=analogRead(0);
        Serial.print(temp,DEC);
        Serial.print(" ");
        
        //Convert int to 2 bytes
        low=temp&0xFF;
        high=temp>>8;
       // Serial.print(temp,DEC);
        //Serial.print(low,DEC);
        //Serial.print(high,DEC);
    
        tempBytes[0]=low;
        tempBytes[1]=high;
        
        if(!sd_raw_write(i,tempBytes,2))
        {
          Serial.print("Write error");
        }
        //sd_raw_sync();
        delay(5000);
        
  Serial.println(); 
       
    }
    
    return 1;
}


int readDisk()
{
    byte low;
    byte high;
    byte info[2];
    int i;
    int  result;
    Serial.println();
    for(i=0;i<50;i=i+2)
    {
        sd_raw_read(i,info,2);
   
        //Serial.print(info[0],DEC);
        //Serial.print(" ");
        //Serial.print(info[1],DEC);
        low=info[0];
        high=info[1];
        result=high<<8;
        //result<<8;
        Serial.print(" ");
        Serial.print(result+low,DEC);
        Serial.print(" ");
    }
   
}

void printWelcome()
{
    Serial.println("------------------------");
    Serial.println("Data sampling system");
    Serial.println("send r to read disk");
    Serial.println("send s to start sampling");
    Serial.println("send q to stop sampling");
    Serial.println("Ready.....");
    Serial.println("-------------------------");
}


int print_disk_info()
{
 

    struct sd_raw_info disk_info;
    if(!sd_raw_get_info(&disk_info))
    {
        return 0;
    }

    
    Serial.println();
    Serial.print("rev:    "); 
    Serial.print(disk_info.revision,HEX); 
    Serial.println();
    Serial.print("serial: 0x"); 
    Serial.print(disk_info.serial,HEX); 
    Serial.println();
    Serial.print("date:   "); 
    Serial.print(disk_info.manufacturing_month,DEC); 
    Serial.println();
    Serial.print(disk_info.manufacturing_year,DEC); 
    Serial.println();
    Serial.print("size:   "); 
    Serial.print(disk_info.capacity,DEC); 
    Serial.println();
    Serial.print("copy:   "); 
    Serial.print(disk_info.flag_copy,DEC); 
    Serial.println();
    Serial.print("wr.pr.: ");
    Serial.print(disk_info.flag_write_protect_temp,DEC); 
    Serial.print('/');
    Serial.print(disk_info.flag_write_protect,DEC); 
    Serial.println();
    Serial.print("format: "); 
    Serial.print(disk_info.format,DEC); 
    Serial.println();
    Serial.print("free:   "); 
   
    return 1;
}

Will this work on the atmega8 ?

excellent, given the fat / sketch size limitation ... could you fit the sd/fat library on a atmega, then interface that chip with simple commands via i2c?

like have a master arduino and a slave arduino, the slave only handling sd/fat interactions.

would this be a good project for the dual core in this same section?

You have plenty of space if you don't use the fat library and just the raw sd card commands. Its just like having a 1G eeprom that is easy to use :). Probably the best thing to do would be to wait until the atmega328p chip is available and works in the arduino and then you would have more than enough for the fat library and any code you want.

That's good work, Mr Orange, and thanks for sharing.

Regards,

Mike

I'm having some trouble getting it working on a arduino Mini04. Everything worked when I tested it out on the Diecimila, but I'm getting the "MMC/SD initialization failed" message on the Mini.

Any ideas?

Regardless of my troubles, this is great!

Really nice! I was hoping to see something like that, that will really help me debugging my projects. For instance, for the monome clone, I can finally dump the serial received (well, I could have done it to the eeprom) as the serial communications isn't with the arduino IDE but with monomeserial, so I can't see real time what is received. This way, I save it, upload a new sketch, read the SD, and hopefully finish to implement the monome protocol ^^

Thanks again ^^

You could also use my uFat library.

It's a kind of halfway-house solution between a full-fat and a fat-free solution. (Sorry couldn't resist it.) Basically you get to read and write sectors within files that you pre-allocate on a PC.

It's a really simple interface. 1. Get the base sector for a named file on the card. 2. Use it!

Naturally there's a couple of minor restrictions, but that's how trade-offs work, right :wink:

Read more about uFat here: Arduino Nut: u-Fat filesystem

I'll be happy to help with any queries. PM or mail me.

Charlie

if you just want to log data (and not necessarily read it) i have an sdlogging library that saves to fat16 formatted SD cards. i use it to log GPS & sensor data: GPS datalogging shield for Arduino

If you want fat support, couldn't you theoretically throw it on the first portion of the SD card itself and then access it that way? I'm not intelligent enough to implement such a thing, but I thought I'd throw it out there. Would you have to modify the Arduino bootloader in order to get it to read a sketch from a foreign memory source? Is it even possible?

Hi Charlie - your uFAT library looks interesting, but I haven't been successful with it so far.

Has anyone else gotten it working?

I have an SD setup just as described at the top of this thread. I am able to demonstrate 'raw' SD I/O successfully using the SD raw library and the demonstration sampling app with two different SD cards.

I have downloaded and built mmc1.rar and it compiles and upload successfully. You don't directly state the pinouts, but they appear the same as the schematic above from the code. It correctly detects the presence of the SD card (or its removal), but it never gets past mmc::initialize.

I'd love to get this working - any ideas for me to try?

Thanks, harry
http://www.creatrope.com/blog/make/uduino-arduino-board-support/

Mr. Orange-

I had no trouble getting your code up and running in 15 minutes - happily logging, saving, and reading the input to analog1.

However, after hitting the arduino reset button, I found that the read function returns junk(from the SD card).

Shouldn't the SD card retain data after a power cycle? or, is it a function of the code that you so nicely supplied to get me started - and I just don't understand it, yet?

Hi - I wanted you to know that I got the mmc1.rar code for uFAT working, just as advertised. My problem was that a makeshift 3.3v supply from a voltage divider seemed to work for the raw SD write, but not for the full uFAT mmc code.

I cobbled together a 'real' variable power supply capable of producing 3.3v from Electronic Equiptment - DIY LM317 power supply, which worked flawlessly and the uFAT code worked correctly.

A few 'tricks':

Your card must be formatted FAT16, not FAT32. Under windows, if you see FAT32 and FAT, the 'FAT' is FAT16 and the partition must be less than 2G.

It hasn't been explicitly mentioned but the wiring for uFAT is indeed the same as the raw SD write above.

The demonstration file that uFAT writes to is fred.txt . If you just create fred.txt in windows be sure you really get fred.txt and not fred.txt.txt! If necessary, enter the command shell and mv fred.txt.txt to fred.txt.

To answer ducttapepro6, I verified that the newly written files are 'static' on the SD card using uFAT as one would expect.

Mr. Orange,

Thanks. I plan to use to log a battery charging session to see what the profile is on my DeWalt battery charger.

Any chance you would post the real time clock circuit you have on there?

Thanks,

Rick

Hello,

I'm trying to interface arduino uC to a microSD card thru pin 8-13 and GND.

I have been googling and i found this post, ladyada's code[1] based on roland's code[2] and some arduino's vendor code[3].

I have not been able to use SD card yet. The closest i got it is with this post and ladyada's code, but i can not initialize correctly the SD card.

As i read in this post, some people is having same issues, did you resolve it?

I'll be waisting some time on this and kick it, if somebody wants to join, it is welcome.

(I can not post active links)

--

Troubleshooting

------------------------                             
Data sampling system                                 
send r to read disk                                  
send s to start sampling
send q to stop sampling
Ready.....
-------------------------
MMC/SD initialization failed

How should i format SD card? I have tried without partitions and with FAT16

Can you use this with a micro sd card?

No, I have not been able to use it yet. It compiles safely but it does not initialize the SD card, so I can not write nor read from it.

I don't think it will work with microSD. According to wikipedia the SPI mode that this library uses is optional for microSD but required for SD:

How hard would it be to use the SD mode instead of SPI? And what about SDHC support?