|
|
View previous topic :: View next topic |
Author |
Message |
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
SDHC Initialization Sequence |
Posted: Wed Nov 26, 2008 10:38 am |
|
|
Hi, Im trying to use a SDHC in a datalogger project, but it is a little hard to find informations about its initialization sequence.
if someone has this answer, I´ll apreciate if you share with us.
regards. _________________ Andre |
|
|
crystal_lattice
Joined: 13 Jun 2006 Posts: 164
|
|
Posted: Thu Nov 27, 2008 12:14 am |
|
|
Do a search on google and you will find: http://svenpeter.blogspot.com/2008/11/sdhc-support-for-wii.html
It is not for microcontrollers, but still applies, I haven't played around with these cards so I can't give you experienced help, but here is an extract from the link I gave you: Quote: | After sending the "GO_IDLE_STATE" command you need to send another command to indicate that you know about SDHC and are going to use it. The next two commands are then very similar to the SDv1 initialization with one more bit set to tell the card (again) that you know about high-capacity cards. If you don't send the special "I know about sdhc kthx" (aka CMD8) command the card will just return an error when you send the next command because it thinks that it can't be used with this host. |
Here is another link providing some useful code:
http://www.cygnal.org/ubb/Forum5/HTML/001181.html |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Thu Nov 27, 2008 7:37 am |
|
|
Thank you man, I'm gonna check it... when I get some results I'll post.
ps: The second link that you gave me, I've already seen, and didn't work, but I'll look deeper.
regards. _________________ Andre |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Nov 27, 2008 4:05 pm |
|
|
I never used SDHC cards but I think Crystal Lattice summed it up nicely.
You can download the SD / SDHC specifications v2.00 from: http://www.sdcard.org/developers/tech/sdcard/
Check out Figure 4-2 for the command sequence flow. |
|
|
crystal_lattice
Joined: 13 Jun 2006 Posts: 164
|
|
Posted: Fri Nov 28, 2008 12:16 am |
|
|
I have also tried the link from that site, but seems you have to go to the site directly (elm chan one) and download the file, i use free download manager but this does not seem to work, i have to allow my browser (mozilla firefox) to download it else i get directed else where. That is, if you are refering to the link not working and not the actual file/driver...
I don't think you will easily find SDHC support/pre written driver for the pic as this falls in the catagory of memory>4GB which is a lot of storage memory for a pic. I doubt that the average hobbiest requires more memory than that... But like Ckielstra said, refer to the manual for answers. |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Fri Nov 28, 2008 9:56 am |
|
|
crystall_latice
Im trying to follow the steps in reference manual of sd association, but the 4gb sd kingston that I have doesnt pass from CMD8. CMD0 works fine, but CMD8 doesnt work....
Ill try to find a way to make it works...
thanks for the help. _________________ Andre |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Sun Nov 30, 2008 9:20 am |
|
|
Hi, _________________ Andre
Last edited by andreluizeng on Sun Nov 30, 2008 3:47 pm; edited 1 time in total |
|
|
andreluizeng
Joined: 04 Apr 2006 Posts: 117 Location: Brasil
|
|
Posted: Sun Nov 30, 2008 9:24 am |
|
|
Hi,
I've been working on a 4GB SD Kingston, using those information that you gave me, but I can't even pass through CMD8. I received Illegal command all the time.
So, using the block diagram of the initialization sequence in that paper (SD organization), it says that if CMD8 doesn't work, ACMD has to be sent.
so.. I did, and the answer is CRC Error.
This is my initialization sequence just for tests:
Code: |
char InitCard (void)
{
char Requ;
char i;
char Cmd;
long TimeOut;
// dummy clocks
for (i = 0; i < 20; i++) MMC8Clock ();
// Reset
printf ("\r\nCMD0");
Requ = SendCmd (CMD0, 0x00, 0x95); (arguments are: cmd, data, crc)
MMCDebug (Requ);
if (Requ == IN_IDLE_STATE)
{
printf ("\r\nCMD8");
// CMD8 - SEND_IF_COND
Requ = SendCmd (CMD8, 0x1AA, 0x87);
MMCDebug (Requ);
// SD Card V2.0 or later
if (Requ == IN_IDLE_STATE)
{
printf ("\r\nSDHC");
}
// SD Card V2.0 with wrong voltage
// or SD Card V1.0 / MMC
else
{
// ACMD41 - SD_SEND_OP_COND
printf ("\r\nACMD41");
Requ = SendCmd (ACMD41, 0x00, 0x01);
MMCDebug (Requ);
// SD Card
if (Requ <= IN_IDLE_STATE)
{
Cmd = ACMD41;
printf ("\r\nSD");
}
// MMC
else
{
Cmd = CMD1;
printf ("\r\MMC");
}
TimeOut = 5000;
Requ = TRUE;
while (Requ && TimeOut)
{
Requ = SendCmd (Comando, 0x00, 0x01);
TimeOut--;
}
if (! TimeOut)
{
printf ("\r\nInitialization sequence failed");
return FALSE;
}
// set block size to 512 bytes
else
{
Requ = SendCmd (CMD16, 0x0200, 0x01);
if (Requ)
{
printf("\r\nError");
return FALSE;
}
}
}
return TRUE;
}
return FALSE;
}
|
and my answers are:
Quote: |
CMD0
Request: 0x01
IN IDLE STATE
CMD8
Request: 0x05
IN IDLE STATE
ILLEGAL COMMAND
ACMD41
Request: 0x09
IN IDLE STATE
COMMAND CRC ERROR
Initialization sequence failed
|
so.... any clues?
Im keeping trying... if any progress Ill post.
thanks. _________________ Andre |
|
|
eternauta3k Guest
|
|
Posted: Tue Feb 10, 2009 7:33 pm |
|
|
I'm having the same problem. When I do a SEND_IF_COND, I get illegal command + in idle state.
The spec says the command is legal in idle state, maybe what it means is that I can only run it while it's still returning a 1 in the idle state bit. I'm gonna try that, see how it works. |
|
|
spatial
Joined: 07 Jul 2010 Posts: 1
|
|
Posted: Wed Jul 07, 2010 9:43 am |
|
|
Sorry to open this thread again but I also have been having the same problems with an Kingston 4GB SD Card. I sent them an email and got the following response:
Quote: | Please note that Kingston Technology does not manufacture and subsequently test its range of flash card products to be used for the purpose of being addressed under the SPI mode.
Our products are made for the purpose of being used as removable storage media in popular electronic equipment such as digital cameras, mp3 players, satellite navigation devices, PDAs and mobile phones.
Although it is possible that our cards can be addressed in the way which you intend, we can not guarantee that this will always be possible.
Indeed the results may vary from one card or batch to the next, depending on the type of components used during the manufacturing process.
If you are able to use the cards in standard data transfer mode, then the product is working according to Kingston Technology design specification.
|
If the card can't be addressed using SPI then it probably isn't too much of a worry and is more of a poor reflection on Kingston. |
|
|
Wayne_
Joined: 10 Oct 2007 Posts: 681
|
|
Posted: Wed Jul 07, 2010 9:57 am |
|
|
The simplified physical layer spec specifies:-
"The CMD8 CRC verification is always enabled. The Host shall set correct CRC in the argument of
CMD8. If CRC error is detected, card returns CRC error in R1 response regardless of command index."
You must set the CRC for CMD8 always.
It also says:-
"If the card indicates an illegal command, the card is legacy and does not support CMD8. If the card
supports CMD8 and can operate on the supplied voltage, the response echoes back the supply voltage
and the check pattern that were set in the command argument.
If VCA in the response is set to 0, the card cannot operate on the supplied voltage. If check pattern is
not matched, CMD8 communication is not valid. In this case, it is recommended to retry CMD8
sequence."
retry CMD8 if it fails first time.
Please also note that the SD interface, SPI included is covered by a license for use. It costs around $3000 per year to make a product which can use SD cards. |
|
|
icebell
Joined: 22 Jun 2012 Posts: 1
|
second time |
Posted: Fri Jun 22, 2012 3:57 am |
|
|
That is true, with the kingston 4GB sdHC card, the sescond time I send the CMD8 comand, the response is 0xFF, 0x01, 0x00, 0x00, 0x01, 0xAA. |
|
|
hadipic
Joined: 02 Dec 2012 Posts: 2
|
|
Posted: Tue Feb 17, 2015 4:42 am |
|
|
Code: |
/*-----------------------------------------------------------------------*/
/* PFF - Low level disk control module for ATtiny85 (C)ChaN, 2009 */
// conver ccs compile for use pic18f452 by bashniji
// 2015-1-26
//hadi bashniji
// emai hadi.bashniji@gmail .com
// hcmmc init test ok
// initing low level routin
/*-----------------------------------------------------------------------*/
#define _WRITE_FUNC 1
#define debug_monitor 0
#define debug_monitor_r 0
/* Definitions for MMC/SDC command */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
#define ACMD41 (0xe9) //(0x80 + 0x40 ) /* SEND_OP_COND (SDC) */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
#include "stdint.h"
#include <string.h>
#define bud1 18000000 //9216000 // F_CPU / 2
#ifndef MMCSD_PIN_SCL
#define MMCSD_PIN_SCL PIN_C3 //o
#define MMCSD_PIN_SDI PIN_C4 //i
#define MMCSD_PIN_SDO PIN_C5 //o
#define MMCSD_PIN_SELECT PIN_C2 //o
#endif
#define USE_SW_ONLY 0
#if USE_SW_ONLY
/* For software spi */
#use spi(MASTER,BAUD=bud1,CLK=MMCSD_PIN_SCL, DO=MMCSD_PIN_SDO, DI=MMCSD_PIN_SDI, BITS=8, MODE=3, MSB_FIRST, stream=mmcsd_spi, FORCE_SW)
#else
/* For hardware spi */
#use spi(MASTER,BAUD=bud1,CLK=MMCSD_PIN_SCL, DO=MMCSD_PIN_SDO, DI=MMCSD_PIN_SDI, BITS=8, MODE=3, stream=mmcsd_spi, FORCE_HW)
#endif
#define dword int32
#define word int16
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Function succeeded */
RES_ERROR, /* 1: Disk error */
RES_NOTRDY, /* 2: Not ready */
RES_PARERR /* 3: Invalid parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
//DSTATUS disk_initialize (void);
//DRESULT disk_readp (BYTE*, DWORD, WORD, WORD);
//DRESULT disk_writep (const BYTE*, DWORD);
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
/* Card type flags (CardType) */
#define CT_MMC 0x01 /* MMC ver 3 */
#define CT_SD1 0x02 /* SD ver 1 */
#define CT_SD2 0x04 /* SD ver 2 */
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
#define CT_BLOCK 0x08 /* Block addressing */
#byte SSPCON1= 0x0FC6
#bit SSPM1 = SSPCON1.1
#bit SSPM0 = SSPCON1.0
BYTE CardType;
void init_spi(void){
output_drive(MMCSD_PIN_SCL);
output_drive(MMCSD_PIN_SDO);
output_drive(MMCSD_PIN_SELECT);
output_float(MMCSD_PIN_SDI);
}
unsigned char xmit_spi(unsigned char dat)
{
spi_xfer(mmcsd_spi,dat);
}
/*-----------------------------------------------------------------------*/
/* Receive a byte from MMC via SPI (Platform dependent) */
/*-----------------------------------------------------------------------*/
unsigned char rcv_spi(void)
{
return spi_xfer(mmcsd_spi, 0xFF);
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus */
/*-----------------------------------------------------------------------*/
static
void deselect (void)
{
output_high(MMCSD_PIN_SELECT);
// spi_xfer(mmcsd_spi,0xff); /* Dummy clock (force DO hi-z for multiple slave SPI) */
}
/*-----------------------------------------------------------------------*/
/* Select the card and wait for ready */
/*-----------------------------------------------------------------------*/
static
int select (void) /* 1:Successful, 0:Timeout */
{
output_low(MMCSD_PIN_SELECT);
// spi_xfer(mmcsd_spi,0xff); /* Dummy clock (force DO enabled) */
// if (wait_ready()) return 1; /* OK */
// deselect();
//
//return 0; /* Timeout */
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus */
/*-----------------------------------------------------------------------*/
static
void release_spi (void)
{
DESELECT();
rcv_spi();
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready */
/*-----------------------------------------------------------------------*/
static
BYTE wait_ready (void)
{
BYTE res;
WORD timeout = 0x1FFF;
do
res = rcv_spi();
while ((res != 0xFF) && (--timeout));
return res;
}
/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC */
/*-----------------------------------------------------------------------*/
static
BYTE send_cmd (
BYTE cmd, /* Command byte */
DWORD arg /* Argument */
)
{
BYTE n, res;
/* Select the card and wait for ready */
DESELECT();
SELECT();
if (wait_ready() != 0xFF) {
return 0xFF;
}
//res = send_cmd(CMD55, 0); // PICC18 Compiler error! (recursive function)
if (cmd & 0x80) { /* ACMD<n> is the command sequence of CMD55-CMD<n> */
cmd= cmd & 0x7F;
//res = send_cmd(CMD55, 0); // PICC18 Compiler error! (recursive function)
/* Send command packet */
xmit_spi(CMD55); /* Start + Command index */
xmit_spi( make8(0, 3)); /* Argument[31..24] */
xmit_spi( make8(0, 2)); /* Argument[23..16] */
xmit_spi( make8(0, 1)); /* Argument[15..8] */
xmit_spi( make8(0, 0)); /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
xmit_spi(n);
/* Receive command response */
if (cmd == CMD12) rcv_spi(); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
res = rcv_spi();
while ((res & 0x80) && --n);
if (res > 1) return res;
}
/* Send command packet */
xmit_spi(cmd); /* Start + Command index */
xmit_spi( make8(arg, 3)); /* Argument[31..24] */
xmit_spi( make8(arg, 2)); /* Argument[23..16] */
xmit_spi( make8(arg, 1)); /* Argument[15..8] */
xmit_spi( make8(arg, 0)); /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
xmit_spi(n);
/* Receive command response */
if (cmd == CMD12) rcv_spi(); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
res = rcv_spi();
while ((res & 0x80) && --n);
#if debug_monitor_r
printf (" %d -> %x \n\r",cmd-0x40,res);
#endif
return res; /* Return with the response value */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (void)
{
BYTE n, cmd, ty, ocr[4];
int16 tmr,timer1;
init_spi();
// sspm0 , sspm1 > 00 foc/4 01 foc/16 10 foc /64
// foc/64 low sped
SSPM0 = 1 ;
SSPM1 = 0 ;
#if _WRITE_FUNC
// if (MMC_SEL) disk_writep(0, 0); /* Finalize write process if it is in progress */
#endif
for (n = 100; n; n--) rcv_spi(); /* Dummy clocks */
ty = 0;
if (send_cmd(CMD0, 0) == 1)
{ /* Enter Idle state */
if (send_cmd(CMD8, 0x1AA) == 1)
{ /* SDv2 */
for (n = 0; n < 4; n++) ocr[n] = rcv_spi(); /* Get trailing return value of R7 resp */
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
#if debug_monitor
printf ("cmd8= %x %x \n\r",ocr[2],ocr[3]);
#endif
// while (get_timer1() && send_cmd(ACMD41,(DWORD)1 << 30));
for (tmr = 12000; tmr && send_cmd(ACMD41,(int32)1<<30 ); tmr--) ;delay_us(1) ; /* Wait for leaving idle state (ACMD41 with HCS bit) */ // 1<<30=0x40000000
// if (get_timer1()&& send_cmd(CMD58, 0) == 0) /* Check CCS bit in the OCR */
if (tmr && send_cmd(CMD58, 0) == 0)
{ /* Check CCS bit in the OCR */
for (n = 0; n < 4; n++) ocr[n] = rcv_spi();
#if debug_monitor
printf ("ocr= %x %x %x %x \n\r",ocr[0],ocr[1]ocr[2],ocr[3]);
#endif
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 (HC or SC) */
}
}
}
else { /* SDv1 or MMCv3 */
// for (tmr = 25000; tmr && send_cmd(cmd1, 0); tmr--);
if (send_cmd(ACMD41, 0) <= 1)
{
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
}
else
{ /* Proteus 7.x MMC sim model */
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
}
#if debug_monitor
printf ("card type %x \n\r",ty);
#endif
for (tmr = 25000; tmr && send_cmd(cmd, 0); tmr--) ;
#if debug_monitor
printf ("cmd41 \n\r",); /* Wait for leaving idle state */
#endif
if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
}
CardType = ty;
release_spi();
#if debug_monitor
printf ("card type %x \n\r",CardType);
#endif
SSPM0 = 0 ;
SSPM1 = 0 ;
return ty ? 0 : STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read partial sector */
/*-----------------------------------------------------------------------*/
DRESULT disk_readp (
BYTE *buff, /* Pointer to the read buffer (NULL:Read bytes are forwarded to the stream) */
DWORD lba, /* Sector number (LBA) */
WORD ofs, /* Byte offset to read from (0..511) */
WORD cnt /* Number of bytes to read (ofs + cnt mus be <= 512) */
)
{
DRESULT res;
BYTE rc;
WORD bc;
if (!(CardType & CT_BLOCK)) lba *= 512; /* Convert to byte address if needed */
res = RES_ERROR;
if (send_cmd(CMD17, lba) == 0) { /* READ_SINGLE_BLOCK */
bc = 30000;
do { /* Wait for data packet in timeout of 100ms */
rc = rcv_spi();
} while (rc == 0xFF && --bc);
if (rc == 0xFE) { /* A data packet arrived */
bc = 514 - ofs - cnt;
/* Skip leading bytes */
if (ofs) {
do rcv_spi(); while (--ofs);
}
/* Receive a part of the sector */
if (buff) { /* Store data to the memory */
do
*buff++ = rcv_spi();
while (--cnt);
} else { /* Forward data to the outgoing stream (depends on the project) */
//do
//xmit(rcv_spi()); /* (Console output) */
//while (--cnt);
}
/* Skip trailing bytes and CRC */
do rcv_spi(); while (--bc);
res = RES_OK;
}
}
release_spi();
return res;
}
/*-----------------------------------------------------------------------*/
/* Write partial sector */
/*-----------------------------------------------------------------------*/
#if _WRITE_FUNC
DRESULT disk_writep (
BYTE *buff, /* Pointer to the bytes to be written (NULL:Initiate/Finalize sector write) */
DWORD sa /* Number of bytes to send, Sector number (LBA) or zero */
)
{
DRESULT res;
WORD bc;
static WORD wc;
res = RES_ERROR;
if (buff) { /* Send data bytes */
bc = (WORD)sa;
while (bc && wc) { /* Send data bytes to the card */
xmit_spi(*buff++);
wc--; bc--;
}
res = RES_OK;
} else {
if (sa) { /* Initiate sector write process */
if (!(CardType & CT_BLOCK)) sa *= 512; /* Convert to byte address if needed */
if (send_cmd(CMD24, sa) == 0) { /* WRITE_SINGLE_BLOCK */
xmit_spi(0xFF); xmit_spi(0xFE); /* Data block header */
wc = 512; /* Set byte counter */
res = RES_OK;
}
} else { /* Finalize sector write process */
bc = wc + 2;
while (bc--) xmit_spi(0); /* Fill left bytes and CRC with zeros */
if ((rcv_spi() & 0x1F) == 0x05) { /* Receive data resp and wait for end of write process in timeout of 300ms */
for (bc = 65000; rcv_spi() != 0xFF && bc; bc--) ; /* Wait ready */
if (bc) res = RES_OK;
}
release_spi();
}
}
return res;
}
#endif
|
Last edited by hadipic on Tue Feb 17, 2015 4:47 am; edited 2 times in total |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|