pic with mmc circuit

Discussion in 'Embedded Systems and Microcontrollers' started by pankajkumar, Sep 9, 2009.

  1. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    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.
     
  2. steinar96

    Active Member

    Apr 18, 2009
    239
    4
    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.
     
  3. mik3

    Senior Member

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

    Well-Known Member

    Oct 22, 2008
    539
    46
    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.
     
  5. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    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.
     
  6. davebee

    Well-Known Member

    Oct 22, 2008
    539
    46
    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.
     
  7. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    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.
     
  8. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    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
     
  9. Papabravo

    Expert

    Feb 24, 2006
    10,157
    1,795
    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.

     
  10. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    @ 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
     
  11. Papabravo

    Expert

    Feb 24, 2006
    10,157
    1,795
    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.
     
  12. davebee

    Well-Known Member

    Oct 22, 2008
    539
    46
    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?
     
  13. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    @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
    }
     
  14. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    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................................
     
  15. davebee

    Well-Known Member

    Oct 22, 2008
    539
    46
    Can you show your initialization code?
     
  16. pankajkumar

    Thread Starter New Member

    Apr 15, 2009
    9
    0
    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........
     
  17. blueroomelectronics

    AAC Fanatic!

    Jul 22, 2007
    1,758
    98
    Please learn to use the code tags.
     
  18. davebee

    Well-Known Member

    Oct 22, 2008
    539
    46
    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.
     
Loading...