EMMC - can't get READ_RDY


23 posts
by 9pi » Sat Aug 11, 2012 7:19 pm
I'm writing a driver for the SD/MMC host interface, working from information in the BCM2835 datasheet and the official SD card "simplified specifications". I'm able to set up the card, fetch the CID and CSD registers, and select it into transfer state. I issue commands SET_BLOCKLEN(512) and READ_SINGLE_BLOCK(0), which terminate with no errors. I then loop waiting for the READ_RDY bit to appear in the Interrupt register to show that data is available in the fifo, but it never sets (nor does any error bit - the Interrupt register just stays at zero). And yes, I have enabled all the bits in the Irpt_mask register.

I've probably missed out some small but essential step. Any suggestions?
Posts: 31
Joined: Sat Aug 11, 2012 6:14 pm
by DexOS » Sat Aug 11, 2012 8:00 pm
I have not looked into this myself, but did noticed some low level SD/MMC code in the PI's RiscOS port.
Maybe that will help.
Batteries not included, Some assembly required.
User avatar
Posts: 869
Joined: Wed May 16, 2012 6:32 pm
by 9pi » Sat Aug 11, 2012 8:21 pm
DexOS wrote:I have not looked into this myself, but did noticed some low level SD/MMC code in the PI's RiscOS port.

Thanks - where can I find the source code?
Posts: 31
Joined: Sat Aug 11, 2012 6:14 pm
by Cycl0ne » Sat Aug 11, 2012 10:28 pm
PI's RiscOS port.

-> Its completely in Assembler, you find it through google: riscos -> and there si a raspberry pi branch.

I finished my MMC driver and what i noticed, it is veryyyyyyyy buggy and you have to delay some commands. i also had this error when fetching data from the device. i increased my wait() tremendously.

twoticks delay is about 1/3 second. but this is only in the first initialisations. when the chip is up and you have pulled the mhz to its fast speed mode, you can cut down the delay to the 2 ticks.

the initialisation often not works on first time, so i made a loop and bang this chip 2 or 3 times (seldom 3 but 2 times i need for initialisation):

Code: Select all

{
   twoticks_delay = ((2000000000ULL/MIN_FREQ) + 1)*get_tbclk()/1000000;
   twoticks_delay = (twoticks_delay + 1000 - 1) / 1000;
}

inline static void bcm2835_sdhci_raw_writel(struct sdhci_host *host, u32 val, int reg)
{

   /*
    *The Arasan has a bugette whereby it may lose the content of
    * successive writes to registers that are within two SD-card clock
       * cycles of each other (a clock domain crossing problem).
    * It seems, however, that the data register does not have this problem.
    * (Which is just as well - otherwise we'd have to nobble the DMA engine
    * too)
    */
   while (get_timer(last_write) < twoticks_delay) {}
   writel(val, host->ioaddr + reg);
   last_write = get_timer(0);

   if (host->mmc->clock <= MIN_FREQ) {
      udelay(50000);
   }

   if ((reg != SDHCI_BUFFER && reg != SDHCI_INT_STATUS && reg != SDHCI_CLOCK_CONTROL)
       && host->mmc->clock > MIN_FREQ)
     {
      int timeout = 100000;
      while (val != readl(host->ioaddr + reg) && --timeout > 0)
         continue;

      if (timeout <= 0)
         printf("bcm2835_sdhci: writing 0x%X to reg 0x%X "
               "always gives 0x%X\n",
               val, reg, readl(host->ioaddr + reg));
   }

}


you should also have a look into the linux source, they are always fiddling too there and they also found a new solution (but i havent looked into it atm).

https://github.com/raspberrypi/linux/blob/rpi-patches/drivers/mmc/host/sdhci.c
User avatar
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am
by DexOS » Sun Aug 12, 2012 12:53 pm
9pi wrote:
DexOS wrote:I have not looked into this myself, but did noticed some low level SD/MMC code in the PI's RiscOS port.

Thanks - where can I find the source code?

You can get it here: https://www.riscosopen.org/zipfiles/sou ... 1344754809
All the information you need is in the directory mixed/RiscOS/Sources/HAL/BCM2835/S/SDIO

Yes its in assembly 8-), but it as a lot of comments and the comments have a lot of good info about what is needed.
Batteries not included, Some assembly required.
User avatar
Posts: 869
Joined: Wed May 16, 2012 6:32 pm
by 9pi » Sun Aug 12, 2012 7:10 pm
Thanks for the pointers to source code. I prefer not to read linux source unless I'm really really desperate. And it turns out there is more to the RiscOS SD driver than just that bit of assembly - in cddl/RiscOS/Sources/HWSupport/SD/SDIODriver there's another 5681 lines of C source and headers.

I don't think it's a delay problem - however much delay I put between register writes, the READ_RDY bit never appears. But looking at RiscOS, they are not using that bit, but instead polling bit 11 in the Status register to see when data is available. This contradicts the Broadcom datasheet which (a) says that bit is "reserved", and (b) says the status register is "not recommended for polling". However it is consistent with the SD HCI spec for a "Buffer Read Enable" bit at that position.

Using Status bit 11, my driver can now read blocks successfully from the card. Not the best solution, though, because that bit can't generate an interrupt.

Cycl0ne, are you managing to get a READ_RDY interrupt somehow, or are you using DMA and letting the DMA interrupt signal the availability of data?
Posts: 31
Joined: Sat Aug 11, 2012 6:14 pm
by DexOS » Sun Aug 12, 2012 7:45 pm
There are a lot of errors in the datasheet see here:
http://elinux.org/BCM2835_datasheet_errata

As a side note are you using a memory read barrier ?
Batteries not included, Some assembly required.
User avatar
Posts: 869
Joined: Wed May 16, 2012 6:32 pm
by Cycl0ne » Mon Aug 13, 2012 6:40 am
9pi wrote:Thanks for the pointers to source code. I prefer not to read linux source unless I'm really really desperate. And it turns out there is more to the RiscOS SD driver than just that bit of assembly - in cddl/RiscOS/Sources/HWSupport/SD/SDIODriver there's another 5681 lines of C source and headers.

I don't think it's a delay problem - however much delay I put between register writes, the READ_RDY bit never appears. But looking at RiscOS, they are not using that bit, but instead polling bit 11 in the Status register to see when data is available. This contradicts the Broadcom datasheet which (a) says that bit is "reserved", and (b) says the status register is "not recommended for polling". However it is consistent with the SD HCI spec for a "Buffer Read Enable" bit at that position.

Using Status bit 11, my driver can now read blocks successfully from the card. Not the best solution, though, because that bit can't generate an interrupt.

Cycl0ne, are you managing to get a READ_RDY interrupt somehow, or are you using DMA and letting the DMA interrupt signal the availability of data?



im polling.. not using interrupts at the moment.
User avatar
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am
by 9pi » Mon Aug 13, 2012 9:09 am
DexOS wrote:There are a lot of errors in the datasheet see here:
http://elinux.org/BCM2835_datasheet_errata

As a side note are you using a memory read barrier ?

Thanks, I've read the errata but there's nothing about EMMC there. Maybe I should add something?

Strictly speaking, the armv6 doesn't have a memory read barrier; I think the Data Memory Barrier is the closest equivalent. I haven't yet put in DMBs between accesses to different peripherals. Not yet convinced that they are necessary, as I'm doing all I/O access through MMU addresses marked as non-cached & non-buffered, and I haven't seen any suggestion that this arm core does out-of-order execution of instructions. Also it's not clear to me what is a "peripheral" - for example are the system and ARM timers on the AXI bus?
Posts: 31
Joined: Sat Aug 11, 2012 6:14 pm
by DexOS » Mon Aug 13, 2012 1:54 pm
Yes i would add something like theres a possible error on page ?, it says it reserved, but a example in RISCOS uses it and from your test it works.

Once you get your code fully working, a writeup of basic steps would be help full, no need for code, just basic steps.
Thanks.
Batteries not included, Some assembly required.
User avatar
Posts: 869
Joined: Wed May 16, 2012 6:32 pm
by Cycl0ne » Mon Aug 13, 2012 3:16 pm
DexOS wrote:Once you get your code fully working, a writeup of basic steps would be help full, no need for code, just basic steps.
Thanks.


Dont listen to Dexos, CODE is always welcomed ;) Even more if you have IRQ activated.
User avatar
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am
by dwelch67 » Mon Aug 13, 2012 5:30 pm
The BCM doc may be wrong (there are many errors, check the errata on the wiki page). I assume you are polling at the moment, what you can do is enable all interrupts and poll the interrupt status register to see what if anything is changing. I sorted out a uart doc bug this way. Some of those interrupts are used by the GPU and appear to be quite active, so when you see those just ignore them (dont enable them in your mask).

In particular if the BCM docs have "its just like this chip X except we dont support Y", I have found at least two instances where you actually have to set the Y bits to make the thing work even though they say you dont. So if this module is derived from a well known module, get the docs for the well known module and program it as if it were the real module, maybe you will find a missing bit needed to make it work.
Posts: 438
Joined: Sat May 26, 2012 5:32 pm
by gin » Tue Sep 04, 2012 6:15 am
Has anyone had any luck getting this working? Everytime I try to set the response length flags I get the error bit set in the INTERRUPT register.

My setup routine is:

No setting up and GPIO selection register or pull up registers because it looks like eMMC is setup by default.

*CONTROL0 = 0
*CONTROL1 = CLK_INTLEN | CLK_EN
*CONTROL2 = 0

Then I try something like:
*ARG1 = 0;
*CMDTM = (CMD3 | IXCHK_EN | CRCCHK_EN | RESPONSE_48);

Is there anything I'm missing in my initialization sequence or does anyone know of any pitfalls they ran into trying to get this setup?
Posts: 12
Joined: Tue Aug 28, 2012 5:52 am
by 9pi » Wed Sep 05, 2012 9:36 am
gin wrote:Is there anything I'm missing in my initialization sequence or does anyone know of any pitfalls they ran into trying to get this setup?


Initialisation - what I do is:
- write Reset Host Controller to Control1, wait for bit to clear
- after writing clock divisor to Control1, wait for Clock Stable bit to set (and then wait another millisecond for good measure)

I start with a slower clock initially until the card is selected, but with SD cards this may not be strictly necessary.

If CMD3 is really the first thing you're sending the card, it may be a problem. The complete command sequence I use to set up the card initially is:

GO_IDLE_STATE
SD_SEND_IF_COND
APP_CMD, SD_SEND_OP_COND (repeat until Powerup bit is set)
ALL_SEND_CID
SEND_RELATIVE_ADDR
SEND_CSD
SELECT_CARD
SET_BLOCKLEN
APP_CMD, SET_BUS_WIDTH

You can leave out the BLOCKLEN and BUS_WIDTH if you keep the default values.
Posts: 31
Joined: Sat Aug 11, 2012 6:14 pm
by 9pi » Wed Sep 05, 2012 10:43 am
DexOS wrote:Once you get your code fully working, a writeup of basic steps would be help full, no need for code, just basic steps.
Thanks.


It seems the problem was underestimating the subtlety of the READ_RDY interrupt. It doesn't mean "data is available in the read fifo", it means "there has been a transition from data not available to data available". So before waiting for the READ_RDY interrupt, it's prudent to check whether data is already available, using the undocumented (by Broadcom) status bit 11.

An example of working code to read len words to address buf (word-aligned) after issuing a READ_SINGLE_BLOCK or READ_MULTIPLE_BLOCK command is:
Code: Select all
enum {
    Data      = 0x20>>2,
    Status    = 0x24>>2,
    Interrupt = 0x30>>2,
    ...
    Err       = 1<<15,
    Bufread   = 1<<11,
    Datadone  = 1<<1,
    Readrdy   = 1<<5,
    ....
};

unsigned int i, *r, *buf, len;
...
r = EMMCREGS;
while (len > 0) {
    if (r[status] & Bufread) {
        *buf++ = r[Data];
        --len;
        continue;
    }
    while (((i = r[Interrupt]) & (Readrdy|Err|Datadone)) == 0) {
        ... timeout exit if loop takes more than N seconds
    }
    if (i & (Err|Datadone)) {
        r[Interrupt] = i;
        ... error exit
    }
    r[Interrupt] = i;
}

But all this turns out to be unnecessary if you use DMA. The DMA channel does all the fifo handshaking itself, and you just have to wait for the DMA completion interrupt.
Posts: 31
Joined: Sat Aug 11, 2012 6:14 pm
by DexOS » Wed Sep 05, 2012 2:44 pm
Thanks for the info 9pi, i am sure it will be very helpful when i get round to coding my SD/MMC driver.
Batteries not included, Some assembly required.
User avatar
Posts: 869
Joined: Wed May 16, 2012 6:32 pm
by gin » Thu Sep 06, 2012 3:38 am
9pi wrote:If CMD3 is really the first thing you're sending the card, it may be a problem. The complete command sequence I use to set up the card initially is:

GO_IDLE_STATE
SD_SEND_IF_COND
APP_CMD, SD_SEND_OP_COND (repeat until Powerup bit is set)
ALL_SEND_CID
SEND_RELATIVE_ADDR
SEND_CSD
SELECT_CARD
SET_BLOCKLEN
APP_CMD, SET_BUS_WIDTH

You can leave out the BLOCKLEN and BUS_WIDTH if you keep the default values.

Thanks you so much! I got it working! I realized I was looking at the SPI documentation and was looking at eMMC startup sequences. Your steps worked perfectly.!

One thing I noticed for other people trying to get this working is to start out with decent sleeps (I did 10ms between command and when I tried to look at the response). I think it can be dialed down (I don't know if checking CRC and CMD add any response time) but just waiting on the INTERRUPT or STATUS flags wasn't always working for me (again I may be doing something dumb I might catch when I run through this again to clean it up).

Again - thanks a ton for the guide on how to get it set up! I'm excited to be able to right a file system for this thing! :P
Posts: 12
Joined: Tue Aug 28, 2012 5:52 am
by bjraval » Fri Nov 02, 2012 1:30 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 hldswrth » Fri Nov 02, 2012 11:34 am
Most common problem here seems to be that the ACMD41 typically takes a significant time - 100's of milliseconds. From what you list above, you are getting the response for the ACMD41 after the next command - the 00ff8000 response is the card agreeing on the voltage levels which you sent in the ACMD41 command.

The thing that threw me originally is that the CMD_DONE interrupt does not necessarily mean that the response has been received from the card, just that the command has been sent, so you cannot just assume the resp value is valid at that point, especially for ACMD41. The spec says that you need to leave up to 2 seconds for the response from ACMD41. I think my code waits 500ms after sending the command before checking interrupt for command complete and the response value, although I don't have access to it right now to check.
Posts: 101
Joined: Mon Sep 10, 2012 4:14 pm
by bjraval » Mon Nov 05, 2012 6:40 am
hldswrth wrote:Most common problem here seems to be that the ACMD41 typically takes a significant time - 100's of milliseconds. From what you list above, you are getting the response for the ACMD41 after the next command - the 00ff8000 response is the card agreeing on the voltage levels which you sent in the ACMD41 command.

The thing that threw me originally is that the CMD_DONE interrupt does not necessarily mean that the response has been received from the card, just that the command has been sent, so you cannot just assume the resp value is valid at that point, especially for ACMD41. The spec says that you need to leave up to 2 seconds for the response from ACMD41. I think my code waits 500ms after sending the command before checking interrupt for command complete and the response value, although I don't have access to it right now to check.



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
by bjraval » Sat Nov 17, 2012 8:39 pm
Any idea on how to read the sector 0 (Master Boot Record) ??

Thanks,
Brijen
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am
by hldswrth » Thu Nov 29, 2012 1:47 pm
Pass a block address of 0 to the read command?
There's a lot of information on wikipedia on the FAT file system and format of the information in the boot sector
Posts: 101
Joined: Mon Sep 10, 2012 4:14 pm
by maresja » Tue May 28, 2013 9:45 pm
bjraval wrote:
hldswrth wrote:Most common problem here seems to be that the ACMD41 typically takes a significant time - 100's of milliseconds. From what you list above, you are getting the response for the ACMD41 after the next command - the 00ff8000 response is the card agreeing on the voltage levels which you sent in the ACMD41 command.

The thing that threw me originally is that the CMD_DONE interrupt does not necessarily mean that the response has been received from the card, just that the command has been sent, so you cannot just assume the resp value is valid at that point, especially for ACMD41. The spec says that you need to leave up to 2 seconds for the response from ACMD41. I think my code waits 500ms after sending the command before checking interrupt for command complete and the response value, although I don't have access to it right now to check.



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


Hi, I am stuck in the same place, getting the 0x00ff8000 response after ACMD41, but i am not able to get it working after that. If I try to execute CMD2,CMD3 or CMD11 I get status 0x01ff0001, and if I understand it correctly, that means there is error executing last command. That is also signaled by interrupt status which is then 0x00018043 and after ACMD41 was 0x00000043. I wait for 500ms after every command just to be sure.

Brijen, can you please send your code after you get it working - successful switch data-transfer mode. Or if anyone can tell me what I am missing.

Thank you for reply. Jan
Posts: 1
Joined: Tue May 28, 2013 9:34 pm