EmbeddedRelated.com
Forums

SPI / SD on lpc2106

Started by armqamp October 11, 2005
Hello,

I'm trying to make an SD card to work with the lpc2106 and later want
to implement FAT.
The problem is I don't get any response of the SD card when I try to
initialize it.

Maybe somebody can disover what I'm doing wrong?

here is the code:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

void ActivateSD(void){

unsigned int ii=0;
unsigned char resp, i;
unsigned char status;

print("Activating SD Card....\n\n");

// Turn off SD Card
SD_power_off;

// Wait for power to really go down
for(ii = 0; ii; ii++);
for(ii = 0; ii; ii++);
for(ii = 0; ii; ii++);
for(ii = 0; ii; ii++);

// Turn on SD Card
SD_power_on;

// Wait for power to really come up
for(status = 0; status < 10; ++status)
{
for(ii = 0; ii; ii++);
for(ii = 0; ii; ii++);
for(ii = 0; ii; ii++);
for(ii = 0; ii; ii++);
} for(i=1; i<; i++){ //try 10 times to wake up the card

SD_disable; //CS high

InitSequence(); //send 80 clocks

SD_enable; //CS low

SD_SendCommand(CMD0,0,0,0,0); //send Reset command

resp = SD_Response();
if( resp == 0x01 ){ //wait for R1 response to be 0x01
break;
}
else{

}

}

spiSendByte(0xFF); // Response received, send the required 8
clocks after the response to finish up (page 5-6 Sandisk Manual) if(i>10){
SD_disable;
print("SD activation failed\n");
}
else{
print("SD activation successfully\n");

while( resp != 0x00){ //try sending CMD1 until
response R1 is 0x00
SD_SendCommand(CMD1,0,0,0,0); //activate card initialization process
resp = SD_Response();
spiSendByte(0xFF); //send required 8 clocks
if(resp==0x00){ // Ready
print("SD successfully activated!!!\n");
break;
}
}

if(resp != 0x00){
print("Error: ");
print("0x"); printnum(16, 8, 0, '0', resp); print("\n");
}

}
print("\n-------end-----------\n");
} unsigned char SD_Response(void) {
unsigned char i;
unsigned char resp;

for(i=0; i<10; i++) {
resp = spiGetByte();
if(resp != 0xFF) {
return resp;
}
}
return 0xFF;
}

void SD_SendCommand(unsigned char command, unsigned char arg_a,
unsigned char arg_b, unsigned char arg_c, unsigned char arg_d) {
spiSendByte(command);
spiSendByte(arg_a);
spiSendByte(arg_b);
spiSendByte(arg_c);
spiSendByte(arg_d);
spiSendByte(0x95); // correct CRC for first command in SPI after
that CRC is ignored, so no problem with always sending 0x95
}

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@



An Engineer's Guide to the LPC2100 Series

--- In lpc2000@lpc2..., "armqamp" <wouter@w...> wrote:
>
> Hello,
>
> I'm trying to make an SD card to work with the lpc2106 and later want
> to implement FAT.
> The problem is I don't get any response of the SD card when I try to
> initialize it.
>
> Maybe somebody can disover what I'm doing wrong?
>
> here is the code:
>
> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>
> void ActivateSD(void){
>
> unsigned int ii=0;
> unsigned char resp, i;
> unsigned char status;
>
> print("Activating SD Card....\n\n");
>
> // Turn off SD Card
> SD_power_off;
>
> // Wait for power to really go down
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
>
> // Turn on SD Card
> SD_power_on;
>
> // Wait for power to really come up
> for(status = 0; status < 10; ++status)
> {
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> } > for(i=1; i<; i++){ //try 10 times to wake up the card
>
> SD_disable; //CS high
>
> InitSequence(); //send 80 clocks
>
> SD_enable; //CS low
>
> SD_SendCommand(CMD0,0,0,0,0); //send Reset command
>
> resp = SD_Response();
> if( resp == 0x01 ){ //wait for R1 response to be 0x01
> break;
> }
> else{
>
> }
>
> }
>
> spiSendByte(0xFF); // Response received, send the required 8
> clocks after the response to finish up (page 5-6 Sandisk Manual) > if(i>10){
> SD_disable;
> print("SD activation failed\n");
> }
> else{
> print("SD activation successfully\n");
>
> while( resp != 0x00){ //try sending CMD1 until
> response R1 is 0x00
> SD_SendCommand(CMD1,0,0,0,0); //activate card initialization process
> resp = SD_Response();
> spiSendByte(0xFF); //send required 8 clocks
> if(resp==0x00){ // Ready
> print("SD successfully activated!!!\n");
> break;
> }
> }
>
> if(resp != 0x00){
> print("Error: ");
> print("0x"); printnum(16, 8, 0, '0', resp); print("\n");
> }
>
> }
> print("\n-------end-----------\n");
> } > unsigned char SD_Response(void) {
> unsigned char i;
> unsigned char resp;
>
> for(i=0; i<10; i++) {
> resp = spiGetByte();
> if(resp != 0xFF) {
> return resp;
> }
> }
> return 0xFF;
> }
>
> void SD_SendCommand(unsigned char command, unsigned char arg_a,
> unsigned char arg_b, unsigned char arg_c, unsigned char arg_d) {
> spiSendByte(command);
> spiSendByte(arg_a);
> spiSendByte(arg_b);
> spiSendByte(arg_c);
> spiSendByte(arg_d);
> spiSendByte(0x95); // correct CRC for first command in SPI after
> that CRC is ignored, so no problem with always sending 0x95
> }
>
> @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>

First, what's the value of "CMD0" ? It must be 0x40.

Cheers,
Max.



I defined the commands like this:

#define CMD0 0x40 // software reset
#define CMD1 0x41 // brings card out of idle state
#define CMD2 0x42 // not used in SPI mode
#define CMD3 0x43 // not used in SPI mode
#define CMD4 0x44 // not used in SPI mode
#define CMD5 0x45 // Reserved
#define CMD6 0x46 // Reserved
#define CMD7 0x47 // not used in SPI mode

and so on... thanks,

Wouter --- In lpc2000@lpc2..., "theothervmax" <vmax@g...> wrote:
>
> --- In lpc2000@lpc2..., "armqamp" <wouter@w...> wrote:
> >
> > Hello,
> >
> > I'm trying to make an SD card to work with the lpc2106 and later want
> > to implement FAT.
> > The problem is I don't get any response of the SD card when I try to
> > initialize it.
> >
> > Maybe somebody can disover what I'm doing wrong?
> >
> > here is the code:
> >
> > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
> >
> > void ActivateSD(void){
> >
> > unsigned int ii=0;
> > unsigned char resp, i;
> > unsigned char status;
> >
> > print("Activating SD Card....\n\n");
> >
> > // Turn off SD Card
> > SD_power_off;
> >
> > // Wait for power to really go down
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> >
> > // Turn on SD Card
> > SD_power_on;
> >
> > // Wait for power to really come up
> > for(status = 0; status < 10; ++status)
> > {
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > }
> >
> >
> >
> >
> >
> > for(i=1; i<; i++){ //try 10 times to wake up
the card
> >
> > SD_disable; //CS high
> >
> > InitSequence(); //send 80 clocks
> >
> > SD_enable; //CS low
> >
> > SD_SendCommand(CMD0,0,0,0,0); //send Reset command
> >
> > resp = SD_Response();
> > if( resp == 0x01 ){ //wait for R1 response to be 0x01
> > break;
> > }
> > else{
> >
> > }
> >
> > }
> >
> > spiSendByte(0xFF); // Response received, send the required 8
> > clocks after the response to finish up (page 5-6 Sandisk Manual)
> >
> >
> > if(i>10){
> > SD_disable;
> > print("SD activation failed\n");
> > }
> > else{
> > print("SD activation successfully\n");
> >
> > while( resp != 0x00){ //try sending CMD1 until
> > response R1 is 0x00
> > SD_SendCommand(CMD1,0,0,0,0); //activate card initialization
process
> > resp = SD_Response();
> > spiSendByte(0xFF); //send required 8 clocks
> > if(resp==0x00){ // Ready
> > print("SD successfully activated!!!\n");
> > break;
> > }
> > }
> >
> > if(resp != 0x00){
> > print("Error: ");
> > print("0x"); printnum(16, 8, 0, '0', resp); print("\n");
> > }
> >
> > }
> > print("\n-------end-----------\n");
> > }
> >
> >
> > unsigned char SD_Response(void) {
> > unsigned char i;
> > unsigned char resp;
> >
> > for(i=0; i<10; i++) {
> > resp = spiGetByte();
> > if(resp != 0xFF) {
> > return resp;
> > }
> > }
> > return 0xFF;
> > }
> >
> > void SD_SendCommand(unsigned char command, unsigned char arg_a,
> > unsigned char arg_b, unsigned char arg_c, unsigned char arg_d) {
> > spiSendByte(command);
> > spiSendByte(arg_a);
> > spiSendByte(arg_b);
> > spiSendByte(arg_c);
> > spiSendByte(arg_d);
> > spiSendByte(0x95); // correct CRC for first command in SPI after
> > that CRC is ignored, so no problem with always sending 0x95
> > }
> >
> > @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
> >
>
> First, what's the value of "CMD0" ? It must be 0x40.
>
> Cheers,
> Max.
>




--- In lpc2000@lpc2..., "armqamp" <wouter@w...> wrote:
>
> I defined the commands like this:
>
> #define CMD0 0x40 // software reset
> #define CMD1 0x41 // brings card out of idle state
> #define CMD2 0x42 // not used in SPI mode
> #define CMD3 0x43 // not used in SPI mode
> #define CMD4 0x44 // not used in SPI mode
> #define CMD5 0x45 // Reserved
> #define CMD6 0x46 // Reserved
> #define CMD7 0x47 // not used in SPI mode
>
> and so on... > thanks,
>
> Wouter
>

Rest of the code looks good, except for that:
if(i>10){
SD_disable;
print("SD activation failed\n");
}
else{
print("SD activation successfully\n");
} If "SD_disable" is just setting CS high, you'd better do it every time after sending command (and getting response), not only if something failed.

Max


Look under the SPI section in the sandisk manual. I use ACMD41 as this
is the recommended method followed by CMD58 to read the OCR. One little
thing I do different is to pad the start of a CMD with a couple of dummy
reads (same as writing 0xFF). I have implemented an SD driver and FAT16
successfully on the 2106 as well as the 2138 and tested this on about 5
different types of SD cards to date.

BTW, when you power-down the supply just make sure all the SD I/O lines
are taken down to VSS as well.

*Peter* armqamp wrote:

>Hello,
>
>I'm trying to make an SD card to work with the lpc2106 and later want
>to implement FAT.
>The problem is I don't get any response of the SD card when I try to
>initialize it.
>
>Maybe somebody can disover what I'm doing wrong?
>
>here is the code:
>
>@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
>
>void ActivateSD(void){
>
> unsigned int ii=0;
> unsigned char resp, i;
> unsigned char status;
>
> print("Activating SD Card....\n\n");
>
> // Turn off SD Card
> SD_power_off;
>
> // Wait for power to really go down
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
>
> // Turn on SD Card
> SD_power_on;
>
> // Wait for power to really come up
> for(status = 0; status < 10; ++status)
> {
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> for(ii = 0; ii; ii++);
> } > for(i=1; i<; i++){ //try 10 times to wake up the card
>
> SD_disable; //CS high
>
> InitSequence(); //send 80 clocks
>
> SD_enable; //CS low
>
> SD_SendCommand(CMD0,0,0,0,0); //send Reset command
>
> resp = SD_Response();
> if( resp == 0x01 ){ //wait for R1 response to be 0x01
> break;
> }
> else{
>
> }
>
> }
>
> spiSendByte(0xFF); // Response received, send the required 8
>clocks after the response to finish up (page 5-6 Sandisk Manual) > if(i>10){
> SD_disable;
> print("SD activation failed\n");
> }
> else{
> print("SD activation successfully\n");
>
> while( resp != 0x00){ //try sending CMD1 until
>response R1 is 0x00
> SD_SendCommand(CMD1,0,0,0,0); //activate card initialization process
> resp = SD_Response();
> spiSendByte(0xFF); //send required 8 clocks
> if(resp==0x00){ // Ready
> print("SD successfully activated!!!\n");
> break;
> }
> }
>
> if(resp != 0x00){
> print("Error: ");
> print("0x"); printnum(16, 8, 0, '0', resp); print("\n");
> }
>
> }
> print("\n-------end-----------\n");
>} >unsigned char SD_Response(void) {
> unsigned char i;
> unsigned char resp;
>
> for(i=0; i<10; i++) {
> resp = spiGetByte();
> if(resp != 0xFF) {
> return resp;
> }
> }
> return 0xFF;
>}
>
>void SD_SendCommand(unsigned char command, unsigned char arg_a,
>unsigned char arg_b, unsigned char arg_c, unsigned char arg_d) {
> spiSendByte(command);
> spiSendByte(arg_a);
> spiSendByte(arg_b);
> spiSendByte(arg_c);
> spiSendByte(arg_d);
> spiSendByte(0x95); // correct CRC for first command in SPI after
>that CRC is ignored, so no problem with always sending 0x95
>}




Peter,

I thought always CMD0 had to be send to reset the card and then CMD1
to activate it.
I haven't seen other guys do it differently too.
But you are beginnning with ACDM41? and then CMD58?

maybe you can send or post your code so I can compare it?

thanks,

Wouter
--- In lpc2000@lpc2..., Peter Jakacki <peterjak@t...> wrote:
>
> Look under the SPI section in the sandisk manual. I use ACMD41 as this
> is the recommended method followed by CMD58 to read the OCR. One little
> thing I do different is to pad the start of a CMD with a couple of
dummy
> reads (same as writing 0xFF). I have implemented an SD driver and FAT16
> successfully on the 2106 as well as the 2138 and tested this on about 5
> different types of SD cards to date.
>
> BTW, when you power-down the supply just make sure all the SD I/O lines
> are taken down to VSS as well.
>
> *Peter* > armqamp wrote:
>
> >Hello,
> >
> >I'm trying to make an SD card to work with the lpc2106 and later want
> >to implement FAT.
> >The problem is I don't get any response of the SD card when I try to
> >initialize it.
> >
> >Maybe somebody can disover what I'm doing wrong?
> >
> >here is the code:
> >
> >@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
> >
> >void ActivateSD(void){
> >
> > unsigned int ii=0;
> > unsigned char resp, i;
> > unsigned char status;
> >
> > print("Activating SD Card....\n\n");
> >
> > // Turn off SD Card
> > SD_power_off;
> >
> > // Wait for power to really go down
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> >
> > // Turn on SD Card
> > SD_power_on;
> >
> > // Wait for power to really come up
> > for(status = 0; status < 10; ++status)
> > {
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > for(ii = 0; ii; ii++);
> > }
> >
> >
> >
> >
> >
> > for(i=1; i<; i++){ //try 10 times to wake up
the card
> >
> > SD_disable; //CS high
> >
> > InitSequence(); //send 80 clocks
> >
> > SD_enable; //CS low
> >
> > SD_SendCommand(CMD0,0,0,0,0); //send Reset command
> >
> > resp = SD_Response();
> > if( resp == 0x01 ){ //wait for R1 response to be 0x01
> > break;
> > }
> > else{
> >
> > }
> >
> > }
> >
> > spiSendByte(0xFF); // Response received, send the required 8
> >clocks after the response to finish up (page 5-6 Sandisk Manual)
> >
> >
> > if(i>10){
> > SD_disable;
> > print("SD activation failed\n");
> > }
> > else{
> > print("SD activation successfully\n");
> >
> > while( resp != 0x00){ //try sending CMD1 until
> >response R1 is 0x00
> > SD_SendCommand(CMD1,0,0,0,0); //activate card initialization
process
> > resp = SD_Response();
> > spiSendByte(0xFF); //send required 8 clocks
> > if(resp==0x00){ // Ready
> > print("SD successfully activated!!!\n");
> > break;
> > }
> > }
> >
> > if(resp != 0x00){
> > print("Error: ");
> > print("0x"); printnum(16, 8, 0, '0', resp); print("\n");
> > }
> >
> > }
> > print("\n-------end-----------\n");
> >}
> >
> >
> >unsigned char SD_Response(void) {
> > unsigned char i;
> > unsigned char resp;
> >
> > for(i=0; i<10; i++) {
> > resp = spiGetByte();
> > if(resp != 0xFF) {
> > return resp;
> > }
> > }
> > return 0xFF;
> >}
> >
> >void SD_SendCommand(unsigned char command, unsigned char arg_a,
> >unsigned char arg_b, unsigned char arg_c, unsigned char arg_d) {
> > spiSendByte(command);
> > spiSendByte(arg_a);
> > spiSendByte(arg_b);
> > spiSendByte(arg_c);
> > spiSendByte(arg_d);
> > spiSendByte(0x95); // correct CRC for first command in SPI after
> >that CRC is ignored, so no problem with always sending 0x95
> >}
> >
> >
>



I've had a few queries in regards to SD card initialization in SPI mode.
For anyone who is interested I have included a dump of the SPI activity
during an init. There are two examples, the first with a SANDISK 512M
Ultra, and the second with a generic 128M SD.

The SD & FAT code are written in a Forth that I have written for the
LPC2000s. Since this is not everyones cup of tea, I have included a
simple dump of the activity of the SD interface. Comments are as normal
and bytes that are read are prefixed with "r", those that are written
with "w".

Although it is possible to issue a CMD1 following a CMD0, the SANDISK SD
CARD product manual states that ACMD41 should be used. This avoids
confusion with MMC cards but read what SANDISK have to say in section
5.8. Apparently ACMD1 is an illegal command for the thin cards in SPI mode.

The dummy read at the start of the CMD is just to make sure that the SD
interface is synchronized etc. This is easier than putting dummy reads
at the end of transfers .

One thing that didn't show-up on the 128M cards but did on the 512M was
when I was accessing high memory around 300MBs up. I would find that the
data token response on a read block request was taking a lot longer. I
had to either introduce a delay of 1ms in each loop or increase the
retry counter from 8 to 4000!!! (I am running at 16Mhz SPI rate).

Hope this is useful.

*Peter*

;*************************** SD CARD INITIALIZATION ************************ ; *** Initialize a Sandisk 512M SD CARD ***

VDD OFF
CS ON
5ms
VDD ON
1ms

; Dummy clocks
CS ON
rFF rFF rFF rFF rFF rFF rFF rFF rFF rFF
CS OFF
wFF wFF

; CS is asserted to ensure that all interfaces lines are at VSS (no
power whatsoever)
CS ON
rFF rFF
CS OFF
5ms

; CMD0
CS ON
rFF w40 w00 w00 w00 w00 w95 rFF r01

; ACMD41 until response = 0
CS ON
rFF w77 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w69 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w77 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w69 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w77 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w69 w00 w00 w00 w00 w95 rFF r00

; Read OCR
CS ON
rFF w7A w00 w00 w00 w00 w95 rFF r00
r80 rFF r80 r00

; Read CID
CS ON
rFF w4A w00 w00 w00 w00 w95 rFF rFF r00
rFE
r03 r53 r44 r53 r44 r35 r31 r32 r57 r50
r3D r11 r89 r00 r51 r5F rFD rA2 rFF

; Read CSD
CS ON
rFF w49 w00 w00 w00 w00 w95 rFF rFF r00
rFE
r00 r26 r00 r32 r1F r59 r83 rC7 rBE rFB
r4F rFF r92 r40 r40 r3F rF9 rAF rFF
CS OFF ; *** Initialize a generic 128M SD CARD ***

VDD OFF

CS ON
5ms
VDD ON
1ms
CS ON
rFF rFF rFF rFF rFF rFF rFF rFF rFF rFF
CS OFF
wFF wFF
CS ON
rFF rFF
CS OFF
5ms

; CMD0
CS ON
rFF w40 w00 w00 w00 w00 w95 rFF r01

; ACMD41
CS ON
rFF w77 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w69 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w77 w00 w00 w00 w00 w95 rFF r01
CS ON
rFF w69 w00 w00 w00 w00 w95 rFF r00

; Read OCR
CS ON
rFF w7A w00 w00 w00 w00 w95 rFF r00
r80 rFF r80 r00

; Read CID
CS ON
rFF w4A w00 w00 w00 w00 w95 rFF r00
rFF rFE
r04 r00 r00 r44 r30 r35 r30 r37 r00 r02
r02 r8E r69 r00 r48 rFB r6E r4B rFF

; Read CSD
CS ON
rFF w49 w00 w00 w00 w00 w95 rFF r00
rFF rFE
r00 r7F r00 r32 r1F r59 r83 rC9 rF6 rDA
r3F r9F r96 r60 r00 r2D r76 rB7 rFF
CS OFF