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.
That: **broken link removed**

Isn't really informational. Any other links on Fat16 or Fat32.
Actually it is very good info, but stirred into it is some odd stuff that distracts from the info you actually need. It helped me a lot, but I still had some old memory knowledge from learning that stuff the hard way in the early 80's (no internet), so all I had to do was refresh my memory.

You have one of Lucio Di Jasio's "Programming XX-bit Microcontrollers in C" books, right? In the 16-bit book, chapter 14 is all about FAT16. I know the 32-bit book follows the same format and has the same info. It isn't the easiest read unless you're using the same chip as him and just copying his code, but all the necessary info is there.

Between both documents you should be able to puzzle it out. Ask here if you have specific questions.
 
Thanks... i do have that book. Um on page 438 i believe you will see in the code:
Code:
#define FO_FIRST_TYPE 0 x 1C2 // offset of first partition type

I checked my 0x1C2 and its a value of 0x72.
Now i noticed this isnt a valid option for Fat16 Type:

Code:
i = buffer[ FO_FIRST_TYPE];

switch ( i)
{
	case 0 x 04:
	case 0 x 06:
	case 0 x 0E:
		// valid FAT16 options
		break;
	default:
		FError = FE_PARTITION_TYPE;
		free( D); free( buffer);
	return NULL;
} // switch

What am i reading wrong here? lol

BTW im looking in buffer2 value 0xC2 since buffer1 is 256 bytes it ends at FF and resumes in buffer2 as 0x00 - 0xFF so 0xC2 in buffer2 is equal to 0X1C2

Here is my dump... use a hex editor to view. Its a txt just so i can post without issue. You can rename to what ever.
 

Attachments

  • Sector00.txt
    512 bytes · Views: 149
Last edited:
Also Futz i wanted to ask you. Why did you write and read to so many sectors?

Code:
for(i=0;i<1000;i++){
	if(!readSector(addr+i,buffer1,buffer2)){ //addr+i,buffer1,buffer2)){
		while(1){		//verify failed - 3 blinks
			LED=1;
			delay_ms(150);
			LED=0;
			delay_ms(150);
			LED=1;
			delay_ms(150);
			LED=0;
			delay_ms(150);
			LED=1;
			delay_ms(150);
			LED=0;
			delay_s(1);
		}
	}
}

i changed it to :
Code:
if(!readSector(0,buffer1,buffer2)){ //addr+i,buffer1,buffer2)){
	while(1){		//verify failed - 3 blinks
		LED=1;
		delay_ms(150);
		LED=0;
		delay_ms(150);
		LED=1;
		delay_ms(150);
		LED=0;
		delay_ms(150);
		LED=1;
		delay_ms(150);
		LED=0;
		delay_s(1);
	}
}

and it works flawlessly. I assume the write would also. Here is my code to read 512 bytes of sector 0.

Code:
#include <p18f4620.h>
#include <stdio.h>
#include <delays.h>

#pragma config WDT = OFF, OSC = INTIO67, MCLRE = ON, XINST = OFF

#define CSel	LATDbits.LATD2		//chip select line
#define LED		LATDbits.LATD1

typedef unsigned long LBA;

void main(void);

int writeSector(LBA,char *,char *);
int readSector(LBA, char *,char *);
int initMedia(void);
int sendSDCmd(unsigned char,LBA);

void delay_s(unsigned char);
void delay_ms(unsigned char);
void delay_us(unsigned char);

unsigned char writeSPI(unsigned char);

///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////

#pragma udata data1
char data1[256];
#pragma udata data2
char data2[256];
#pragma udata buffer1
char buffer1[256];
#pragma udata buffer2
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
	OSCTUNEbits.PLLEN = 0;			//disable PLL

	while(!OSCCONbits.IOFS);		//wait for osc stable

	SSPSTAT = 0b00000000;		//SMP(7)=0, CKE(6)=0 (clock edge idle to active)
	SSPCON1 = 0b00010010;		//CKP(4)=1 clock polarity (idle high)
					//SSPM3:SSPM0(3:0)=010 spi clock FOSC/64 (<400kHz)
	SSPCON1bits.SSPEN=1;		//SSPEN(5)=1 enable SPI

	for(i=0;i<256;i++){		//fill the send buffers
		data1[i]=i;
		data2[i]=i;
		buffer1[i]=0;		//and clear the receive buffers
		buffer2[i]=0;
	}

	r=initMedia();

	if(r){				//card init failed - 1 blink
		while(1){
			LED=1;
			delay_ms(150);
			LED=0;
			delay_s(1);
		}
	}
	else
    {
        //card init passed all good now use it lol

			if(!readSector(0,buffer1,buffer2)){ //addr+i,buffer1,buffer2)){
				while(1){		//verify failed - 3 blinks
					LED=1;
					delay_ms(150);
					LED=0;
					delay_ms(150);
					LED=1;
					delay_ms(150);
					LED=0;
					delay_ms(150);
					LED=1;
					delay_ms(150);
					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;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(!r) break;
	}while(--i > 0);

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

	SSPCON1 = 0b00010000;		//speed up spi clock
	SSPCON1bits.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(!SSPSTATbits.BF);
	return SSPBUF;
}

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

void delay_s(unsigned char x)
{
    char var1;
	for(var1=0;var1<x;var1++)
	{
        Delay10KTCYx(200);    //2,000,000 cycles = 1 second
	}
}

void delay_ms(unsigned char x)
{
    char var1;
	for(var1=0;var1<x;var1++)
	{
        Delay1KTCYx(2);    //2,000 cycles = 1 us
	}
}

void delay_us(unsigned char x)
{
    char var1;
	for(var1=0;var1<x;var1++)
	{
        Delay1TCY();    //2 cycle = 1 us
        Delay1TCY();

	}
}

Even tho i am not writing to the card yet i left the 2 data variables in so when i do write (if i do) i can have it ready.

I noticed 256 is the max size of a variable... why is that? If i can make 4 256 variables why cant i make 2 of 512?

Can someone help on that also please... Thanks again
 
Last edited:
I checked my 0x1C2 and its a value of 0x72.
Now i noticed this isnt a valid option for Fat16 Type:

What am i reading wrong here? lol

BTW im looking in buffer2 value 0xC2 since buffer1 is 256 bytes it ends at FF and resumes in buffer2 as 0x00 - 0xFF so 0xC2 in buffer2 is equal to 0X1C2

Here is my dump... use a hex editor to view. Its a txt just so i can post without issue. You can rename to what ever.
Your problem is most likely that your SD card isn't formatted. I looked at the dump. The byte at offset $1c2 is the ascii value for the letter 'r' in the word 'other', which is in the sentence "Remove disks or other media". You either don't have a partition table there because the card isn't formatted, or you're not actually looking at sector zero.
 
Also Futz i wanted to ask you. Why did you write and read to so many sectors?
Why not? Lucio's code did it. I thought "Why not? That seems like a good test." :p

My hex editor (read only at present) reads a single sector at a time.

I noticed 256 is the max size of a variable... why is that? If i can make 4 256 variables why cant i make 2 of 512?
Because the PIC you're using has RAM paged in 256 byte banks. I guess the compiler writers decided they didn't want to deal with memory paging, and it only allows 256 byte arrays. Reading/writing in two 256 byte chunks is trivially easy anyway. Not a big deal at all.
 
This has alot of info but im still lost.
https://www.ntfs.com/#fat file system

Why doesnt none match my SD card? Am i supposed to format it special?

im in XP. So i format from a command prompt

format x:\ /FS:FAT /A:512

Any thoughts? MY HD is NTFS will that effect it? Is there a special Formater out there?
I just format it with the camera. Quick and easy.

The NTFS filesystem on your HD has zero to do with the filesystem on the card. XP is perfectly capable of reading/writing any filesystem (need extra drivers for Linux filesystems), including old ones like FAT16.
 
Try using something called a low level format tool on it. All it dose is write all sectors to FF and so completely cleaning the card and then just use windowses built in tool to format to FAT16. This saved my thumb drive when the filesystem got corrupt and windows refused to even try formating it. after clearing it it worked agen.
 
Start OFFSET For Volume ID = in decimal it is 39 and in hex it is 0x27
Code:
dec      39 40 41 42
hex      27 28 29 2A
--------------------
	  C2 E0 AA BC     now becomes    BC AA E0 C2
Needs to be reversed to make my volume id which is "3165315266".
I checked this with Disk Probe.
 
Last edited:
Here is a snapshot of me getting the Bytes per sector using:

Code:
int BytesPerSec;

 //and in filling it i do :

        BytesPerSec = buffer1[0x0C];
        BytesPerSec = (BytesPerSec<<8) + buffer1[0x0B];

I used "int" because its a word (2 byte) I decided to use variable to store the info because if i do another read i loose that info.

But im stilling having issues with memory. How come i have to use:
#pragma udata BytesPerSec
int BytesPerSec;

This is starting to bug me.
 

Attachments

  • sd_bpsect.jpg
    sd_bpsect.jpg
    284.3 KB · Views: 212
Last edited:
Dude! I got to make a 512 Byte Variable. Its a matter of altering the linker and that pragma. Open up the hlpC18up.chm (the user guide)

GOTO "Examples"
GOTO "Application: Creating Large Data Objects and the USART"

You will learn it there. It was so simple lol I call i simple because if i can do it anyone can lol

Here is my project... so far...
 

Attachments

  • sd_upd_01.zip
    9.6 KB · Views: 201
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top