SD card second write produces timeout


21 posts
by hldswrth » Wed Oct 31, 2012 12:47 am
Making some progress with SD card access after some diversions around FAT, ELF and UART :)
I'm trying to get SD writing working, with some limited success.

It appears I can write one block successfully, but when I try to write a second block, after sending the second WRITE_SINGLE command I don't see a CMD_DONE interrupt, instead I get a DATA_TIMEOUT interrupt. At this point registers are:

Status: 0x01ef0107 (indicates DAT_ACTIVE/DAT_INHIBIT)
Resp: 0x00000900 (may be the value from the previous write command)
Interrupt: 0x00108000 (indicates DATA_TIMEOUT)

All I can think is that for some reason the previous block write has not completed, although as far as I can see the data is completely written and there on the card as expected.
Do I need to wait for the DAT_INHIBIT flag to drop from the status register before sending another WRITE_SINGLE command? I checked on entry to the second call and status before the command is 0x01ef0006, indicating DAT_ACTIVE|DAT_INHIBIT.

Here's how I do the data transfer (somewhat reduced):

*EMMC_BLKSIZECNT = (1 << 16) | 512;
// sendCommand waits for CMD_DONE interrupt;
// command value being sent is actually:
// 0x18000000|CMD_RSPNS_48 |CMD_IS_DATA|TM_DAT_DIR_HC
sdSendCommand(WRITE_SINGLE,blockAddress);
while( numWritten < 128 ) {
if( *EMMC_STATUS & SR_WRITE_AVAILABLE )
*EMMC_DATA = buffer[numWritten++];
else
waitCycle(150);
}

Thanks, Simon
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by hldswrth » Wed Oct 31, 2012 1:46 pm
With a bit more investigation, I added a 500ms wait after writing the last word.
I verified that all 512 bytes were correctly written to the card.
However after the 500ms wait, registers are:
status = 0x01ff0006 - indicating data still busy
interrupt = 0x00108010 - indicating data timeout
So simply waiting after writing the block doesn't seem to help. It seems like the card is expecting me to write more data, despite setting it up for a single block write of 512 bytes.
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by tritonium » Wed Oct 31, 2012 5:18 pm
Hi
I'm no C expert but the

while( numWritten < 128 ) {
.
.
*EMMC_DATA = buffer[numWritten++];

seems to indicate to me that you are only sending 128 bytes of the 512 so its waiting for more data (unless somehow each write is 4 bytes) :?

Nah thats too obvious....I expect I'm talking rubbish....

Dave
Posts: 78
Joined: Tue Jan 03, 2012 7:10 pm
by hldswrth » Wed Oct 31, 2012 10:33 pm
Yes, should have said the buffer is cast to int* so its 128 writes of 4 bytes at a time - and I've checked that the full 512 bytes are written correctly to the card.
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by hldswrth » Fri Nov 02, 2012 4:22 pm
Still failing to get this to work. I've tried all different variants of the command code and even sending extra bytes and still get a data timeout and the DAT_INHIBIT flag never clears from the status register after I do a single block write, although it does successfully write the 512 bytes I do send to the card.
The exact command value I'm setting is 0x18220000
which is CMD_INDEX = 0x18 (i.e. CMD24), CMD_ISDATA, 48 bit response, single block, transfer from host to card.
Anyone actually have a working WRITE_SINGLE implementation?
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Sat Nov 03, 2012 9:42 pm
Hello,
I have Write cmd working with
0x18230000 insteed 0x18220000
Philippe
Posts: 120
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by hldswrth » Sat Nov 03, 2012 11:40 pm
Thanks! that's one thing I had not tried. When I use that value (i.e. 48 bit response with busy) I don't get the data timeout interrupt any more. However now what I'm finding is that the first byte written in the second block is being written with an incorrect value for some reason, so I need to check that out.
Could I check a couple of things -

1) What do you wait for before you write data to the data register after the WRITE_SINGLE command?
I'm waiting for STATUS&0x00000400 to indicate write space is available, the alternative I see is waiting for INTERRUPT&WRITE_RDY.

2) What do you wait for after you have written data to know the write is complete? If I wait for DAT_INHIBIT or DAT_ACTIVE to be cleared from the STATUS register I time out. If I wait for the DAT0 bit in the STATUS register to go high, then it appears to work OK.

Thanks very much, Simon
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by hldswrth » Sun Nov 04, 2012 1:00 am
OK, looks like I spoke too soon. Once I removed all the debug console output and removed the get_status command I was sending after the write, I'm back to getting a data timeout in the interrupt register after the write has completed.
Another question about working implementations - do you sent a card_select (CMD7) before and after every read or write operation? As far as I can tell from the spec its not strictly necessary but wondering if it might help.
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Sun Nov 04, 2012 8:09 am
hldswrth wrote:OK, looks like I spoke too soon. Once I removed all the debug console output and removed the get_status command I was sending after the write, I'm back to getting a data timeout in the interrupt register after the write has completed.
Another question about working implementations - do you sent a card_select (CMD7) before and after every read or write operation? As far as I can tell from the spec its not strictly necessary but wondering if it might help.



For me, I send only one CMD7 in the initialisation process, the card is always selected.
Philippe
Posts: 120
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by phil95 » Sun Nov 04, 2012 8:20 am
hldswrth wrote:Thanks! that's one thing I had not tried. When I use that value (i.e. 48 bit response with busy) I don't get the data timeout interrupt any more. However now what I'm finding is that the first byte written in the second block is being written with an incorrect value for some reason, so I need to check that out.
Could I check a couple of things -

1) What do you wait for before you write data to the data register after the WRITE_SINGLE command?
I'm waiting for STATUS&0x00000400 to indicate write space is available, the alternative I see is waiting for INTERRUPT&WRITE_RDY.

2) What do you wait for after you have written data to know the write is complete? If I wait for DAT_INHIBIT or DAT_ACTIVE to be cleared from the STATUS register I time out. If I wait for the DAT0 bit in the STATUS register to go high, then it appears to work OK.

Thanks very much, Simon


I have read somewhere (where ?) that STATUS is not well accurate. Thus I'm always using INTERRUPT.(read bcm2835 arm peripherals P 72 top).
When I'm waiting for interrupt, I test by software for time out (if interrupt is not coming ...)
Philippe
Posts: 120
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by hldswrth » Sun Nov 04, 2012 2:35 pm
OK... but whatever means I use to check for when I can write, and when the write has finished, I'm still successfully writing all 512 bytes to the card, but then getting a data timeout in the interrupt and the data busy/inhibit flags in status never clear. Final thing to check, what value of CONTROL1 are you using?
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by phil95 » Sun Nov 04, 2012 3:01 pm
*pCONTROL1 = 0x00000027 | (TO << 16) | ((DIV & 0xFF) << 8) | (((DIV >> 8) & 0x3) << 6)
with
TO = 7
and
DIV = 25000000 / FREQ
AND
FREQ = 25000000

Philippe
Posts: 120
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by hldswrth » Sun Nov 04, 2012 7:20 pm
Philippe, thanks for that info. It looks like setting the timeout value in the control register was the bit I was missing. However using your divider setting does not work for my (2GB non-HC) card. I use a divider setting of 16 for both setup and transfer and that appears to work OK. I would expect that a divider value of 1 would be OK for HC cards which can run at 25Mhz, but that's an area I'd need to look into much more deeply to understand and implement a general solution.

For reference my CONTROL1 value ends up being: 00071007. The CLK_GENSEL flag (0x20) did not seem to make any difference one way or another.
I tried setting the timeout value to F which is supposed to mean disabled, but still got the timeout interrupt occurring.
Thanks again, hoping this is a permanent solution and I can get on and complete my FAT file create/update functions now :)
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by bjraval » Mon Nov 12, 2012 6:40 am
Hello,
I'm starting to read and write data blocks from the SD card.
It's a silly question but what block addresses should I be writing while sending the READ_SINGLE_BLOCK command?

Can someone give me an overview of how read and write block functions would work?

-Brijen
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am
by DexOS » Mon Nov 12, 2012 9:54 pm
From my tests it seems, to be 0 for the first block, then 512 for the next, then 1024 and so on.
That is what works, but too me, it should be 0, 1, 2, 3 etc.
This is if you use 512 block sizers.
Batteries not included, Some assembly required.
User avatar
Posts: 866
Joined: Wed May 16, 2012 6:32 pm
by hldswrth » Tue Nov 13, 2012 12:58 am
Looking at my code:

// Address passed in is byte offset from start of the card.
// Address is different depending on the card type.
// HC pass address as block # which is address/512.
// SC pass address straight through.
int blockAddress = sdCard.type == SD_TYPE_2_HC ? (int)(address>>9) : (int)address;
*EMMC_BLKSIZECNT = (1 << 16) | 512;
int resp = sdSendCommandA(READ_SINGLE,blockAddress);

HC cards can be identified by setting the HCS flag in the argument to ACMD41 and getting that bit back in the response. ( 0x40000000)
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by bjraval » Wed Nov 14, 2012 1:12 am
hldswrth wrote:Looking at my code:

// Address passed in is byte offset from start of the card.
// Address is different depending on the card type.
// HC pass address as block # which is address/512.
// SC pass address straight through.
int blockAddress = sdCard.type == SD_TYPE_2_HC ? (int)(address>>9) : (int)address;
*EMMC_BLKSIZECNT = (1 << 16) | 512;
int resp = sdSendCommandA(READ_SINGLE,blockAddress);

HC cards can be identified by setting the HCS flag in the argument to ACMD41 and getting that bit back in the response. ( 0x40000000)



Thank you everyone for the replies,

I did something similar to what you have done and I get my Interrupt and Status registers as follows

After the WRITE_SINGLE_BLOCK command
STATUS - 01FF0506
INTERRUPT - 00000053
RESP0 - 00000900

After writing data
STATUS - 01EF0106
INTERRUPT - 00000053
RESP0 - 00000900

It shows me all the time data can be written..

How do I verify if my write is done successfully ?

This is a part of my code
Code: Select all
//WRITE_SINGLE_BLOCK
PUT32(ARG1,0x00000005);
 PUT32(CMDTM,0x18230000);


//SEND_DATA

while(num_written<128)
    {
       //Not sure whether I should rely on the STATUS bits
        PUT32(DATA,0x00000066);
        num_written++;
    }




Am i doing anything stupid here?


-Brijen
Posts: 25
Joined: Sun Oct 07, 2012 4:04 am
by Arjan » Wed Feb 06, 2013 11:57 am
Hi Simon,

Is your code available on the Internet?

I am interested to look at it and see if it can be used for the FatFs module.

Thanks. Arjan
Posts: 131
Joined: Sat Sep 08, 2012 1:59 pm
by hldswrth » Thu Feb 07, 2013 12:25 pm
I've not published my code, not yet sure where I want to go with it. I'm actually 80% of the way through a basic FAT file system implementation, and need to improve some aspects of the SD card access once that's done as I suspect I have some hard-coded values which may break the code on other cards. Yes I know, re-inventing the wheel but that's kind of what bare metal is all about ;)
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm
by DexOS » Thu Feb 07, 2013 10:32 pm
hldswrth wrote:I've not published my code, not yet sure where I want to go with it. I'm actually 80% of the way through a basic FAT file system implementation, and need to improve some aspects of the SD card access once that's done as I suspect I have some hard-coded values which may break the code on other cards. Yes I know, re-inventing the wheel but that's kind of what bare metal is all about ;)

I know that feeling hldswrth, you start off with why is there not more info on how to do this, but by the time you put hours, up on hours of work to get it to work, you think why should other get it so easy :twisted:
Batteries not included, Some assembly required.
User avatar
Posts: 866
Joined: Wed May 16, 2012 6:32 pm
by hldswrth » Mon Feb 11, 2013 11:30 am
I'm more than happy to answer questions about what I did and post snippets, however my employer owns the IP to all code I write. I would need management approval to make any fully working code available, and that would be under a specific license. That's not really something I want to go through at this point.
Posts: 99
Joined: Mon Sep 10, 2012 4:14 pm