Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

SD Card Project

Status
Not open for further replies.

AtomSoft

Well-Known Member
Hey all while im waiting for payday to finish my charger project. i thought id start on my other project. SD Cards. I recently bought a few things from futulec:

SD/MMC Mini Board

Logic Converter Mini Board

I wanted these for my glcd mostly but plan to do TFT LCDs (color) Soon! So i though heh memory is needed.

i hope this kind of thread is ok to post. Im hoping to get help on the simpler things here like SPI and other things.

At the end i of learning this i will of course share my whole project including schematics, code and thoughts. I will be sure to keep everything neat and commented as much as possible. So if there is anyone who wished to help me along the journey.. I say thank you.

Here are some PDFs i collected along the way:
PICmicro Mid-Range MCU Family Reference Manual
**broken link removed**
PIC - MMC (Multi Media Card) Flash Memory Extension


Any links or datasheets or anything that can help would be great. Also any advice or experience is great too!
 
Hey all while im waiting for payday to finish my charger project. i thought id start on my other project. SD Cards.
I got working on mine again this weekend. I'm having some strangeness and haven't yet got it working. I would like to compare code with what you come up with. :p My code is mostly borrowed from the book "Learning To Fly The PIC24", but modified to suit the 18F4620 I'm using.

The 32MB cards I have don't seem to work in SPI mode. They return illegal command codes every time. After thinking it was my code for quite a while I finally grabbed the 4GB card out of the camera and it works (almost) properly. So I'm shopping for another SD card just for experimenting. Think I'll get a 2GB. They're around $11.

Any links or datasheets or anything that can help would be great.
I'll find my list and post it again later today or tonight. There are some very good refs out there, along with a lot of useless crap.
 
Last edited:
Well how do you expect me to help you if neither one of you guys bought a set of boards for me (grin)?

Just joking. I sincerely wish I had the budget to buy some of these things. I'm always going to be a year behind you guys on these fun projects.

Mike
 
Just joking. I sincerely wish I had the budget to buy some of these things. I'm always going to be a year behind you guys on these fun projects.
SD sockets can be made out of an **broken link removed** or purchased for a couple bucks. The bought ones you just solder some pins on and plug into your breadboard. Cheap.

SD cards are also dirt cheap these days. Like I said, **broken link removed**. Look **broken link removed** likely find better deals than that.

The rest is just wiring and some pullup resistors. Very simple. The logic level converter isn't really necessary. Use voltage dividers for the wires that need em.
 
Last edited:
Last edited:
I was suprised to get it from futurlec in such short time. I always hear bad things. But i didnt know it comes from thailand. If i knew that i would have expected but i thought it was in US or UK so i was expecting it sooner. But when you add time for customs then its ok.
 
Here's the links I have. Be sure to post any good ones you find:


This is a GOOD one, and hard to find. I don't particularly like his code or coding style, but it's good info anyway: sdcard_appnote_foust.pdf

This is the useful part of the MAXIM info in open document format: sdcard_info.zip

Toshiba SD Card Spec: TOSHIBA_SD_Card_Specification.pdf

Some links:
**broken link removed**
http://www.kronosrobotics.com/Projects/MMC.shtml
**broken link removed**
http://www.roland-riegel.de/sd-reader/index.html
http://pinouts.ru/Memory/sdcard_pinout.shtml
**broken link removed**
**broken link removed**
http://www.captain.at/electronics/pic-mmc/
**broken link removed**
**broken link removed**
 
Last edited:
The 32MB cards I have don't seem to work in SPI mode. They return illegal command codes every time. After thinking it was my code for quite a while I finally grabbed the 4GB card out of the camera and it works (almost) properly. So I'm shopping for another SD card just for experimenting. Think I'll get a 2GB. They're around $11.
So I got a **broken link removed** and played with the code for a long while. I think I almost have it working. But now I plug the 32MB card in and it works normally (meaning almost working). I don't know what was going on before. So buying the 2GB wasn't necessary. Ah well... It'll get used, I guess.

Now I have code that seems to init the card to SPI mode, but won't write a sector. According to Lucio Di Jasio, when I send the write_single command it's supposed to return zero, meaning "command accepted". It never does. It's always one, meaning "idle".

Here's my current, broken code for 18F4620:
Code:
#include "sdcard.h"

char data1[256];
char data2[256];
char buffer1[256];
char buffer2[256];

void main(void){
	LBA addr;
	int i,r;
	trisd=0;
	trisc=0b00010000;
	CSel=1;						//init chip select (active low)
	LED=0;						//LED off
	osccon=0x72;					//8MHz clock
	osctune.6=0;					//disable PLL
	while(!osccon.IOFS);				//wait for osc stable
	sspstat = 0b00000000;				//SMP(7)=0, CKE(6)=0 (clock edge idle to active), others don't care
	sspcon1 = 0b00010010;				//CKP(4)=1 clock polarity (idle high)
							//SSPM3:SSPM0(3:0)=010 spi clock FOSC/64 (<400kHz)
	sspcon1.SSPEN=1;				//SSPEN(5)=1 enable SPI
	for(i=0;i<256;i++){				//fill the buffers
		data1[i]=i;
		data2[i]=i;
	}
	r=initMedia();
	if(r){						//card init failed - 1 blink
		while(1){
			LED=1;
			delay_ms(75);
			LED=0;
			delay_s(1);
		}
	}
	else{						//write card
		addr = 10000;
		for(i=0;i<1000;i++){
			if(!writeSector(addr+i,data1,data2)){
				while(1){		//write failed - 2 blinks
					LED=1;
					delay_ms(75);
					LED=0;
					delay_ms(75);
					LED=1;
					delay_ms(75);
					LED=0;
					delay_s(1);
				}
			}
		}
		addr=10000;				//verify write
		for(i=0;i<1000;i++){
			if(!readSector(addr+i,buffer1,buffer2)){
				while(1){		//verify failed - 3 blinks
					LED=1;
					delay_ms(75);
					LED=0;
					delay_ms(75);
					LED=1;
					delay_ms(75);
					LED=0;
					delay_ms(75);
					LED=1;
					delay_ms(75);
					LED=0;
					delay_s(1);
				}
			}
			if(memcmp(data1,buffer1,256)||memcmp(data2,buffer2,256)){	//verify
				while(1){		//mismatch - 4 blinks
					LED=1;
					delay_ms(75);
					LED=0;
					delay_ms(75);
					LED=1;
					delay_ms(75);
					LED=0;
					delay_ms(75);
					LED=1;
					delay_ms(75);
					LED=0;
					delay_ms(75);
					LED=1;
					delay_ms(75);
					LED=0;
					delay_s(1);
				}
			}
		}
	}
	while(1){					//success!
		LED=1;
		delay_s(1);
		LED=0;
		delay_s(1);
	}
}

int writeSector(LBA a,char *p1,char *p2)
{
	unsigned r,i;
	LED=1;						//turn on write LED
	r=sendSDCmd(24,(a<<9));
	if(r==0){
		writeSPI(0xfe);				//send Data Start byte
		for(i=0;i<256;i++)			//first 256 bytes
			writeSPI(*p1++);
		for(i=0;i<256;i++)			//second 256 bytes
			writeSPI(*p2++);
		writeSPI(0xff);				//send dummy CRC
		writeSPI(0xff);
		if((r=writeSPI(0xff) & 0x0f) == 0x05){	//check if data accepted
			for(i=10000;i>0;i--){
				if(r=writeSPI(0xff))
					break;
			}
		}
		else
			r=0;				//fail
	}
	CSel=1;writeSPI(0xff);				//disable SD
	LED = 0;					//LED off
	return(r);
}

int readSector(LBA a, char *p1, char *p2)
{
	int r,i;
	LED = 1;					//turn on read LED
	r = sendSDCmd(17,(a<<9));
	if(r==0){					//check if command was accepted
		i=10000;				//wait for a response
		do{
			r = writeSPI(0xff);
			if(r==0xfe)
				break;
		}while(--i > 0);
		if(i){					//if no timeout, read 512 byte sector
			for(i=0;i<256;i++)
				*p1++ = writeSPI(0xff);
			for(i=0;i<256;i++)
				*p2++ = writeSPI(0xff);
			writeSPI(0xff);			//ignore CRC
			writeSPI(0xff);
		}
	}
	CSel=1;writeSPI(0xff);				//disable SD
	LED = 0;					//read LED off
	return(r == 0xfe);
}

int initMedia(void)
{
	int i,r;
	CSel=1;					//while card is not selected
	for(i=0;i<16;i++)			//send 80 clock cycles to start up
		writeSPI(0xff);
	CSel=0;					//then select the card
	r = sendSDCmd(0,0);			//send reset command to enter SPI mode
	CSel=1;					//disable SD
	writeSPI(0xff);
	if(r != 1)				//error check - need 1
		return 0x84;
	i = 10000;				//send init for up to 0.3s
	CSel=0;
	do{
		r = sendSDCmd(1,0);		//send init command
		CSel=1;				//disable SD
		writeSPI(0xff);
		if(r) break;
	}while(--i > 0);
	if(i==0)				//time out error 0x85
		return 0x85;
	sspcon1 = 0b00010000;			//speed up spi clock
	sspcon1.SSPEN=1;
	return 0;
}

int sendSDCmd(unsigned char c,LBA a)
{
	int i,r;
	CSel=0;						//send command packet (6 bytes)
	writeSPI(c|0x40);				//send command & frame bit
	writeSPI(a>>24);				//send 32-bit address
	writeSPI(a>>16);
	writeSPI(a>>8);
	writeSPI(a);
	writeSPI(0x95);					//send CRC
	i=9;						//wait for response
	do{
		r=writeSPI(0xff);			//check if ready
		if(r != 0xff)
			break;
	}while(--i > 0);
	return(r);
}

unsigned char writeSPI(unsigned char send)
{
	sspbuf=send;
	while(!sspstat.BF);
	return sspbuf;
}
and the header file:
Code:
#include <system.h>
#include <memory.h>

#pragma	CLOCK_FREQ	8000000
#pragma DATA    _CONFIG1H, _OSC_INTIO67_1H
#pragma DATA    _CONFIG2H, _WDT_OFF_2H
#pragma DATA    _CONFIG3H, _MCLRE_ON_3H
#pragma DATA    _CONFIG4L, _LVP_OFF_4L & _XINST_OFF_4L

#define CSel	latd.2			//chip select line
#define LED		latd.1

typedef unsigned long LBA;

int writeSector(LBA,char *,char *);
int readSector(LBA, char *,char *);
int initMedia(void);
int sendSDCmd(unsigned char,LBA);
unsigned char writeSPI(unsigned char);
 
Last edited:
Well i have one word for you MDDFS Lib. Its a library made officially by microchip and it dosent only handle the communication to the card or hard drive it also handles the FAT12 FAT16 or FAT32 file system. It supports everything from directory's to file search to attributes and time stamps.Only thing it dosent support yet are long filenames.

Also it comes with code ready to interface with SD cards, CF cards and IDE harddrives. Its also very easy to get working.
 
Well i have one word for you MDDFS Lib. Its a library made officially by microchip and it dosent only handle the
Thanks Electro, but I make it a policy to always do it myself first, even if it's with mostly someone else's code. I don't care how long it takes. I like to learn how it works. Using libs teaches me nothing.

For me getting there is all the fun. :D
 
This is so confusing. I have not seen not 1 flow chart type info to explain how to initialize the sd card.

Im using MCC18 (C18) because i dont have full version of boostC (liscenece wont handle this)

OpenSPI(SPI_FOSC_64, MODE_00, SMPEND);
I use the above like to set to 312khz

SPI Master mode, clock = FOSC/64 (my crystal is 20mhz)
Setting for SPI bus Mode 0,0
Input data sample at end of data out

I tried to convert futz code well upto the init part, this is what i have but the LED blinks stating that the init failed:

Code:
#include <p18cxxx.h>
#include <stdio.h>
#include <delays.h>
#include <spi.h>

#pragma config WDT = OFF, OSC = HS, LVP = OFF

// FUNCTION Prototypes
void main(void);
void set_wren(void);
int initMedia(void);
int sendSDCmd(unsigned char c, unsigned long a);
void delay_s(unsigned char x);
void delay_ms(unsigned char x);
void delay_us(unsigned char x);

unsigned char var;

#define CSel LATDbits.LATD0
#define LED LATDbits.LATD1

//*******************************************


void main(void)
{
    char i,r ;
    LED = 0;
    TRISDbits.TRISD0 = 0;
    TRISDbits.TRISD1 = 0;
    CSel = 1;                 //init chip select (active low)
    
    OpenSPI(SPI_FOSC_64, MODE_00, SMPEND);

	r=initMedia();
	if(r){						//card init failed - 1 blink
		while(1){
			LED=1;
			delay_ms(75);
			LED=0;
			delay_s(1);
		}

    }

    while(1);
}


int initMedia(void)
{
	char i,r;

	CSel=1;					//while card is not selected
	for(i=0;i<16;i++)		//send 80 clock cycles to start up
		putcSPI(0xff);
	CSel=0;					//then select the card

	r = sendSDCmd(0,0);		//send reset command to enter SPI mode

	CSel=1;					//disable SD
	WriteSPI(0xff);

	if(r != 1)				//error check - need 1
		return 0x84;

	i = 10000;				//send init for up to 0.3s
	CSel=0;

	do{
		r = sendSDCmd(1,0);	//send init command
		CSel=1;				//disable SD
		putcSPI(0xff);
		if(r) break;
	}while(--i > 0);

	if(i==0)				//time out error 0x85
		return 0x85;

	return 0;
}

int sendSDCmd(unsigned char c, unsigned long a)
{
	int i,r;
	CSel=0;						//send command packet (6 bytes)
	putcSPI(c|0x40);				//send command & frame bit
	putcSPI(a>>24);				//send 32-bit address
	putcSPI(a>>16);
	putcSPI(a>>8);
	putcSPI(a);
	putcSPI(0x95);					//send CRC
	i=9;	
					//wait for response
	do{
		r=putcSPI(0xff);			//check if ready
		if(r != 0xff)
			break;
	}while(--i > 0);

	return(r);
}


void delay_s(unsigned char x)
{
    char var1;
	for(var1=0;var1<x;var1++)
	{				
        Delay10KTCYx(200);
	} 
}

void delay_ms(unsigned char x)
{
    char var1;
	for(var1=0;var1<x;var1++)
	{				
        Delay1KTCYx(2);
	} 
}

void delay_us(unsigned char x)
{
    char var1;
	for(var1=0;var1<x;var1++)
	{				
        //Delay10TCYx(2);
        Delay1TCY();
        Delay1TCY();
	} 
}
 
Last edited:
This is so confusing. I have not seen not 1 flow chart type info to explain how to initialize the sd card.
I've seen a couple, but they're never quite detailed enough. :p

Input data sample at end of data out
I think you should be sampling in middle, not end.

I tried to convert futz code well upto the init part, this is what i have but the LED blinks stating that the init failed:
Then you're semi close to where I am. Spending tons of time in the debugger, setting breakpoints all over the place to see what r is at different points.

I changed my LED blink delays to 150ms so I could see and count them better. May even go to 200 or more.

Oh ya, the code I posted had the trisc set for all outs. Trisc.4 (the SDI pin) must be a 1. I've edited the post, but you may have screen-scraped the source before I did that.

The thing seems to initialize fine, but still returns 1 instead of 0 when I send it a write_single command (24), and therefore doesn't write anything. :confused:
 
Last edited:
Im trying to understand how send the reset command.
I know that data goes and comes in packets:
(to send)

cmd-jpg.21650


"SD commands are listed in the form CMDXX" How do i send that out?

Should i make a array like:
unsigned char pData[5];

and fill it with the bytes for the packet?

1. 01 is like start bits
2. How would i turn CMD0 into 6 bits?
3. What would be the args?
4. CRC i see is a constant because not really used in SPI (0x95) only for fist to set SPI.
5. 1 is the stop bit.

Thats my main concern right now. I kinda can follow the app notes but cant until i understand the above 2,3 and how to send it all.

Well sending isnt going to be hard. I can write each byte out 1 after the other no issue im sure. Its just preparing them.

EXAMPLE:
Code:
    pData[0]= 0x40;
    pData[1]= 0x00;
    pData[2]= 0x00;
    pData[3]= 0x00;
    pData[4]= 0x00;
    pData[5]= 0x95;
 

Attachments

  • cmd.jpg
    cmd.jpg
    15.2 KB · Views: 1,349
Last edited:
OK i havent got it to write but compiles fine! Um in the WriteSector function r returns
r=sendSDCmd(24,(a<<9)); == (0x80)

Not sure but it receives it as 2 bytes. Does the byte length refer to like R2 (Response type R2) If so then the error is "Out of Range, CSD Overwrite"

Any thoughst?
 
OK i havent got it to write but compiles fine! Um in the WriteSector function r returns
r=sendSDCmd(24,(a<<9)); == (0x80)

Not sure but it receives it as 2 bytes. Does the byte length refer to like R2 (Response type R2) If so then the error is "Out of Range, CSD Overwrite"
A write_single command gets an R1 response, which is one byte. It's getting stored into an int, so it shows up in the debugger as two bytes of which the msbyte will always be zero. It could just as well be stored in an unsigned char, but I just typed in that part of the book code as is.

"SD commands are listed in the form CMDXX" How do i send that out?

Should i make a array like:
unsigned char pData[5];

and fill it with the bytes for the packet?

1. 01 is like start bits
2. How would i turn CMD0 into 6 bits?
3. What would be the args?
4. CRC i see is a constant because not really used in SPI (0x95) only for fist to set SPI.
5. 1 is the stop bit.

Thats my main concern right now. I kinda can follow the app notes but cant until i understand the above 2,3 and how to send it all.
Six byte packets:
Byte 1. The command (OR'd with 0x40 to set frame bit). Commands are just numbers and will never exceed 6 bits. You don't have to turn them into 6 bits. :p The args in my (Julio's) function are the command (unsigned char) and the address (unsigned long (32-bits) - uses LBA alias).

Bytes 2,3,4 & 5. The 32-bit address if needed. Four zero bytes otherwise.

Byte 6. The CRC (ignored after init)

CMD0 means command 0. You send a 0 byte. CMD24 means command 24. You send 24 decimal.
 
Last edited:
Got it working! :D:D:D I went to the book's web-site and found the problem in the errata. It wasn't initializing correctly before. Here's the corrected initMedia() function:
Code:
int initMedia(void)
{
	int i,r;
	CSel=1;writeSPI(0xff);			//while card is not selected
	for(i=0;i<16;i++)				//send 80 clock cycles to start up
		writeSPI(0xff);
	CSel=0;							//then select the card
	r = sendSDCmd(0,0);				//send reset command to enter SPI mode
	CSel=1;writeSPI(0xff);			//disable SD
	if(r != 1)						//error check - need 1
		return 0x84;
	i = 10000;						//send init for up to 0.3s
	CSel=0;
	do{
		r = sendSDCmd(1,0);			//send init command
		CSel=1;writeSPI(0xff);		//disable SD
		if([COLOR="Red"]!r[/COLOR]) break;
	}while(--i > 0);
	if(i==0)						//time out error 0x85
		return 0x85;
	sspcon1 = 0b00010000;			//speed up spi clock
	sspcon1.SSPEN=1;
	return 0;
}
The change is where it's waiting for the response to the init command. It was checking if r was true. That's wrong. It was supposed to be checking for false (0). So it never got properly initialized and was stuck forever in idle mode.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top