• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

SDHC code

#2
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.
 

DirtyLude

Well-Known Member
#3
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.
 

AtomSoft

Well-Known Member
Thread starter #5
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:
http://www.cygnal.org/ubb/Forum5/HTML/001181.html
 
Last edited:

AtomSoft

Well-Known Member
Thread starter #7
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
 

DirtyLude

Well-Known Member
#8
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.
 

AtomSoft

Well-Known Member
Thread starter #10
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
 

DirtyLude

Well-Known Member
#11
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:

AtomSoft

Well-Known Member
Thread starter #13
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

AtomSoft

Well-Known Member
Thread starter #15
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:

Latest threads

EE World Online Articles

Loading

 
Top