pic with mmc circuit

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
sorry, by mistake i have posted same in other thread also....

I am using pic18lf452 to write image data(HEX) on MMC and then read back.
MCC 18 platform is used while ICD 2 is used for programming.
I have simulated code on PROTEUS and its working. But on hardware I am facing the problem.

pic and mmc communicating in SPI mode.
MMC is accepting cmd0(reset) and cmd1(initialization), but not other cmds. I am sending cmd16 after cmd0&1 to set block length but every time i get a timeout.
I have used voltage divider to bring 5v of pic to 3.3v for mmc.
If anybody has any idea regarding this please post.
Thanks in advance.
 

steinar96

Joined Apr 18, 2009
239
Voltage dividers are quite bad for this usage. It's very poorly regulated and ineffecient. Varying loads means changing voltages. The mmc might easily lock up if it can't handle voltage swings around the 3.3V point very well.
 

mik3

Joined Feb 4, 2008
4,846
Use voltage regulator IC top regulate the voltage down to 3.3V. The voltage of a voltage divider varies with current.
 

davebee

Joined Oct 22, 2008
539
According to a Sandisk SD document:

"The default block length is as specified in the CSD (512 bytes). A set block length of less than 512 bytes will cause a write error. The only valid write set block length is 512 bytes. CMD16 is not mandatory if the default is accepted."

I don't know if MMC cards are just like SD cards for this command, but they are identical in many ways, so maybe your MMC card has a restriction on what a valid block length may be.

Maybe it would make sense for you to first go with the default blocklength of 512 bytes, get basic data reads and writes working, then try changing the blocklength if you really need to.
 

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
Thanks 4 ur ideas
@davebee
I made some changes in my code. Now I am sending mmc block write cmd instead of cmd for setting blocklength after cmd 0&1. But still I am getting a timeout, that is cmd is not accepted. so ultimately the situation is same.
 

davebee

Joined Oct 22, 2008
539
Why not start with getting a read to work instead of a write?

If the card is initialized properly, you should be able to read the card information register with command 9. Many of the information fields have known bit settings, so they make good tests of whether your read command is being accepted and whether your data retrieval code is correct.

Another thing you could do is format the card for a PC FAT filesystem then verify that the DOS FAT signature $55AA is correctly read from the last two bytes of sector zero.

I would say forget about trying to write to the card until you can show a working read.
 

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
Hello all
@davebee thanks 4 ur idea i ll try read in place of write.

But I want to share something about latest status as I have 18LF452, I can operate it at 3.3V also. In that case there is no need of voltage divider before mmc and I have connected spi pins of pic and mmc directly but still write cmd wasn't accepted after cmd0 &1.

Now I ll try read also.
 

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
Hello all

I tried sending read command , CSD command after cmd 0 & 1 but all in vain.
neither read nor CSD command's response is 0x00 ie cmd itself is not accepted.
i cant understand its a problem of code or hardware.

Here is some part of code i am using

int mmc_read_block(unsigned long block_number)
{
unsigned long i;
//unsigned long varh,varl;

//varl=((block_number&0x003F)<<9);
//varh=((block_number&0xFFC0)>>7);

SPI_CS = 0; // set SS = 0 (on)

SPI_WRITE(0x51); // send mmc read single block command
SPI_WRITE(0x00)); // arguments are address
SPI_WRITE(0x00));
SPI_WRITE(0x00));
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
SPI_WRITE(0xFF); //dummy

if((mmc_response(0x00))==1) return 1; // if mmc_response returns 1 then we failed to get a 0x00 response (affirmative)

puts("Got response to read block command\n\r");

if((mmc_response(0xFE))==1) return 1; // wait for data token

puts("Got data token\n\r");

for(i=0;i<512;i++)
{
SPI_READ(); // we should now receive 512 bytes
}

SPI_READ(); // CRC bytes that are not needed
SPI_READ();

SPI_CS=1; // set SS = 1 (off)
SPI_WRITE(0xFF); // give mmc the clocks it needs to finish off

puts("\n\rEnd of read block\n\r");

return 0;
}

I am getting return 1 ie command response is not correct

Thanks
 

Papabravo

Joined Feb 24, 2006
12,388
In the specification JEDS84-B41, section 9.5.7, p.90, it says:
 
The host must poll the card (by repeatedly sending CMD1) until the ‘in-idle-state’ bit in the card response indicates (by being set to 0) that the card has completed its initialization processes and is ready for the next command.

In my implementation, which responds only to manual input from the keyboard, it takes two CMD1 commands before the "In-Idle-State" bit goes to '0'. You did not say what value was returned in the R1 status byte, but I'm guessing it was a value like 0x05, which means that the card was still "In-Idle-State" and there was an illegal command/switch.

After the second CMD1 the "In-Idle-State" bit was 0 and I have successfully issued commands CMD10 to read the CID register, CMD13 to read the status, and CMD58 to read the OCR.

 

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
@ papabravo
In my code i am sending cmd0 once after that cmd1 with polling ie i ll be sending cmd1 again n again (255 times before timeout) until it gets 0x00.
I am comparing return of SPI_Read with 0x00 only.
right now i am not with hardware but at best of my knowledge i was also getting cmd1 acceptance response after sending it twice.

Thanks
 

Papabravo

Joined Feb 24, 2006
12,388
The other point is that you really should get copies of the JEDEC specs for the MMC cards. The SD card specs from San-Disk will lead you astray.
 

davebee

Joined Oct 22, 2008
539
What does your mmc_response($FE) call do?

Looking over code that's worked for me, I've found that after enabling the CS, sending $51, sending the 4 byte address, then $FF, I had to loop repeatedly, several hundred times sometimes, sending $FF and looking for $FE in the response, in order to allow the card time to perform the read.

Could it be that your mmc_response($FE) isn't allowing the card enough time before it declares failure?
 

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
@davebee
here is my mmc_response function
I hav one doubt, i can check for response ($FE) once i get cmd response as ($00). In my code iam getting timeout at cmd response itself.
I hav plan to make few changes in code, i will implement and thn come back.

Thanks

int mmc_response(unsigned char response)
{
long count = 0x2FFF; // 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
unsigned char r;

while(--count > 0)
{ r=ReadSPI();
if(r==response)
{ break;
}

}

if(count==0) return 1; // loop was exited due to timeout
else return 0; // loop was exited before timeout
}
 

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
Hello to all
In my ckt i am getting 0xFF as cmd response for any cmd i send after cmd0&1 which is very doubtfull as no cmd response can have MSB 1,
while i am getting correct cmd response for cmd 0 &1.
is it a hardware problem???
any idea................................
 

Thread Starter

pankajkumar

Joined Apr 15, 2009
9
void delay()
{
for(q=0;q<9555;q++)
;
}

int mmc_init()
{

OpenSPI(SPI_FOSC_16,MODE_00,SMPEND);//SMPMID); //MODE_00 is CKE=1; CKP-0
//OpenSPI(SPI_FOSC_16,MODE_00,SMPMID); //MODE_00 is CKE=1; CKP-0

SPI_CS = 1;
delay();delay();delay();delay();

for(i=0;i<10;i++) // initialise the MMC card into SPI mode by sending clks on
{
WriteSPI(0xFF);
}

SPI_CS = 0; // enable slave
delay();delay();delay();delay();

WriteSPI(0xFF);
WriteSPI(0x40); // send reset command
WriteSPI(0x00); // all the arguments are 0x00 for the reset command
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x95); // precalculated checksum as we are still in MMC mode
WriteSPI(0xFF);
r1=ReadSPI();

if(r1!=0x01)
return 1; // timeout

i = 0;
while((i<255))
{ WriteSPI(0xFF); //dummy bytes
WriteSPI(0x41); // send mmc command one to bring out of idle state
WriteSPI(0x00); // all the arguments are 0x00 for command one
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0xFF);
WriteSPI(0xFF);
r1=ReadSPI();

if(r1==0x00)
break;
i++;
} // must keep sending command if response

if(i >= 254) return 2; // timeout
SPI_CS = 1;
return;
}

int mmc_read_block(unsigned long block_number)
{
long i;
SPI_CS = 0; // SS portc<4> enables slave ,SS = 0
delay();delay();delay();
WriteSPI(0xFF);
WriteSPI(0x51); // send mmc read single block command
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x64);
WriteSPI(0x00);
WriteSPI(0xFF); // checksum is no longer required but we always send 0xFF
WriteSPI(0xFF);
r1=ReadSPI();

if(r1!=0x00)
return 2; // timeout
-
-
-
I am geting timeout here as r1 is 0xFF which has MSB 1........
 

davebee

Joined Oct 22, 2008
539
My working code seems pretty much like yours, except in your routine

int mmc_read_block(unsigned long block_number)
{
long i;
SPI_CS = 0; // SS portc<4> enables slave ,SS = 0
delay();delay();delay();
WriteSPI(0xFF);
WriteSPI(0x51); // send mmc read single block command
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x64);
WriteSPI(0x00);
WriteSPI(0xFF); // checksum is no longer required but we always send 0xFF
WriteSPI(0xFF);
r1=ReadSPI();
...

where your code makes the single call to "r1=ReadSPI()" and expects 0x00,my code loops up to 256 times, sending $FF and checking the result for the return code "$FE".

Maybe my code ignores a "command accepted" response and just waits for the "command completed" response, I'm not sure, but this has worked for me, so you might try it and see if it works.
 
Top