SD card access


27 posts   Page 1 of 2   1, 2
by hldswrth » Tue Sep 18, 2012 5:53 pm
OK, so I really wanted to sort this out by myself, but after a day of banging my head against a wall I'm hoping someone can help. I've seen another thread about SD card access through the eMMC interface, and read various pages and specs, but fail to get past the first hurdle.
Here's what my code is doing:

Code: Select all
  // Full reset, wait until the reset bit is cleared.
  *EMMC_CONTROL0 = 0;
  *EMMC_CONTROL1 = C1_SRST_HC;
  *EMMC_CONTROL2 = 0;
  while( *EMMC_CONTROL1 & C1_SRST_HC );
  // Set the clock - I've tried including various values for the divider...
  *EMMC_CONTROL1 = C1_CLK_EN | C1_CLK_INTLEN;
  while( !(*EMMC_CONTROL1 & C1_CLK_STABLE) );
  // Enable interrupts for errors which occur during setup commands.
  *EMMC_IRPT_EN   = INT_CMD_COMPLETE_MASK;
  *EMMC_IRPT_MASK = INT_CMD_COMPLETE_MASK;
  // Send GO_IDLE_STATE command
  *EMMC_INTERRUPT = 0;
  *EMMC_ARG1 = 0;
  *EMMC_CMDTM = 0 << 24;  // GO_IDLE_STATE = index 0, I know, shift does nothing 
  // Wait for some sort of response.
  while( !(*EMMC_INTERRUPT & INT_CMD_COMPLETE_MASK) );


After doing this, what I see in the RESP0 register is the value 0, when its supposed to be 1. The rest, i.e. waiting for the command to complete, appears at least to work fine.
What I'm not certain about is:
1) what's the actual int value that should be written to CMDTM for CMD0?
2) should the command value include the CMD_RSPNS_TYPE flag (10)? If I include that when I set the command I get a timeout error in the interrupt register...
3) Is the reset/clock part necessary? What divider value should I be using? Is there any additional setup code I'm missing?
4) Should I be looking in RESP0 or RESP3? RESP3 seems to have values in it which change somewhat depending on how I mess with the code above - the high byte is either 0x05 or 0x07...

Thanks for any help in advance
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Wed Sep 19, 2012 7:24 am
Hi
I'm working in the same subject; today, I can read the first sector of any (?) SD card
After a lot of tries and bug and tests with scope ...
I'm using the following setup (not optimized ...)

Init:


*pCONTROL0 = 0x00100000;
*pCONTROL1 = 0x000F0F27;
*pCONTROL2 = 0x00000000;

SendCMD00:
*pARG1 = 0x00000000;
*pCMDTM = 0x00000010;

SendCMD08:
*pARG1 = 0x000001AA;
*pCMDTM = 0x08030010;

...

In my documentation (SD specs part 1 simplified 2.00 sept 25, 2006), no response for CMD0

Good luck
Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by hldswrth » Wed Sep 19, 2012 8:57 am
Thanks for the response. There are a few differences in your flag settings that I'll try when I get back to my pi - in particular setting the control1 programmable clock flag and command multi-block transfer flag.

I'm confused about the response to CMD0 - every example I've seen looks for a response of 0x01 indicating that the card is idle once CMD0 returns. Does that 0x01 appear in RESP0 or somewhere else?

Also did you have to do anything with GPIO pins to make this work? The Broadcom spec says "Because the EMMC module shares pins with other functionality it must be selected in the
GPIO interface" - although the GPIO section doesn't state which how that might be done.

Cheers, Simon
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Wed Sep 19, 2012 9:39 am
There is an error in the GPIO documentation:
GPIO of SD (46 - 53) must be programmed in alt 3 mode (FSEL = 7) and not in alt 0 mode.
But I don't program these pins because they are already correctly initialized.
Some CMDs don't send any resp in my documentation: CMD0, CMD4, CMD15, ...
For me, the end of exec is with INTERRUPT bits 1 and 0.
STATUS bits 2 - 0 are busy signals
If they are active after time out, you have a problem ...

Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by hldswrth » Wed Sep 19, 2012 9:57 am
So reading the simplified spec (section 7.3.1.3) it shows that if CMD0 enters SPI mode then the expected resp type is R1 (and not no response). I'm confused as to whether SPI mode is necessary/expected and from the point of view of accessing the card whether it actually makes any significant different to the commands. Also I can't see any direct access to the CS line through the PI's EMMC registers so not sure how to assert SPI mode (other than possibly through CONTROL0).
Cheers, Simon
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Wed Sep 19, 2012 11:37 am
hldswrth wrote:So reading the simplified spec (section 7.3.1.3) it shows that if CMD0 enters SPI mode then the expected resp type is R1 (and not no response). I'm confused as to whether SPI mode is necessary/expected and from the point of view of accessing the card whether it actually makes any significant different to the commands. Also I can't see any direct access to the CS line through the PI's EMMC registers so not sure how to assert SPI mode (other than possibly through CONTROL0).
Cheers, Simon

In my opinion, I'm not in SPI mode:
- no R1 to CMD0
- CMD3 necessary to get RCA
- CMD7 necessary to select the board with RCA
I don't know if it is possible to change dynamically the mode (SPI or NOT). You can try to program the GPIO pin of CS in mode output before CMD0.
Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by hldswrth » Wed Sep 19, 2012 12:34 pm
Following your sequence of commands exactly, I get stuck on CMD0... the status register gets bit 0 set to indicate command in progress, but that never resets and the interrupt bit indicating complete never gets set. If I remove the CONTROL0 SPI_EN bit then I at least get the interrupt from CMD0 but then my CMD8 returns with "timeout" in interrupt
i.e. sending:
CONTROL0 = 0x00100000
CONTROL1 = 0x000F0F27
CONTROL2 = 0x00000000
ARG = 0x00000000
CMDTM=0x00000010
I get the following with no change to status or interrupt afterwards:
STATUS=0x017f0001, INTERRUPT=0x00000000

I did get GPIO FSEL setting, it looks like 48-53 are set to ALT3 anyway, I set 46 and 47 to ALT3 but it made no difference.
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by DexOS » Wed Sep 19, 2012 3:26 pm
Have you read this viewtopic.php?p=166470#p166470
Also seen the RISC OS code ?.
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by hldswrth » Wed Sep 19, 2012 4:28 pm
Yes I read that thread, was trying to execute the command sequence (or similar). Looking at that SDIO asm code, it seems mostly about setting GPIO (which people claim is already set up), and calculating the clock divider. I don't see any actual SD commands in there.
Right now I've tried my code out on two cards, one SDHC and one older. The furthest I've managed to get is with:
CONTROL0 = 0;
CONTROL1 = 0x00007c07;
CONTROL2 = 0;
IRPT_EN = 00110003
IRPT_MASK = 00110003
The older card leaves the low bit of STATUS set after calling SEND_IF_COND (returning with timeout), and doesn't seem to ever switch it off again. The newer one gets to ACMD41 having echoed 1AA to CMD8, but then returns a timeout for ACMD41.
I've booted linux off both these cards so I know they do work.
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Wed Sep 19, 2012 4:58 pm
CONTROL1 = 0x00007c07;
Your time out is very very short ...

In my sample I have a tempo of 100 mS betwen the calls.
In my Init sequence, I have
*pCONTROL1 = 0x070F0000; // Reset DATA/CMD/HC
tempo(100)
*pCONTROL1 = 0x000F0000;
tempo(100)

*pCONTROL0 = 0x00100000;
*pCONTROL1 = 0x000F0F27;
*pCONTROL2 = 0x00000000;
*pIRPTMASK = 0xffffffff; // validate all interrupts
tempo(500);

Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by DexOS » Wed Sep 19, 2012 5:08 pm
The problem your going to have is that once you get it working, it will work with one card but not another.
I try to keep things simple when coding, so to that end, i let the bootloader do the monkey work.
Just stick a image file (floppy or hdd etc) to the end of your kernel.img keep your programs in that.
You can not write to it, but you can not have everything.
Loading files is supper fast ;) .
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by phil95 » Wed Sep 19, 2012 5:19 pm
Sorry but my sequence is working with all cards I have tested.
(only 5, but differents manufacturers, differents sizes and SD & SDHC boards).
I wrote that driver for another board with ARM some months ago.
And it is very interesting for a stand alone soft to write on the SD card.
Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by DexOS » Wed Sep 19, 2012 5:49 pm
phil95 wrote:Sorry but my sequence is working with all cards I have tested.
(only 5, but differents manufacturers, differents sizes and SD & SDHC boards).
I wrote that driver for another board with ARM some months ago.
And it is very interesting for a stand alone soft to write on the SD card.
Philippe

I am glad to hear, if you need more SD card tests let me know and you can send me a img file, i have about 10 cards :)
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by hldswrth » Wed Sep 19, 2012 8:13 pm
Well with some fiddling around I've made a bit of progress; with both an old card and new I've got as far as ACMD41 (HCS 1 for the new card, 0 for the old one).

I'm using CONTROL1 = 0x000F0F25 (although only 0x00000F05 are relevant this far through init). If I set CONTROL0 = 0x00100000 I don't get so far with either card.
I have to reset the slow card after the CMD8 as the status command inhibit flag gets stuck high.

However in both cases what I get back from the ACMD41 is 0x00FF8000. This would appear to show that all voltages are available (bit 15 to 23), but bit 31 being 0 means the card is busy and I'm supposed to wait until bit 31 is set, but however long I wait (5 seconds or more) that never happens.
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Wed Sep 19, 2012 8:38 pm
What do you put in arg1 register ?
Try
*pARG1 = 0x40FF0000;
*pCMDTM = 0x2F020010;
Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by hldswrth » Wed Sep 19, 2012 9:02 pm
I was putting 0x50000000. I tried 0x50FF0000 but get the same response, no complete bit gets set.
btw the code I write for ACMD41 is 0x29020000 ... 0x2f is not a valid command index is it (would be ACMD47..?).
I tried continuing past this to do a CMD2 but that returns with a timeout interrupt, I assume because the ACMD41 has not properly completed.
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by hldswrth » Wed Sep 19, 2012 9:59 pm
Well not entirely sure what I changed ^^ I added longer delays between the ACMD41 calls and now I'm getting the top bit set (hooray!). Getting a successful response to CMD2 now so hopefully I can make some progress.
Thanks for your responses :)
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by bjraval » Sat Oct 27, 2012 3:26 am
hldswrth wrote:Well not entirely sure what I changed ^^ I added longer delays between the ACMD41 calls and now I'm getting the top bit set (hooray!). Getting a successful response to CMD2 now so hopefully I can make some progress.
Thanks for your responses :)


I have been trying to set up the sd card and initialize it. Can you help me with it?
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am
by hldswrth » Wed Oct 31, 2012 12:16 am
I can certainly try to help with specific questions, although I'm not the expert in this stuff. I've managed to get as far as basic reading and writing to the SD card, although not without my own unresolved issues.
Posts: 97
Joined: Mon Sep 10, 2012 4:14 pm
by bjraval » Wed Oct 31, 2012 4:07 pm
hldswrth wrote:I can certainly try to help with specific questions, although I'm not the expert in this stuff. I've managed to get as far as basic reading and writing to the SD card, although not without my own unresolved issues.


Hello,
I'm still stuck at Initializing the SD card. If its fine can I borrow your code for initialization?
Thank you,
Brijen
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am
by bjraval » Fri Nov 02, 2012 1:29 am
Here is what I use to initialize my SD card

Code: Select all
void sd_init()
{
    unsigned int m;
    unsigned int test;
    PUT32(CONTROL0,0x00100000);
    PUT32(CONTROL1,0x070F0F27);
    PUT32(CONTROL2,0x00000000);

    do
    {
        m = GET32(CONTROL1);
        test = m & 0x10000000;
    }while(test!=0);  //Waiting it to reset

    PUT32(CONTROL0,0x00100000);
    PUT32(CONTROL1,0x000F0F27);
    PUT32(CONTROL2,0x00000000);
    PUT32(IRPT_MASK,0xFFFFFFFF);

    do
    {
        m = GET32(CONTROL1);
        test = m &  0x00000002;
    }while(test!=2); //Waiting for clock to be stable

   

    //GO_IDLE_STATE
    PUT32(ARG1,0x00000000);
    PUT32(CMDTM,0x00000010);
   

    //SD_SEND_IF_COND
    PUT32(ARG1,0x000001AA);
    PUT32(CMDTM,0x08030010);
    wait();
   

    unsigned int check;
    //APP_CMD
    PUT32(ARG1,0x00000000);
    PUT32(CMDTM,0x37020000);
    wait();
   

    do
    {
        //SD_SEND_OP_COND (repeat until Powerup bit is set)
        print_s("\n\rIN2 ");
        PUT32(ARG1,0x40FF0000);
        PUT32(CMDTM,0x29020000);
        wait();
        check = GET32(GET32(RESP3));
        hexstrings(check);
        check = check & 0x80000000;
        hexstrings(check);

    }while(check == 0);

    //ALL_SEND_CID
    PUT32(ARG1,0x00000000);
    PUT32(CMDTM,0x02020000);


After doing this, following is what I get


After CMD0 ---- STATUS : 01FF0000 INTERRUPT : 00000041
After CMD8 ---- STATUS : 01FF0000 INTERRUPT : 00000043 RESP0 : 000001AA
After CMD55 --- STATUS : 01FF0000 INTERRUPT : 00000043 RESP0 : 00000120
After ACMD41-- STATUS : 01FF0000 INTERRUPT : 00000043 RESP3 : EA00000E RESP0 : FFFFFFFF
After CMD10 --- RESP0 : 00FF8000


Any idea what might be going wrong?

Thank you,
Brijen
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am
by phil95 » Sat Nov 03, 2012 9:24 pm
Hello,
When you have an error with CMD 41, you must resend CMD 55 and CMD 41, not only CMD41.
The command is ACMD41 and contain CMD 55 AND CMD 41
I think, in your code, you resend only CMD41.
Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by bjraval » Sat Nov 03, 2012 11:09 pm
phil95 wrote:Hello,
When you have an error with CMD 41, you must resend CMD 55 and CMD 41, not only CMD41.
The command is ACMD41 and contain CMD 55 AND CMD 41
I think, in your code, you resend only CMD41.
Philippe


Thanks Philippe,
What I have a doubt is
1. is my CMD55 RESP0 right?
2. For CMD41 which high bit should I be checking? RESP0 or RESP3 ?
3. RESP0 seems to return 0xFFs always...do I need to wait before checking?

Thanks,
Brijen.
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am
by phil95 » Sun Nov 04, 2012 8:02 am
Hello
I'm testing *pRESP0 & 0x80000000
If you don't read RESP0, it will be shifted later to RESP1, RESP1 to RESP2, ...
as in a queue of 16 bytes.
For testing, you can loop for a long time (2 or 3 seconds).
For me, I'm looping only 5 or 10 mSec and restart to reset and CMD 0 to check
if the card is still present ...
Philippe
Posts: 114
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by bjraval » Mon Nov 05, 2012 6:41 am
phil95 wrote:Hello
I'm testing *pRESP0 & 0x80000000
If you don't read RESP0, it will be shifted later to RESP1, RESP1 to RESP2, ...
as in a queue of 16 bytes.
For testing, you can loop for a long time (2 or 3 seconds).
For me, I'm looping only 5 or 10 mSec and restart to reset and CMD 0 to check
if the card is still present ...
Philippe


Thanks much for the reply.
Adding the delay did the job. Now I shall get it reading and writing data.
Thanks everyone for the help.

- Brijen
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am