SDHC code

Status
Not open for further replies.

AtomSoft

Well-Known Member
Anyone have code or in on how to init sdhc cards? I found not a single thing with google
 
How are you intending to use the SDHC card? The protocol is protected IP, as a hobbyist you can only access the card using the SPI protocol. Google "sdhc spi", plenty of decent results.
 
Assuming SPI mode, then it's not all that different from regular SD. The library I'm using (FatFS) supports both and only has some minor logic changes if it sees SDHC. I haven't really looked at it in detail, but I know it works with my 4GB SDHC microSD.
 
Thanks I'll take a look at FatFS and google sdhc spi. I'm not sure if the init is different but so far with the code from petit fs no luck
 
Its not easy heh i cant get it to init at all! this is the code im trying to use:
Code:
DSTATUS disk_initialize (void)
{
    BYTE SDHC = 0;
    BYTE ocr[4] = {0,0,0,0};
    BYTE ty,cmd;

	WORD tmr;
    WORD r,i,x;
    
    tmr = 10000;
    r = 0;

    init_spi();

    // 1. with the card NOT selected
    DESELECT();

    // 2. send 80 clock cycles start up
    for ( i=0; i<10; i++)
        writeSPI(0xFF);

    // 3. now select the card
    SELECT();

    // 4. send a single RESET command
    r = send_cmd(CMD0, 0); 
    //DESELECT();
    if ( r != 1)                // must return Idle
        return 1;   // comand rejected

    // 5. send repeatedly INIT until Idle terminates
    if (send_cmd(CMD8, 0x1AA) == 1) {	/* SDC ver 2.00 */
        SDHC = 1;
        i = 0;
        for (x = 0; x < 4; x++) ocr[x] = rcv_spi();
		if (ocr[2] == 0x01 && ocr[3] == 0xAA) {	                    /* The card can work at vdd range of 2.7-3.6V */
		    while (send_cmd(ACMD41, 1UL << 30)){	                /* ACMD41 with HCS bit */
                i++;
                if(i==tmr) break;
            }
		    if (send_cmd(CMD58, 0) == 0) {	                        /* Check CCS bit */
			    for (x = 0; x < 4; x++) ocr[x] = rcv_spi();
			    ty = (ocr[0] & 0x40) ? CT_SD2|CT_BLOCK : CT_SD2;	/* SDv2 */
		    }
	    }
    }else{

        if (send_cmd(ACMD41, 0) <= 1) {
        	ty = CT_SD1;
            cmd = ACMD41;	/* SDv1 */
		} else {
			ty = CT_MMC; 
            cmd = CMD1;	/* MMCv3 */
		}

        for (i=0; i<tmr; i++){
            r = send_cmd(cmd, 0); DESELECT();
            if ( !r) 
                break; 
        } 
        if ( i == tmr)   
            return 2;  // init timed out 

        for (i=0; i<tmr; i++){
            r = send_cmd(CMD16, 512); DESELECT();
            if ( r) 
                break; 
        } 
        if ( i == tmr)   
            return 2;  // init timed out 
    }
	return r;
}

I made the above code from the below code:
Code:
static
DSTATUS MM_disk_initialize (void)
{
	BYTE n, ty, cmd, ocr[4];


	if (Stat[1] & STA_NODISK)			/* No card in the socket */
		return Stat[1];

	MM_power_on();						/* Force socket power ON */
	FCLK_SLOW();
	for (n = 10; n; n--) MM_rcvr_spi();	/* 80 dummy clocks */

	ty = 0;
	if (MM_send_cmd(CMD0, 0) == 1) {			/* Enter Idle state */
		Timer1 = 100;							/* Initialization timeout of 1000 msec */
		if (MM_send_cmd(CMD8, 0x1AA) == 1) {	/* SDC ver 2.00 */
			for (n = 0; n < 4; n++) ocr[n] = MM_rcvr_spi();
			if (ocr[2] == 0x01 && ocr[3] == 0xAA) {	/* The card can work at vdd range of 2.7-3.6V */
				while (Timer1 && MM_send_cmd(ACMD41, 1UL << 30));	/* ACMD41 with HCS bit */
				if (Timer1 && MM_send_cmd(CMD58, 0) == 0) {	/* Check CCS bit */
					for (n = 0; n < 4; n++) ocr[n] = MM_rcvr_spi();
					ty = (ocr[0] & 0x40) ? CT_SD2|CT_BLOCK : CT_SD2;	/* SDv2 */
				}
			}
		} else {							/* SDv1 or MMCv3 */
			if (MM_send_cmd(ACMD41, 0) <= 1) {
				ty = CT_SD1; cmd = ACMD41;	/* SDv1 */
			} else {
				ty = CT_MMC; cmd = CMD1;	/* MMCv3 */
			}
			while (Timer1 && MM_send_cmd(cmd, 0));	/* Wait for leaving idle state */
			if (!Timer1 || MM_send_cmd(CMD16, 512) != 0)	/* Select R/W block length */
				ty = 0;
		}
	}
	CardType = ty;
	MM_release_spi();

	if (ty) {			/* Initialization succeded */
		Stat[1] &= ~STA_NOINIT;		/* Clear STA_NOINIT */
		FCLK_FAST();
	} else {			/* Initialization failed */
		MM_power_off();
	}

	return Stat[1];
}

FROM here:
**broken link removed**
 
Last edited:
i doubt it. I think it has SPI also. But not sure... i can sort of get it going but heh its a huge headache. So im going to take a break and move on to IR for cable using some captures from "DirtyLude" aka Mark.

Hopefully if i can get my IR to work on my cable box then its all progress heh

The SDHC isnt too much of a hassle but its easier for me to get SDHC cards at discount then SD non HC heh
 
The FatFS library's Init method is outlined on this page under "How to support SDC Ver2 and high capacity cards". They call SDHC SDC V2.

ELM - How to Use MMC/SDC

As far as I can see, looking through the code, there's no difference other than the Init.
 
heh i tried to init the as you can see from above code heh but no luck its not as easy and they make it. I know its my fault heh since everyone else gets it heh

Ill re write the whole thing tommorow without LCD code as to clear up my confusion heh
 
I'm reading on that chans site and I have to admit it doesn't seem so difficult heh. I am going to write my own code fully bitbanged SPI and custom init. And if all goes well I'll write a nice PDF explanation as to help others out . I think it will take me about 2-3 days since I work heh
 
Well, here's the initialization code from FatFS if it helps. This is one thing I have no problem keeping as a black box, though.

Code:
for (n = 10; n; n--) rcvr_spi();	/* 80 dummy clocks */

ty = 0;
if (send_cmd(CMD0, 0) == 1) {			/* Enter Idle state */
	Timer1 = 100;						/* Initialization timeout of 1000 msec */
	if (send_cmd(CMD8, 0x1AA) == 1) {	/* SDHC */
		for (n = 0; n < 4; n++) ocr[n] = rcvr_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 */
			while (Timer1-- && send_cmd(ACMD41, 1UL << 30));	/* Wait for leaving idle state (ACMD41 with HCS bit) */
			if (Timer1 && send_cmd(CMD58, 0) == 0) {		/* Check CCS bit in the OCR */
				for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
				ty = (ocr[0] & 0x40) ? 12 : 4;
			}
		}
	} else {							/* SDSC or MMC */
		if (send_cmd(ACMD41, 0) <= 1) 	{
			ty = 2; cmd = ACMD41;	/* SDSC */
		} else {
			ty = 1; cmd = CMD1;		/* MMC */
		}
		while (Timer1-- && send_cmd(cmd, 0));			/* Wait for leaving idle state */
		if (!Timer1 || send_cmd(CMD16, 512) != 0)	/* Set R/W block length to 512 */
			ty = 0;
	}
}
CardType = ty;
release_spi();
 
Last edited:
heh if you read above you can see i tried to convert it to C18 on post #5 but no luck but i will have to try again when i recreate my code
 
Some what good with bad news lol

Got the SD to init ok i assume since it passes ! but i found out where it get stuck. Its stuck on mounting. it retruns NO FILESYSTEM when i know 100% there is one heh..

Code:
FRESULT pf_mount (
	FATFS *fs		/* Pointer to new file system object (NULL: Unmount) */
)
{
	BYTE fmt, buf[36];
	DWORD bsect, fsize, tsect, mclst;
    BYTE res;


	FatFs = 0;
	if (!fs) return FR_OK;				/* Unregister fs object */

    res = disk_initialize();
	if (res & STA_NOINIT)	/* Check if the drive is ready or not */
		return FR_NOT_READY;

	/* Search FAT partition on the drive */
	bsect = 0;
	fmt = check_fs(buf, bsect);			/* Check sector 0 as an SFD format */
	if (fmt == 1) {						/* Not an FAT boot record, it may be FDISK format */
		/* Check a partition listed in top of the partition table */
		if (disk_readp(buf, bsect, MBR_Table, 16)) {	/* 1st partition entry */
			fmt = 3;
		} else {
			if (buf[4]) {					/* Is the partition existing? */
				bsect = LD_DWORD(&buf[8]);	/* Partition offset in LBA */
				fmt = check_fs(buf, bsect);	/* Check the partition */
			}
		}
	}
	if (fmt == 3) return FR_DISK_ERR;
[B][COLOR="Red"]	if (fmt) return FR_NO_FILESYSTEM;	/* No valid FAT patition is found */[/COLOR][/B]

	/* Initialize the file system object */
	if (disk_readp(buf, bsect, 13, sizeof(buf))) return FR_DISK_ERR;

	fsize = LD_WORD(buf+BPB_FATSz16-13);				/* Number of sectors per FAT */
	if (!fsize) fsize = LD_DWORD(buf+BPB_FATSz32-13);

	fsize *= buf[BPB_NumFATs-13];						/* Number of sectors in FAT area */
	fs->fatbase = bsect + LD_WORD(buf+BPB_RsvdSecCnt-13); /* FAT start sector (lba) */
	fs->csize = buf[BPB_SecPerClus-13];					/* Number of sectors per cluster */
	fs->n_rootdir = LD_WORD(buf+BPB_RootEntCnt-13);		/* Nmuber of root directory entries */
	tsect = LD_WORD(buf+BPB_TotSec16-13);				/* Number of sectors on the file system */
	if (!tsect) tsect = LD_DWORD(buf+BPB_TotSec32-13);
	mclst = (tsect						/* Last cluster# + 1 */
		- LD_WORD(buf+BPB_RsvdSecCnt-13) - fsize - fs->n_rootdir / 16
		) / fs->csize + 2;
	fs->max_clust = (CLUST)mclst;

	fmt = FS_FAT12;							/* Determine the FAT sub type */
	if (mclst >= 0xFF7) fmt = FS_FAT16;		/* Number of clusters >= 0xFF5 */
	if (mclst >= 0xFFF7)					/* Number of clusters >= 0xFFF5 */
#if _FS_FAT32
		fmt = FS_FAT32;
#else
		return FR_NO_FILESYSTEM;
#endif

	fs->fs_type = fmt;		/* FAT sub-type */
#if _FS_FAT32
	if (fmt == FS_FAT32)
		fs->dirbase = LD_DWORD(buf+(BPB_RootClus-13));	/* Root directory start cluster */
	else
#endif
		fs->dirbase = fs->fatbase + fsize;				/* Root directory start sector (lba) */
	fs->database = fs->fatbase + fsize + fs->n_rootdir / 16;	/* Data start sector (lba) */

	fs->flag = 0;
	FatFs = fs;

	return FR_OK;
}

/* No valid FAT patition is found */

why me!?!?!? heh

anyway im off to work. Ill be back later on.. If anyone can figure out why im stuck feel free to share... here is my code attached below...
 

Attachments

  • sd.zip
    88.2 KB · Views: 437
The SD and SDHC interface specification is not really controlled IP. The spec that tells you how to design your own card (for card manufacturers) that one costs $1k.

But you can get and read the interface spec freely here:
**broken link removed**

That spec has everything you need to know for accessing SD and SDHC cards via 4-bit/1-bit SD bus or in SPI-mode.
 
OMG heh i think i got it heh

I forgot to add 1 line to init (in red BOLD):

Code:
DSTATUS disk_initialize (void)
{
    BYTE SDHC = 0;
    BYTE ocr[4] = {0,0,0,0};
    BYTE ty,cmd;

	WORD tmr;
    WORD r,i,x;
    
    tmr = 10000;
    r = 0;
	ty = 0;

    init_spi();

    // 1. with the card NOT selected
    DESELECT();

    // 2. send 80 clock cycles start up
    for ( i=0; i<10; i++)
        writeSPI(0xFF);

    // 3. now select the card
    SELECT();

    // 4. send a single RESET command
    r = send_cmd(CMD0, 0); 
    //DESELECT();
    if ( r != 1)                // must return Idle
        return 1;   // comand rejected

    // 5. send repeatedly INIT until Idle terminates
    if (send_cmd(CMD8, 0x1AA) == 1) {	//* SDC ver 2.00 
        SDHC = 1;
        i = 0;
        for (x = 0; x < 4; x++) ocr[x] = rcv_spi();
		if (ocr[2] == 0x01 && ocr[3] == 0xAA) {	                    //* The card can work at vdd range of 2.7-3.6V 
            for (i=0; i<tmr; i++){
                r = send_cmd(ACMD41, 1UL << 30); 
                DESELECT();
                if (!r) 
                    break; 
            }
		    if (send_cmd(CMD58, 0) == 0) {	                        // Check CCS bit 
			    for (x = 0; x < 4; x++) ocr[x] = rcv_spi();
			    ty = (ocr[0] & 0x40) ? CT_SD2|CT_BLOCK : CT_SD2;	// SDv2 
		    }
	    }
    }else{

        if (send_cmd(ACMD41, 0) <= 1) {
        	ty = CT_SD1;
            cmd = ACMD41;	//* SDv1 
		} else {
			ty = CT_MMC; 
            cmd = CMD1;	//* MMCv3 
		}

        for (i=0; i<tmr; i++){
            r = send_cmd(cmd, 0); DESELECT();
            if ( !r) 
                break; 
        } 
        if ( i == tmr)   
            return 2;  // init timed out 


    }
[B][COLOR="Red"]    CardType = ty;[/COLOR][/B]
	return r;
}

This is why it was so usefull: (inside disk_readp)

Code:
	if (!(CardType & CT_BLOCK)) lba *= 512;		// Convert to byte address if needed
Converts LBA to BLOCKs or something
 
Last edited:
Finally got my camera working heh:

2GB CARD:


4GB CARD:
 

Attachments

  • 2gb.jpg
    412.2 KB · Views: 1,859
  • 4gb.jpg
    387.8 KB · Views: 1,885
Nice! You're an inspiration!

Let us know when you get LongFileName implemented...
 
Last edited:
thanks

i wouldnt use LFN on a PIC mainly because heh it takes up enough memory already heh....

i might try to get the FATFFS Working on this tho. WHIch has it already i think


thanKS again
 
Last edited:
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…