SDHC anyone?

Leeds
2007-02-08
2013-04-24
  • Leeds

    Leeds - 2007-02-08

    I must admit that I was totally in the dark about SDHC and I'm only just now starting to read up on it.  Will these cards still work with SPI? 

    According to one site, they simply use FAT32 and no longer support FAT16 (which seems pretty obvious) but are there any other differences?  That whole SD 2.00 sounds impressive but I have yet to find out what it entails (if they even publish it).

    I'll have to get a card soon to start playing with it but I'd love to hear anyone else's thoughts on the matter.  4-32GB sounds like a pretty nice format to take advantage of...

    -Leeds

     
    • Selwyn Jackson

      Selwyn Jackson - 2008-05-12

      Have you been able to support SDHC cards as yet?

      Regards  Selwyn

       
    • Leeds

      Leeds - 2008-06-13

      Nope, I screwed around with it for a few days and then put it on the back-burner.  I'd like to get it up and running but I'm afraid that it'll be a few more months before I have the time that I assume I'll need to devote to this...

      Any help anyone else has would still be greatly appreciated.  :-)

       
      • Selwyn Jackson

        Selwyn Jackson - 2008-06-14

        I have updated sd.c to support SDHC.  It is now compatible with SD and SDHC cards. 

        I cannot find the link to submit the changes, so I'll include the full source here:

        /*****************************************************************************\ *              efs - General purpose Embedded Filesystem library              *
        *          --------------------- -----------------------------------          *
        *                                                                             *
        * Filename : sd.c                                                             *
        * Revision : Initial developement                                             *
        * Description : This file contains the functions needed to use efs for        *
        *               accessing files on an SD-card.                                *
        *                                                                             *
        * This program is free software; you can redistribute it and/or               *
        * modify it under the terms of the GNU General Public License                 *
        * as published by the Free Software Foundation; version 2                     *
        * of the License.                                                             *
                                                                                      *
        * This program is distributed in the hope that it will be useful,             *
        * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
        * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
        * GNU General Public License for more details.                                *
        *                                                                             *
        * As a special exception, if other files instantiate templates or             *
        * use macros or inline functions from this file, or you compile this          *
        * file and link it with other works to produce a work based on this file,     *
        * this file does not by itself cause the resulting work to be covered         *
        * by the GNU General Public License. However the source code for this         *
        * file must still be made available in accordance with section (3) of         *
        * the GNU General Public License.                                             *
        *                                                                             *
        * This exception does not invalidate any other reasons why a work based       *
        * on this file might be covered by the GNU General Public License.            *
        *                                                                             *
        *                                                    (c)2006 Lennart Yseboodt *
        *                                                    (c)2006 Michael De Nil   *
        *                                                                             *
        * in Driver-Size: use if_spiSend instead for sd_Resp8b as proposed in         *
        * sf.net bug-tracker (applied by mthomas)                                     *
        *                                                                             *
        * Updated to support SDHC cards by Selwyn Jackson May 2008                    *
        \*****************************************************************************/

        /*****************************************************************************/
        #include "interfaces/sd.h"
        /*****************************************************************************/

        static esint8 SDHC = 0;

        esint8 sd_Init(hwInterface *iface)
        {
            esint32 i;
            euint8 resp;
            euint8 respx[4];
               
            /* Try to send reset command up to 100 times */
            i=100;
            do {
                sd_Command(iface, 0, 0, 0);
                resp=sd_Resp8b(iface);
            }
            while(resp!=1 && i--);
           
            if(resp!=1){
                DBG((TXT("CMD0 fail.\n")));
                if(resp==0xff){
                    return(-1);
                }
                else{
                    sd_Resp8bError(iface,resp);
                    return(-2);
                }
            }

            // check for SDHC card
            sd_Command(iface, 8, 0, 0x1AA);
            resp=sd_Resp8b(iface);
            respx[0]=if_spiSend(0xff);
            respx[1]=if_spiSend(0xff);
            respx[2]=if_spiSend(0xff);
            respx[3]=if_spiSend(0xff);
            if (resp == 1 && respx[2] == 1 && respx[3] ==0xAA) {            // high capacity card
                for (i = 0; i < 32000; ++i) {
                    sd_Command(iface, 55, 0, 0);
                    resp=sd_Resp8b(iface);
                    if (resp <= 1) {
                        sd_Command(iface, 41, 0x4000, 0);
                        resp=sd_Resp8b(iface);
                        if (resp == 0) {
                            break;
                        }
                    }
                }
                if (i < 32000) {
                    sd_Command(iface, 58, 0, 0);
                    resp=sd_Resp8b(iface);
                    respx[0]=if_spiSend(0xff);
                    respx[1]=if_spiSend(0xff);
                    respx[2]=if_spiSend(0xff);
                    respx[3]=if_spiSend(0xff);
                    SDHC = (respx[0] & 0x40) ? 1 : 0;
                }
            }

            else {
                /* Wait till card is ready initialising (returns 0 on CMD1) */
                /* Try up to 32000 times. */
                i=32000;
                do{
                    sd_Command(iface,1, 0, 0);

                    resp=sd_Resp8b(iface);
                    if(resp!=0)
                        sd_Resp8bError(iface,resp);
                }
                while(resp==1 && i--);

                if(resp!=0){
                    sd_Resp8bError(iface,resp);
                    return(-3);
                }
            }
            return(0);
        }
        /*****************************************************************************/

        void sd_Command(hwInterface *iface,euint8 cmd, euint16 paramx, euint16 paramy)
        {
            if_spiSend(iface,0xff);

            if_spiSend(iface,0x40 | cmd);
            if_spiSend(iface,(euint8) (paramx >> 8)); /* MSB of parameter x */
            if_spiSend(iface,(euint8) (paramx)); /* LSB of parameter x */
            if_spiSend(iface,(euint8) (paramy >> 8)); /* MSB of parameter y */
            if_spiSend(iface,(euint8) (paramy)); /* LSB of parameter y */

            // only command 0 and command 8 must have the correct crc
            if (cmd == 8) {
                if_spiSend(iface,0x87); // Checksum (command (8, 0x01, 0xAA)
            }
            else {
                if_spiSend(iface,0x95); /* Checksum (should be only valid for first command (0) */
            }

            if_spiSend(iface,0xff); /* eat empty command - response */
        }
        /*****************************************************************************/

        euint8 sd_Resp8b(hwInterface *iface)
        {
            euint8 i;
            euint8 resp;
           
            /* Respone will come after 1 - 8 pings */
            for ( i=0; i<8; i++ ) {
                resp = if_spiSend(iface,0xff);
                if(resp != 0xff)
                    return(resp);
            }
               
            return(resp);
        }
        /*****************************************************************************/

        euint16 sd_Resp16b(hwInterface *iface)
        {
            euint16 resp;
           
            resp = ( sd_Resp8b(iface) << 8 ) & 0xff00;
            resp |= if_spiSend(iface,0xff);
           
            return(resp);
        }
        /*****************************************************************************/

        void sd_Resp8bError(hwInterface *iface,euint8 value)
        {
            switch(value)
            {
                case 0x40:
                    DBG((TXT("Argument out of bounds.\n")));
                    break;
                case 0x20:
                    DBG((TXT("Address out of bounds.\n")));
                    break;
                case 0x10:
                    DBG((TXT("Error during erase sequence.\n")));
                    break;
                case 0x08:
                    DBG((TXT("CRC failed.\n")));
                    break;
                case 0x04:
                    DBG((TXT("Illegal command.\n")));
                    break;
                case 0x02:
                    DBG((TXT("Erase reset (see SanDisk docs p5-13).\n")));
                    break;
                case 0x01:
                    DBG((TXT("Card is initialising.\n")));
                    break;
                default:
                    DBG((TXT("Unknown error 0x%x (see SanDisk docs p5-13).\n"),value));
                    break;
            }
        }
        /*****************************************************************************/

        esint8 sd_State(hwInterface *iface)
        {
            eint16 value;
           
            sd_Command(iface,13, 0, 0);
            value=sd_Resp16b(iface);

            switch(value)
            {
                case 0x000:
                    return(1);
                    break;
                case 0x0001:
                    DBG((TXT("Card is Locked.\n")));
                    break;
                case 0x0002:
                    DBG((TXT("WP Erase Skip, Lock/Unlock Cmd Failed.\n")));
                    break;
                case 0x0004:
                    DBG((TXT("General / Unknown error -- card broken?.\n")));
                    break;
                case 0x0008:
                    DBG((TXT("Internal card controller error.\n")));
                    break;
                case 0x0010:
                    DBG((TXT("Card internal ECC was applied, but failed to correct the data.\n")));
                    break;
                case 0x0020:
                    DBG((TXT("Write protect violation.\n")));
                    break;
                case 0x0040:
                    DBG((TXT("An invalid selection, sectors for erase.\n")));
                    break;
                case 0x0080:
                    DBG((TXT("Out of Range, CSD_Overwrite.\n")));
                    break;
                default:
                    if(value>0x00FF)
                        sd_Resp8bError(iface,(euint8) (value>>8));
                    else
                        DBG((TXT("Unknown error: 0x%x (see SanDisk docs p5-14).\n"),value));
                    break;
            }
            return(-1);
        }
        /*****************************************************************************/

        /* ****************************************************************************
        * WAIT ?? -- FIXME
        * CMDWRITE
        * WAIT
        * CARD RESP
        * WAIT
        * DATA BLOCK OUT
        *      START BLOCK
        *      DATA
        *      CHKS (2B)
        * BUSY...
        */

        esint8 sd_writeSector(hwInterface *iface,euint32 address, euint8* buf)
        {
            euint32 place;
            euint16 i;
            euint16 t=0;
           
            /*DBG((TXT("Trying to write %u to sector %u.\n"),(void *)&buf,address));*/
            place=address;
            if (SDHC == 0) {
                place=512*address;
            }
            sd_Command(iface,CMDWRITE, (euint16) (place >> 16), (euint16) place);

            sd_Resp8b(iface); /* Card response */

            if_spiSend(iface,0xfe); /* Start block */
            for(i=0;i<512;i++)
                if_spiSend(iface,buf[i]); /* Send data */
            if_spiSend(iface,0xff); /* Checksum part 1 */
            if_spiSend(iface,0xff); /* Checksum part 2 */

            if_spiSend(iface,0xff);

            while(if_spiSend(iface,0xff)!=0xff){
                t++;
                /* Removed NOP */
            }
            /*DBG((TXT("Nopp'ed %u times.\n"),t));*/

            return(0);
        }
        /*****************************************************************************/

        /* ****************************************************************************
        * WAIT ?? -- FIXME
        * CMDCMD
        * WAIT
        * CARD RESP
        * WAIT
        * DATA BLOCK IN
        *         START BLOCK
        *         DATA
        *         CHKS (2B)
        */

        esint8 sd_readSector(hwInterface *iface,euint32 address, euint8* buf, euint16 len)
        {
            euint8 cardresp;
            euint8 firstblock;
            euint8 c;
            euint16 fb_timeout=0xffff;
            euint32 i;
            euint32 place;

            /*DBG((TXT("sd_readSector::Trying to read sector %u and store it at %p.\n"),address,&buf[0]));*/
            place=address;
            if (SDHC == 0) {
                place=512*address;
            }
            sd_Command(iface,CMDREAD, (euint16) (place >> 16), (euint16) place);
           
            cardresp=sd_Resp8b(iface); /* Card response */

            /* Wait for startblock */
            do
                firstblock=sd_Resp8b(iface);
            while(firstblock==0xff && fb_timeout--);

            if(cardresp!=0x00 || firstblock!=0xfe){
                sd_Resp8bError(iface,firstblock);
                return(-1);
            }
           
            for(i=0;i<512;i++){
                c = if_spiSend(iface,0xff);
                if(i<len)
                    buf[i] = c;
            }

            /* Checksum (2 byte) - ignore for now */
            if_spiSend(iface,0xff);
            if_spiSend(iface,0xff);

            return(0);
        }
        /*****************************************************************************/

        /* ****************************************************************************
        calculates size of card from CSD
        (extension by Martin Thomas, inspired by code from Holger Klabunde)
        */
        esint8 sd_getDriveSize(hwInterface *iface, euint32* sectors )
        {
            euint8 cardresp, i, by;
            euint8 iob[16];
            euint16 c_size_mult, read_bl_len;
            euint32 c_size;
           
            sd_Command(iface, CMDREADCSD, 0, 0);
           
            do {
                cardresp = sd_Resp8b(iface);
            } while ( cardresp != 0xFE );

            DBG((TXT("CSD:")));
            for( i=0; i<16; i++) {
        #warning "inofficial CSD-read patch active sd_Resp8b->if_spiSend"
                /* iob[i] = sd_Resp8b(iface); */
                iob[i] = if_spiSend(iface,0xff);
                DBG((TXT(" %02x"), iob[i]));
            }
            DBG((TXT("\n")));

            if_spiSend(iface,0xff);
            if_spiSend(iface,0xff);
           

            if ((iob[0] & 0xc0) == 0) {         // CSD version 1
                c_size = iob[6] & 0x03; // bits 1..0
                c_size <<= 10;
                c_size += (euint16)iob[7]<<2;
                c_size += iob[8]>>6;

                by= iob[5] & 0x0F;
                read_bl_len = 1;
                read_bl_len <<= by;

                by=iob[9] & 0x03;
                by <<= 1;
                by += iob[10] >> 7;

                c_size_mult = 1;
                c_size_mult <<= (2+by);

                *sectors = (euint32)(c_size+1) * (euint32)c_size_mult * (euint32)read_bl_len / 512;
            }
            else if ((iob[0] & 0xc0) == 0x40) {         // CSD version 2
                c_size = (iob[7] & 0x3f) << 16;  // reserved - set to zero - c_size is 16 bits
                c_size += (iob[8] << 8);
                c_size += iob[9];

                *sectors = (euint32)(c_size+1) * 1024;   // indicates 512K

            }
            else {
                return 1;       // invalid CSD
            }
            return 0;
        }

         
  • Fred Bartoli

    Fred Bartoli - 2013-01-16

    Been using the EFSL (ver2.7) lib with Sandisk SD Ultra 2G cards for a few years with no problems.  Since they are now hard to get I need to use SDHC.   SO I used the "Updated to support SDHC cards by Selwyn Jackson May 2008 "  code from above to initialize the card, but I was still getting error when trying to initialize the file system (init_fs();), so what I was able to do is resize and reformat the SDHC cards.  I do not need more then 2G so I took an 8G and 16G Sandisk Ultra card and used MinitoolPartition to resize the primary partition to 1.99G, then I changed the file system to FAT16, then on the 16G card I had to change the Volume ID to 0x06 (for FAT16).

    So far it is working.

     

Log in to post a comment.