Discussion in "8051 Discussion Forum" started by    Help    Dec 8, 2008.
Mon Dec 08 2008, 09:39 am
#1
Dear Fren,

I would like to use AT89C52 to interface with SD. c52 don't have build in SPI function but we can write the SPI function using coding but i'm not sure whether it can run on SD not.

I have found one very usefull information.
http://elm-chan.org/fsw/ff/00index_e.html
This link provide completed sample which can attach to any uC but i don't know how to use it. I think most important part is the ioctl part.

Please anyone can guide me how to do...

( May i know.. Is there any possible to get SD library for Protues? Proteus able to simulate MMC. If Proteus no support SD, It is possible i use SD design work for MMC? )

Thank you..


[ Edited Mon Dec 08 2008, 09:54 am ]
Mon Dec 08 2008, 08:02 pm
#2
yes proteus is able to simulate SD card, but i have never tested it.
SD and MMC are mostly same with a little difference. basic working is same.

elm-chan's library is very good and is best as i know..

regarding SPI, i suggest use a controller with on-chip SPI. example AT89S8253.
 Help like this.
Tue Dec 09 2008, 07:40 am
#3
Dear Fren,

Thank for your reply...

Ya, elm-chan's library is a very good reference...

Temporary is it possible to use AT89C52? In my local i can't get AT89S8253 and i also don't have this burner.

How can we do the basic interface between SD and C52 using SPI? I think this the 1st step we need to test it before we go further..

Another Q, the SD card is operate at 3.3V rite? I will put one 3.3V regulator for SD pin-3,4 and 6, is it correct? So the other data pin can i directly using uC port pin to communicate with SD card?

Please advice...

Thank you.


[ Edited Tue Dec 09 2008, 11:02 am ]
Tue Dec 09 2008, 11:48 am
#4
better use a line driver.. like 74LCX245 its a bidirectional transceiver and line driver
http://www.fairchildsemi.com/ds/74/74LCX245.pdf

Basic interface of SPI includes four pins, MISO, MOSI, SCK and SS

I am not saying that MMC wont work with software SPI, just that it will be very very slow, because when it comes to data transfer you have 512 bytes to write and read.. which may take a long time.

You give SPI a try.. If you want to see how to send data over SPI in software, then check the nokia LCD code. I have written small function SPISend to send data over SPI bus.
Tue Dec 09 2008, 01:53 pm
#5
Empty.. (sorry upload empty)


[ Edited Tue Dec 09 2008, 02:05 pm ]
Tue Dec 09 2008, 01:53 pm
#6
Empty.. (sorry upload empty)


[ Edited Tue Dec 09 2008, 02:05 pm ]
Tue Dec 09 2008, 02:04 pm
#7
Dear Fren,

If we using 74LCX245 as bidirectional transceiver and line driver. How we going to control the Read/Write for the driver? I have draw out the circuit please have a look. Does the SD card able to drive 5V signal from driver? Do we need 3.3V for SD card?

You done a great job fren..the nokia LCD result look very nice and cool...
From your sample code you have this 3 function.
spisend()
wrdata()
wrcmd()

Do we need the read function? I have prepare the code not sure whether correct not... Please can you help me have a look?

unsigned char spiRec(void){
	unsigned char x=0;
	unsigned char i;
	for(i=8;i>
0;i--){
		SCK = 0;
		if((DC==1)){
			x =| 1;
		}
		SCK = 1;
		x <<= 1;
	}
	return x;
}

unsigned char Rdata(void){
	unsigned char x=0;
	DAT = 1;
	CE = 0;
	x = spiRec();
	CE = 1;
	return x;
}

unsigned char Rcmd(void){
	unsigned char x=0;
	DAT = 0;
	CE = 0;
	x = spiRec();
	CE = 1;
	return x;
}



Wed Dec 10 2008, 06:28 pm
#8
you don't need write command and write data function, they are for LCD only.
do change the names too keep the pins shown in by Proteus.

here is SPI Init routine for AVR, you can make it for 8051 also, with small changes..

int MMCInit(void)
{
unsigned int i;
unsigned char Byte;

SPIDDR = SCLK + MOSI + CS + MMCPOWER;
SPIPORT = 0x00;
Delay_1ms(500);
SPIPORT |= MMCPOWER;
SPIPORT |= CS;
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0);    /* enable SPI as master, set clk divider */
Delay_1ms(250);

/* start off with 80 bits of high data with card deselected */
for(i=0;i<10;i++)
SpiByte(0xff);
SPIPORT &= ~CS;        /* select card */

/* now send CMD0 - go to idle state */
MMCCommand(0,0,0);
if (MMCGet() != 1)
   {
   SPIPORT |= CS;
   return -1;  // MMC Not detected
   }

/* send CMD1 until we get a 0 back, indicating card is done initializing */
i = 0xffff;
while ((SpiByte(0xff) != 0) && (--i))
     {
     MMCCommand(1,0,0);
     WDR();
     }
if (i == 0)
   {
   SPIPORT |= CS;
   return -2;  // Init Fail
   }

SPIPORT |= CS;
return 0;
}


take reference of MMC document i posted. where all the specifications are given along with timing diagrams.
Wed Dec 10 2008, 10:31 pm
#9
Hi,

Your coding is too brief....Can't understand how the coding run..

I have found out this information.., from your PDF, pg-79. From there i understand the intial 0xff with 80 clock cycle.

int MMCInit(void)
{
unsigned int i;
unsigned char Byte;

SPIDDR = SCLK + MOSI + CS + MMCPOWER; // 1)  is it we hav to set SCK, DI, DO and CS to 'Hi'. What is MMCPOWER? Is it we hv to use port-pin to control the card power?
 
SPIPORT = 0x00; // 2) Set SCK, DI, DO, and CS to 'Lo'?
Delay_1ms(500);
SPIPORT |= MMCPOWER; // 3) Set MMCPOWER port-pin "Hi"
SPIPORT |= CS; // 4) set CS = 1
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0);    /* enable SPI as master, set clk divider */ // 5) this line doing what?
Delay_1ms(250);

/* start off with 80 bits of high data with card deselected */
for(i=0;i<10;i++)
SpiByte(0xff); // 6) [i]This sequence is a contiguous stream of logical ‘1’s. The sequence length is the maximum of 1 msec, 74 clocks or the supply-ramp-up-time; The additional 10 clocks (over the 64 clocks after what the card should be ready for communication) are ...[/i]
SPIPORT &= ~CS;        /* select card */ // 7) CS = 0;

/* now send CMD0 - go to idle state */
MMCCommand(0,0,0); // 8) What element function passing? How to write this function routine? 
if (MMCGet() != 1) // 9) Ths MMCGet function is it my previous post spiRec() function?
   {
   SPIPORT |= CS; // 10) CS = 1;
   return -1;  // MMC Not detected
   }

/* send CMD1 until we get a 0 back, indicating card is done initializing */
i = 0xffff;
while ((SpiByte(0xff) != 0) && (--i))
     {
     MMCCommand(1,0,0); // 11) What element function passing? How to write this function routine? 
     WDR(); // 12) I think this should be WatchDog Timer. What should i do here? If i'm using C52
     }
if (i == 0)
   {
   SPIPORT |= CS; // 12) CS = 1;
   return -2;  // Init Fail
   }

SPIPORT |= CS; // 13) CS = 1;
return 0;
}


Please can you explain...

Thank you,


[ Edited Wed Dec 10 2008, 10:33 pm ]
Fri Dec 12 2008, 02:00 am
#10
card works on 3.3V, in the code power is obtained from AVR pin.

you need to understand that code is for AVR controller which has onchip SPI. so you code is not going to be same.

I gave you the init code to understand the flow of program. whatever comment given in the original code are sufficient to understand what is going on..

in order to understand code better you need to know how onchip SPI works..

I think it would be better if i paste all the supported routines.

/*************************************************************
 * MMC Init function
 *
 * - flushes card receive buffer
 * - selects card
 * - sends the reset command
 * - sends the initialization command, waits for card ready
 *************************************************************/
int MMCInit(void)
{
unsigned int i;
unsigned char Byte;

SPIDDR = SCLK + MOSI + CS + MMCPOWER;
SPIPORT = 0x00;
Delay_1ms(500);
SPIPORT |= MMCPOWER;
SPIPORT |= CS;
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR1) | (1<<SPR0);    /* enable SPI as master, set clk divider */
Delay_1ms(250);

/* start off with 80 bits of high data with card deselected */
for(i=0;i<10;i++)
SpiByte(0xff);
SPIPORT &= ~CS;        /* select card */

/* now send CMD0 - go to idle state */
MMCCommand(0,0,0);
if (MMCGet() != 1)
   {
   SPIPORT |= CS;
   return -1;  // MMC Not detected
   }

/* send CMD1 until we get a 0 back, indicating card is done initializing */
i = 0xffff;
while ((SpiByte(0xff) != 0) && (--i))
     {
     MMCCommand(1,0,0);
     WDR();
     }
if (i == 0)
   {
   SPIPORT |= CS;
   return -2;  // Init Fail
   }

SPIPORT |= CS;
return 0;
}

/************************************************************
 * void MMCInfo(void)
 *
 * - gets and prints formatted CID and CSD info from card
 ************************************************************/
void MMCInfo(void)
{
int i;

MMCCommand(10,0,0);
if (MMCDataToken() != 0xfe) TxString("MMC: error during CID read\n\r\0");
else TxString("MMC: CID read\n\r\0");

// Skip 3 byte Manufacturer ID
SpiByte(0xff);
SpiByte(0xff);
SpiByte(0xff);

TxString("MMC: Product Name : ");
for (i=0;i<7;i++) TxChar(SpiByte(0xff));
TxString("\n\r\0");

for (i=0;i<9;i++) SpiByte(0xff); // Read 9 left byte

SPIPORT |= CS;
}

/************************************************************
 * int MMCReadSector(unsigned long lba, unsigned char * s)
 *
 * - reads a sector from the card (512 bytes)
 * - takes sector # as param
 ************************************************************/
int MMCReadSector(unsigned long lba, char *s)
{
unsigned int i;

MMCCommand(17,(lba>
>
7) & 0xffff, (lba<<9) & 0xffff);
if (MMCDataToken() != 0xfe)
   {
   SEI();
   return -1;
   }

for (i=0;i<512;i++)     /* read the sector */
   {
    *s++ = SpiByte(0xff);
   }
SpiByte(0xff);          /* checksum ->
 don't care about it for now */
SpiByte(0xff);       /* checksum ->
 don't care about it for now */
SPIPORT |= CS;
return 0;
}

/************************************************************
 * int MMCWriteSector(unsigned long lba, unsigned char * s)
 *
 * - reads a sector from the card (512 bytes)
 * - takes sector # as param
 ************************************************************/
int MMCWriteSector(unsigned long lba, char *s)
{
unsigned int i;

MMCCommand(24, (lba>
>
7)& 0xffff, (lba<<9)& 0xffff);
if (MMCGet() == 0xff) return -1;

SpiByte(0xfe);  // Send Start Byte

for (i=0;i<512;i++)       /* read the sector */
   {
    SpiByte(*s++);
   }
SpiByte(0xff);          /* checksum ->
 don't care about it for now */
SpiByte(0xff);       /* checksum ->
 don't care about it for now */
SpiByte(0xff);       /* Read "data response byte"                 */

i = 0xffff;
while ((SpiByte(0xff) == 0x00) && (--i)); /* wait for write finish */
if (i == 0) return -1; // Error

SPIPORT |= CS;
return 0;
}

/************************************************************
 * unsigned char MMCGet(void)
 *
 * - pings the card until it gets a non-0xff value
 * - returns one byte of read info
 ************************************************************/
unsigned char MMCGet(void)
{
unsigned int i = 0xffff;
unsigned char Byte = 0xff;

while((Byte == 0xff) && (--i)) Byte = SpiByte(0xff);
return Byte;
}

/************************************************************
 * int MMCDataToken(void)
 *
 * - pings the card until it gets data token
 * - returns one byte of read info (data token)
 ************************************************************/
unsigned char MMCDataToken(void)
{
unsigned int i = 0xffff;
unsigned char Byte = 0xff;

while((Byte != 0xfe) && (--i)) Byte = SpiByte(0xff);
return Byte;
}

/************************************************************
 * void MMCCommand(unsigned char command, unsigned int px, unsigned int py)
 *
 * - send one byte of 0xff, then issue command + params + (fake) crc
 * - eat up the one command of nothing after the CRC
 ************************************************************/
void MMCCommand(unsigned char command, unsigned int px, unsigned int py)
{
SPIPORT &= ~CS;
SpiByte(0xff);
SpiByte(command | 0x40);
SpiByte((unsigned char)((px >
>
 8)&0x0ff)); /* high byte of param y */
SpiByte((unsigned char)(px & 0x00ff));     /* low byte of param y */
SpiByte((unsigned char)((py >
>
 8)&0x0ff)); /* high byte of param x */
SpiByte((unsigned char)(py & 0x00ff));     /* low byte of param x */
SpiByte(0x95);            /* correct CRC for first command in SPI          */
                          /* after that CRC is ignored, so no problem with */
                          /* always sending 0x95                           */
SpiByte(0xff);
}



Keep in mind given comments are sufficient to understand. Just keep the timing diagram along with code, to understand code better. dont go into how data is sent over spi, rather check what is sent over SPI and what is recieved.

SpiByte(0xff) <- this instruction will send dummy clock signals on SPI, coz your data pin will not change as data is high always. only you are sending clocks.
also in onchip SPI, when u want to read something, you need to send clock signal to your slave IC. hence your slave IC shifts data to controller's data buffer and you read data from there. I better not go into SPI of AVR now. try to uderstand what is sent over SPI, i will write you a routine which reads from SPI bus ok?

Get Social

Information

Powered by e107 Forum System

Downloads

Comments

Bobbyerilar
Thu Mar 28 2024, 08:08 am
pb58
Thu Mar 28 2024, 05:54 am
Clarazkafup
Thu Mar 28 2024, 02:24 am
Walterkic
Thu Mar 28 2024, 01:19 am
Davidusawn
Wed Mar 27 2024, 08:30 pm
Richardsop
Tue Mar 26 2024, 10:33 pm
Stevencog
Tue Mar 26 2024, 04:26 pm
Bernardwarge
Tue Mar 26 2024, 11:15 am