網路城邦
上一篇 回創作列表 下一篇   字體:
自己寫的SD CARD的driver
2008/11/25 17:12:56瀏覽16085|回應11|推薦0

以下是自己寫的sd card driver,雖然沒有整理成一個檔案,但有心要寫driver的人一定可以改的出來,因為關鍵點都列出來了!其中也有查表式的軟體CRC(這部份抄來的),SD 1.1的spec需要自己在網路上找,這個driver幾乎適用所有的cpu,只要有io腳都可以,8051也不例外,當然pic、TIDSP也可以,如果有硬體的SPI就更好了,只要加個FAT,就可以存取檔案了。

除了SDHC,大部分的SD CARD幾乎都試過,時間有限,就不逐行解釋了。

#include "sd.h"
#include "uart.h"
#include "tmr_ctrl.h"

#include "sdcmdset.h"
#include "sddef.h"

#define SD_DUMMY_WR()   CPLD_B.sd_wp = 0

/*
READ BLOCK:
DATA IN     *-CMD(1)-*
DATA OUT            *-R1(1)-**-START TOKEN(1)-**-DATA BLOCK(512)-**-CRC16(2)-*

READ BLOCK ERROR:
DATA IN     *-CMD(1)-*
DATA OUT            *-R1(1)-**-ERR TOKEN(1)-*

WRITE BLOCK:
DATA IN     *-CMD(1)-*       *-START TOKEN(1)-**-DATA BLOCK(512)-**-CRC16(2)-*
DATA OUT            *-R1(1)-*                                                 *-DATA RESP(1)-*--BUSY--

CSD REG:PAGE 63
SPI MODE:PAGE 86
CMD: PAGE 92
*/
#define SD_OP_COND_RETRY  100
#define SD_WR_TIMEOUT     10000   //max:65535
#define SD_TIMEOUT        255 // ms
#define SD_RETRY_TIME     3
#define SD_RESET_RETRY    1
#define SPI_DELAY         0
#define SD_CRC_DISP       0
#define SD_QRY_WR_STATUS  0


// ----------------- variable -------------------
U32   SD_TotalKB, SD_TotalSectors;
BOOL  SDActive = 0, SDWrLock = 0;

#define CSD_SIZE    (128/8)

static const U8 SDRstCmd[] = { 0xff, 0x40, 0, 0, 0, 0, 0x95, 0xff };
static const U8 SDOpCondCmd[]  = { 0xff, CMD1_OP_COND, 0, 0, 0, 0, 0xff, 0xff };

_EXTERNAL_MEMORY_
static char PTmp[40];
static U8 CSD[CSD_SIZE] = {0};

#if SD_DBG_MSG_ON
static const char *SDRespMsg[] = {
    // 16bit:0~7
    "IDLE",
    "Erase Reset",
    "Illegal Command",
    "CRC err.",
    "Erase Seq Err",
    "Addr OOB",
    "Arg OOB",
    "Unknown error",   
    // ---- 16bit:8~15
    "Card is Locked",
    "WP Erase Skip",
    "General error",
    "Card controller error",
    "Card ECC Error",
    "Write protect violation",
    "An invalid erase",
    "CSD_Overwrite"
};
#endif

// ----------------- PROTOTYPE -------------------

static void  Calc_CRC7 (U8 *buf, U16 len);
static U16   Calc_CRC16(U8 *ptr, U16 len) ;

static void  SPI_Wr(U8 arg);
static U8    SPI_Rd(void);

static U8    SD_RstCmd(void);
static U8    SD_InitCmd(void);
static U8    WaitSDResp8State(void);
static U8    WaitSDResp16State(void);
static void  _SDCmdOut(U8 cmd, U32 arg);
static U8    SD_Reset(void);
static U8    SDCmd200K(U8 *cmd, U8 len, U8 resp);
static U8 SDCmdRst400K(void);
#if SD_DBG_MSG_ON
  static void SD_ParseRespMsg(U16 val);
#endif

static void CalcSDSize(void);
static U8   SDCommand(U8 cmd, U32 arg);
static U8   SD_RdCSD(void);
static U8   QrySDStatus(void);
static void SD_OutputFF(U16 cnt);
// ----------------- function -------------------

#ifndef SYS_DELAY_TICK_US
  #define SpiDelay()  { U8 dly = SPI_DELAY; while(dly--); }
#else
  #define SpiDelay()     SysDelay(SYS_DELAY_TICK_US)
#endif

#define SpiDelay()  { U8 dly = SPI_DELAY; while(dly--); }


/**************** SD INIT *****************/

void SD_Init(void)
{  
    SD_IOInit();
    CPLD_B.sd_w = 0xff;
    SD_CSB(1);
}

static DISK_STATUS SD_Reset(void)
{
    U8  i;
   
    for(i = 0; i < SD_RESET_RETRY; i++)
    {
        if( !IsSDInsert() )
            return (fatDiskStatus = DISK_REMOVE);
      #if SD_DBG_MSG_ON
        DBG_PRINT("RST\xD\xA");
      #endif
     
        if( SD_RstCmd() != DISK_ACCESS_OK )
            continue;
       
        SD_DELAY(100);
      #if SD_DBG_MSG_ON
        DBG_PRINT("Init\xD\xA");
      #endif
     
        if( SD_InitCmd() != DISK_ACCESS_OK )
            continue;

        break;
    }
 
    return (fatDiskStatus = (i == SD_RESET_RETRY? DISK_ACCESS_ERROR:DISK_ACCESS_OK));
}

U8 SDCardCmd(U8 cmd, U32 arg)
{
 U8 resp;

    resp = SDCommand(cmd, arg);
    return resp;
}


/*****************************************************************************/
BOOL SDReadOnly(void)
{
    return SDWrLock;
}

DISK_STATUS  SDRdSector  (U32 lba, U8 *buf )
{
    U8 retry;
   
    if(lba < SD_TotalSectors)
    {
      #if SD_SIMPLE_MSG_ON
        DBG_PRINT("R");
      #endif
        for(retry = 0; retry < SD_RETRY_TIME; retry++)
        {           
            if( (fatDiskStatus = SD_RdBlock( lba, buf )) == DISK_ACCESS_OK )
            {
              #if SD_DBG_MSG_ON
                DBG_PRINT("SDRdSector:%lu\xD\xA", lba);
              #endif
                break;
            }
           
            if( IsSDInsert() )
            {
              #if SD_DBG_MSG_ON
                DBG_PRINT("SDRdSector Retry:%d\xD\xA", retry);
              #endif
                SD_Insert();           
            }
            else
            {
                return (fatDiskStatus = DISK_REMOVE);
            }
        }
    }
    else
    {
        fatDiskStatus = DISK_ACCESS_ERROR;
    }
    return fatDiskStatus;
}

DISK_STATUS  SDWrSector (U32  lba, U8 *buf )
{
    U8 retry;
           
  #if SD_MBR_PROTECT
    if(lba == 0)
    {
      #if SD_DBG_MSG_ON
        DBG_PRINT("SDWrSector:0\xD\xA");
      #endif
        return (fatDiskStatus = DISK_ACCESS_ERROR);
    }
  #endif
   
   
  #if SD_DBG_MSG_ON
    DBG_PRINT("SDWrSector:%lu\xD\xA", lba);
  #endif
   
    if(lba < SD_TotalSectors)
    {
      #if SD_SIMPLE_MSG_ON
        DBG_PRINT("W");
      #endif
     
        for(retry = 0; retry < SD_RETRY_TIME; retry++)
        {
            if( (fatDiskStatus = SD_WrBlock( lba, buf )) == DISK_ACCESS_OK )
                break;
       
            if( IsSDInsert() )
            {
              #if SD_DBG_MSG_ON
                DBG_PRINT("SDWrSector Retry:%d\xD\xA", retry);
              #endif
                SD_Insert();           
            }
            else
            {
                return (fatDiskStatus = DISK_REMOVE);
            }
        }
    }
    else
    {
        fatDiskStatus = DISK_ACCESS_ERROR;
    }
   
    return fatDiskStatus;
}


U8 SD_RdBlock(U32 blk, U8 *buf)
{
    U8    resp, retry;
    U16   i, crc16;
   
    blk *= SECTOR_SIZE;

    for(retry = 0; retry < SD_RETRY_TIME; retry++)
    {
        if( !IsSDInsert() )
            return DISK_REMOVE;
           
        if( (resp = SDCommand(CMD17_RD_ONE_BLK, blk )) != 0 )
        {
          #if SD_DBG_MSG_ON
            DBG_PRINT("SD_RdBlock retry:%d\xD\xA", retry);
          #endif
            SD_DELAY(100);
            continue;
        }
       
        for(i = 0; i<1000; i++)
        {
             if( SPI_Rd() == SINGLE_START_TOKEN )
                break;
        }
       
        for(i = 0; i<(SECTOR_SIZE); i++)
        {
            buf[i] = SPI_Rd();
        }
        // verify crc here if required.
        i  = (U16)SPI_Rd() << 8;  // 16bit CRC.
        i |= SPI_Rd();
       
        crc16 = Calc_CRC16(buf, 512);
     
        if(i != crc16)
        {
          #if SD_CRC_DISP
            DBG_PRINT("CRC16 ERROR:%x\xD\xA", i);
          #endif
            return DISK_ACCESS_ERROR;
        }
     
        break;
    }
   
    return retry == SD_RETRY_TIME? DISK_ACCESS_ERROR:DISK_ACCESS_OK;
}


U8 SD_WrBlock(U32 blk, U8 *buf)
{
    U16  i, crc16;
    U8   resp, retry;
   
    blk *= SECTOR_SIZE;

    for(retry = 0; retry < SD_RETRY_TIME; retry++)
    {
        if( !IsSDInsert() )
            return DISK_REMOVE;
           
        if( (resp = SDCommand(CMD24_WR_ONE_BLK, blk)) != 0 )
        {
          #if SD_DBG_MSG_ON
            DBG_PRINT("\xD\xA:w retry:%d\xD\xA", retry);
          #endif
            SD_DELAY(100);
            continue;
        }
       
        SPI_Wr( SINGLE_START_TOKEN );
       
        for(i = 0; i<SECTOR_SIZE; i++)
             SPI_Wr( buf[i] );
       
        // --- send crc here if required ---- //
        crc16 = Calc_CRC16(buf, 512);
        SPI_Wr( (U8)(crc16>>8) );
        SPI_Wr( (U8)crc16      );

        // ============= wait response ============= //
       
        for(i = 0; i<SD_WR_TIMEOUT; i++)
        {
            if( (resp = SPI_Rd()) != 0xff )
                break;
        }

        if( i == SD_WR_TIMEOUT )
        {
            #if SD_DBG_MSG_ON
              DBG_PRINT("SD Timeout1:\xD\xA");
            #endif
            return DISK_TIMEOUT;
        }
       
        // ========================================= //
       
        // ============= wait bus idle ============= //
        for(i = 0; i<SD_WR_TIMEOUT; i++)
        {
            if( SPI_Rd() == 0xff )
                break;
        }

        if( i == SD_WR_TIMEOUT )
        {
            #if SD_DBG_MSG_ON
              DBG_PRINT("SD Timeout2:\xD\xA");
            #endif
            return DISK_TIMEOUT;
        }
       
        // ============= parse response ============ //
        if( (resp & 0x5) != 0x5 )
        {
          #if SD_DBG_MSG_ON
            DBG_PRINT("\xD\xAWRespErr:%x\xD\xA", resp);
          #endif
            continue;
        }
        break;
    }

  #if SD_QRY_WR_STATUS
    if(retry < SD_RETRY_TIME)
    {
        QrySDStatus();
    }
  #endif

    return retry >= SD_RETRY_TIME? DISK_ACCESS_ERROR:DISK_ACCESS_OK;
}


// ----------------------------- local api --------------------------

static U8 SD_RstCmd(void)
{
    U16 i, ii;

    SD_PWR(PWR_OFF);
    SD_DELAY(2000);
    SD_PWR(PWR_ON);
    SD_DELAY(1000);
   
    CPLD_B.sd_w = 0xff;
   
    SD_OutputFF(10);

    SD_CSB(0);
    if( SDCmd200K(SDRstCmd, sizeof(SDRstCmd), 1) != 1 )
    {
      #if SD_DBG_MSG_ON
        DBG_PRINT("SD_RstCmd Err.\xD\xA");   
      #endif
        return DISK_ACCESS_ERROR;
    }

    return DISK_ACCESS_OK;
}

static void SDOClk200K_H(void)
{
    SD_CLK(1);
    SD_DUMMY_WR();
    SD_DUMMY_WR();
    SD_DUMMY_WR();
}

static void SDOClk200K_L(void)
{
    SD_CLK(0);
    SD_DUMMY_WR();
}

static void SDIClk200K_H(void)
{
    SD_CLK(1);
    SD_DUMMY_WR();
}

static void SDIClk200K_L(void)
{
    SD_CLK(0);
    SD_DUMMY_WR();
    SD_DUMMY_WR();
}

static U8 SDCmd200K(U8 *cmd, U8 len, U8 resp)
{
    register U8  val;
    register U16 retry = 50000;
   
    while(len--)
    {
        val = *cmd;
        cmd++;
        CPLD_B.sd_w = val;
        SDOClk200K_H();   SDOClk200K_L();
        SDOClk200K_H();   SDOClk200K_L();
        SDOClk200K_H();   SDOClk200K_L();
        SDOClk200K_H();   SDOClk200K_L();
        SDOClk200K_H();   SDOClk200K_L();
        SDOClk200K_H();   SDOClk200K_L();
        SDOClk200K_H();   SDOClk200K_L();
        SDOClk200K_H();   SD_CLK(0);
    }

    CPLD_B.sd_w = val = 0xff;
    while( val != resp )
    { 
        if( !IsSDInsert() )
            return 0xff;

        SDIClk200K_H();   SDIClk200K_L();
        SDIClk200K_H();   SDIClk200K_L();
        SDIClk200K_H();   SDIClk200K_L();
        SDIClk200K_H();   SDIClk200K_L();
        SDIClk200K_H();   SDIClk200K_L();
        SDIClk200K_H();   SDIClk200K_L();
        SDIClk200K_H();   SDIClk200K_L();
        SDIClk200K_H();   SDIClk200K_L();
       
        val = CPLD_B.sd_r;
        if( !(retry--) )
        {
            SD_OutputFF(1);
          #if SD_DBG_MSG_ON
            DBG_PRINT("--400K TimeOut:%x\xD\xA", val);
          #endif
            return 0xff;
        }
       
    }

    SD_OutputFF(1);
   
    return val;
}

static U8 SD_InitCmd(void)
{
    U8   i;

    for(i = 0; i < SD_OP_COND_RETRY; i++)
    {
        if( !IsSDInsert() )
            return DISK_REMOVE;
       
        if( SDCmd200K(SDOpCondCmd, sizeof(SDOpCondCmd), 0) == 0 )
            break;
           
        SD_DELAY(15);
    }
   
    if(i == SD_OP_COND_RETRY)
    {
      #if SD_DBG_MSG_ON
        DBG_PRINT("SDOpCond Err.\xD\xA");
      #endif
        return DISK_ACCESS_ERROR;
    }
   
    SDCardCmd(CMD59_CRC_ONOFF, 1);
   
    if( SDCardCmd(CMD16_SET_BLKLEN, 512) != 0 )
    {
      #if SD_DBG_MSG_ON
        DBG_PRINT("SDBlkLen Err.\xD\xA");
      #endif
        return DISK_ACCESS_ERROR;
    }
   
    return DISK_ACCESS_OK;
}

static void _SDCmdOut(U8 cmd, U32 arg)
{
    U8   *ptr = (U8*)&arg;
    U8   d[7];
    U8   i;
           
    d[0+1] = cmd;
  #ifdef B_ENDIAN
    d[1+1] = ptr[0]; d[2+1] = ptr[1]; d[3+1] = ptr[2]; d[4+1] = ptr[3];
  #else
    d[1+1] = ptr[3]; d[2+1] = ptr[2]; d[3+1] = ptr[1]; d[4+1] = ptr[0];
  #endif
    //d[5+1] = 0xFF;  // null crc.
    Calc_CRC7(d, 6);
   
    SPI_Wr( 0xff );
    for(i = 1; i<7; i++)
    {
        SPI_Wr( d[i] );
    }
    SPI_Wr( 0xff );
}

static U8 SDCommand(U8 cmd, U32 arg)
{
    _SDCmdOut(cmd, arg);
    return WaitSDResp8State();
}

static void CalcSDSize(void)
{
    U32 mult, bk_size;
    U32 block_nr;
       
    bk_size = 1 << (RdBitPosiVal(CSD, CSD_RD_BL_LEN_LOC, CSD_RD_BL_LEN_BITS) - 9) ;   // unit:0.5kb.
    mult    = 1 << (RdBitPosiVal(CSD, CSD_C_SIZE_MULT_LOC, CSD_C_SIZE_MULT_BITS) + 2 );
    block_nr = ((U32)RdBitPosiVal(CSD, CSD_C_SIZE_LOC, CSD_C_SIZE_BITS) + 1) * mult;
   
    SD_TotalSectors = block_nr * bk_size;
    SD_TotalKB = SD_TotalSectors / 2;    // unit:1kb
  #if SD_DBG_MSG_ON
    DBG_PRINT("SD:%ldKB, %ldMB.\xD\xA", SD_TotalKB, SD_TotalKB>>10);
  #endif
}

static U8 SD_RdCSD(void)
{
    U8     resp;
    U16    i;
   
    if( (resp = SDCommand(CMD9_SEND_CSD, 0)) != 0 )
    {
        return resp;
    }
   
    for(i = 0; i<0x100; i++)
    {
         if( SPI_Rd() == SINGLE_START_TOKEN )
            break;
    }
    for(i = 0; i<CSD_SIZE; i++)
    {
         CSD[i] = SPI_Rd();
    }
   
    // verify crc here if required.
    i  = SPI_Rd() << 8;  // 16bit CRC.
    i |= SPI_Rd();

  #if SD_CRC_DISP
    DBG_PRINT("CRC16:%x\xD\xA", i);
  #endif
    return SD_READ_OK;
}

static U8 WaitSDResp8State(void)
{
    U8  resp;
   
    SetTimeOut(SD_TIMEOUT);  // ms.
   
    while( (resp = SPI_Rd()) == 0xff )
    {
        if( IsTimeOut() )
        {
          #if SD_DBG_MSG_ON
            DBG_PRINT("--Cmd TimeOut\xD\xA");
          #endif
            break;
        }
    }
   
  #if SD_DBG_MSG_ON
    SD_ParseRespMsg(resp);
  #endif
    return resp;
}

#if SD_QRY_WR_STATUS
  static U8 QrySDStatus(void)
  {
      _SDCmdOut(CMD13_SEND_STATUS, 0);
      return WaitSDResp16State();
  }
 
  static U8 WaitSDResp16State(void)
  {
      U16 resp;
     
      SetTimeOut(SD_TIMEOUT);  // ms.
 
      while( (resp = SPI_Rd()) == 0xff )
      {
          if( IsTimeOut() )
          {
            #if SD_DBG_MSG_ON
              DBG_PRINT("--Cmd TimeOut\xD\xA");
            #endif
              return 0xff;
          }
      }
     
      resp <<= 8;
      resp |= SPI_Rd();
    #if SD_DBG_MSG_ON
      SD_ParseRespMsg(resp);
    #endif
     
      return resp;
  }
#endif


#if SD_DBG_MSG_ON
  static void SD_ParseRespMsg(U16 val)
  {
      U8  i;
      U16 sft;
     
      for(i = 0, sft = 1; i < 16;
          i++  , sft<<=1)
      {
          if(val & sft) DBG_PRINT("Resp:%s\xD\xA", SDRespMsg[i]);
      }
  }
#endif


void SD_Eject(void)
{
    SD_PWR(PWR_OFF);
    SD_IOInit();
    SDActive = 0;
  #if SD_DBG_MSG_ON
    DBG_PRINT("\xD\xA##SD Extract##\xD\xA");
  #endif
}

// FALSE: ERR,    TRUE:OK.
BOOL SD_Insert(void)
{
    SDActive = FALSE;
   
    if( !IsSDInsert() )
        return FALSE;
   
    SD_Init();

    if( SD_Reset() != DISK_ACCESS_OK )
    {
      #if SD_DBG_MSG_ON
        DBG_PRINT("SD_Reset Err\xD\xA");
      #endif
        return FALSE;
    }
  #if SD_DBG_MSG_ON
    else
        DBG_PRINT("\xD\xA**SD Ready**\xD\xA");
  #endif
 
    SD_RdCSD();   
    CalcSDSize();
   
    SDWrLock = IsSDLock();
    SDActive = TRUE;
   
  #if SD_DBG_MSG_ON
    if(SDWrLock)
        DBG_PRINT("SD RO\xD\xA");
    else
        DBG_PRINT("SD RW\xD\xA");
  #endif
 
    return TRUE;
}

// --------------------------- SPI BUS --------------------------- //
static U8 SPI_Rd(void)
{
    register U8 val = 0;
    U8 i;
   
    CPLD_B.sd_w = 0xff;
       
    for(i = 0; i<8; i++)
    {
        val<<=1;
   
        SpiDelay();
        SD_CLK(1);
        SpiDelay();
        val |= SD_SDO();
        SD_CLK(0);
    }

    return val;
}

static void SPI_Wr(U8 v)
{
    register U8 val;
    U8   i;
    val = v;

    for(i = 0; i<8; i++, val<<=1)
    {
        SD_SDI( (val & 0x80) );
        SpiDelay();
        SD_CLK(1);
        SpiDelay();
        SD_CLK(0);
    }
}

static void SD_OutputFF(U16 cnt)
{
    U8  ii;
   
    SD_SDI(1);
    while(cnt--)
    {
        for(ii = 0; ii<8; ii++)
        {
            SYS_TINY_DELAY_INIT();
            SD_CLK(1);           
            SYS_TINY_DELAY_WAIT();
            SD_CLK(0);
        }
    }
}

static const U8 CRC7_Table[256] = {
//    0      1      2      3      4      5      6      7      8      9     10     11     12     13     14     15
    0x00 , 0x09 , 0x12 , 0x1B , 0x24 , 0x2D , 0x36 , 0x3F , 0x48 , 0x41 , 0x5A , 0x53 , 0x6C , 0x65 , 0x7E , 0x77 ,
    0x19 , 0x10 , 0x0B , 0x02 , 0x3D , 0x34 , 0x2F , 0x26 , 0x51 , 0x58 , 0x43 , 0x4A , 0x75 , 0x7C , 0x67 , 0x6E ,
    0x32 , 0x3B , 0x20 , 0x29 , 0x16 , 0x1F , 0x04 , 0x0D , 0x7A , 0x73 , 0x68 , 0x61 , 0x5E , 0x57 , 0x4C , 0x45 ,
    0x2B , 0x22 , 0x39 , 0x30 , 0x0F , 0x06 , 0x1D , 0x14 , 0x63 , 0x6A , 0x71 , 0x78 , 0x47 , 0x4E , 0x55 , 0x5C ,
    0x64 , 0x6D , 0x76 , 0x7F , 0x40 , 0x49 , 0x52 , 0x5B , 0x2C , 0x25 , 0x3E , 0x37 , 0x08 , 0x01 , 0x1A , 0x13 ,
    0x7D , 0x74 , 0x6F , 0x66 , 0x59 , 0x50 , 0x4B , 0x42 , 0x35 , 0x3C , 0x27 , 0x2E , 0x11 , 0x18 , 0x03 , 0x0A ,
    0x56 , 0x5F , 0x44 , 0x4D , 0x72 , 0x7B , 0x60 , 0x69 , 0x1E , 0x17 , 0x0C , 0x05 , 0x3A , 0x33 , 0x28 , 0x21 ,
    0x4F , 0x46 , 0x5D , 0x54 , 0x6B , 0x62 , 0x79 , 0x70 , 0x07 , 0x0E , 0x15 , 0x1C , 0x23 , 0x2A , 0x31 , 0x38 ,
    0x41 , 0x48 , 0x53 , 0x5A , 0x65 , 0x6C , 0x77 , 0x7E , 0x09 , 0x00 , 0x1B , 0x12 , 0x2D , 0x24 , 0x3F , 0x36 ,
    0x58 , 0x51 , 0x4A , 0x43 , 0x7C , 0x75 , 0x6E , 0x67 , 0x10 , 0x19 , 0x02 , 0x0B , 0x34 , 0x3D , 0x26 , 0x2F ,
    0x73 , 0x7A , 0x61 , 0x68 , 0x57 , 0x5E , 0x45 , 0x4C , 0x3B , 0x32 , 0x29 , 0x20 , 0x1F , 0x16 , 0x0D , 0x04 ,
    0x6A , 0x63 , 0x78 , 0x71 , 0x4E , 0x47 , 0x5C , 0x55 , 0x22 , 0x2B , 0x30 , 0x39 , 0x06 , 0x0F , 0x14 , 0x1D ,
    0x25 , 0x2C , 0x37 , 0x3E , 0x01 , 0x08 , 0x13 , 0x1A , 0x6D , 0x64 , 0x7F , 0x76 , 0x49 , 0x40 , 0x5B , 0x52 ,
    0x3C , 0x35 , 0x2E , 0x27 , 0x18 , 0x11 , 0x0A , 0x03 , 0x74 , 0x7D , 0x66 , 0x6F , 0x50 , 0x59 , 0x42 , 0x4B ,
    0x17 , 0x1E , 0x05 , 0x0C , 0x33 , 0x3A , 0x21 , 0x28 , 0x5F , 0x56 , 0x4D , 0x44 , 0x7B , 0x72 , 0x69 , 0x60 ,
    0x0E , 0x07 , 0x1C , 0x15 , 0x2A , 0x23 , 0x38 , 0x31 , 0x46 , 0x4F , 0x54 , 0x5D , 0x62 , 0x6B , 0x70 , 0x79
};

static const U16 CRC16_Table[256]={
    0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
    0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
    0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
    0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
    0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
    0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
    0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
    0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
    0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
    0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
    0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
    0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
    0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
    0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
    0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
    0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
    0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
    0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
    0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
    0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
    0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
    0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
    0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
    0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
    0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
    0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
    0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
    0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
    0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
    0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
    0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
    0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
};

static void Calc_CRC7 (U8 *buf, U16 len)
{
    register U8   acc = 0;
    register U16  i;

    buf[0] = 0;
    for (i = 0;  i < len;  ++i)
    {
      acc = CRC7_Table[ (acc << 1) ^ buf[i] ];
    }

    buf[6] = ((buf[0] ^ acc) << 1) | 0x1;
}

static U16 Calc_CRC16(U8 *ptr,  U16 len)
{
    register U16 crc;
    U8  d;
 
    crc = 0;
    while(len-- != 0)
    {
        d = (U8) (crc >> 8);
        crc <<= 8;
        crc ^= CRC16_Table[d ^ *ptr];
        ptr++;
    }
    return crc;
}

( 時事評論政治 )
回應 推薦文章 列印 加入我的文摘
上一篇 回創作列表 下一篇

引用
引用網址:https://classic-blog.udn.com/article/trackback.jsp?uid=cchahacaptain&aid=2416395

 回應文章 頁/共 2 頁  回應文章第一頁 回應文章上一頁 回應文章下一頁 回應文章最後一頁

KJ
Header File for SD Card Driver
2011/05/03 09:32

您好,因為最近有測試治具記錄資料的需求,所以想採用SD Card來做量測資料的記錄,也因此爬文爬到貴寶地,目前程式環境是採用Keil C進行程式的撰寫,在爬了一下之後,也跟其他人有相同的問題,就是您程式中Header File的部份,不知是否可以分享給小弟呢?

小弟的E-mail是 kjung.tw@yahoo.com.tw

感謝您了.

之前C語言只是寫一些測試用的東西而已,對於這些較進階的部份比較不懂,所以如果問了一些阿里不達的問題時,請多多包涵,謝謝.

彼得鄧(cchahacaptain) 於 2011-05-03 17:32 回覆:
真的有缺嗎?可能是我沒有檢察清楚,我不是很清楚缺了哪個,可以告訴我嗎?

彼得鄧
等級:7
留言加入好友
程式碼
2011/04/06 13:43

skydrive不知原因的掛了,我把程式碼放在hinet上,應該沒問題了

http://petercake.myweb.hinet.net/download/fat.zip

裡面的fat_new是我從以前做的案子裡刮出來的,應該是穩定的,只不過要花點時間移植。

mcu_8051是更久以前使用8051平台做出的,會動,配合前面的fat_new來修改才會比較正常動作。

使用單晶片來移植要很注意熱插拔造成的SD CARD ESD毀損的問題,一般硬體工程師通常不會注意這個嚴重性,尤其這個問題加上脈衝電流會更嚴重,要使用可以floating的腳位才會比較安全,等確定插上後,再來設定io方向,8051可以使用P0=0xFF使port變成open drain

sd card電源最好設計成BJT電流源控制,控制在幾百mA以下,不然至少也要加個電感,來避免sd card插上時脈衝電流灌入io port導致sd card毀損。


zero
請問這份程式可否拿來做SPI
2010/12/01 19:53

您好,

我目前正在試著用SPI來把CPU的資料寫入SD CARD,

所用的CPU是32bit的,而CPU本身有內建SPI的功能,

想請問一下,這份程式是否可應用到上面?

如果可套用上去,那我需要先完成哪些設定?

因為問題有點多,

所以如果可以的話,是否可以跟您要您的信箱,以便請教您呢?

麻煩您了,謝謝

彼得鄧(cchahacaptain) 於 2010-12-06 10:45 回覆:

可以,把spi設定好就可以了,把我程式內spi R/W改成硬體就可以了,硬體spi更好用。

只不過我的程式只支援sd1.1,2.0存取模式稍稍不同,我沒有支援。

cchaha@ms35.hinet.net


急思考keil c 的人
疑問
2010/02/11 13:48
如果是用來讀出usb內的資料內容,是否是一樣用這一個程式碼??
彼得鄧(cchahacaptain) 於 2010-02-13 08:59 回覆:

那個zip檔只有sd card driver,fat部分是可共用的,usb要自己弄了。

usb1.1, 2.0的等級和SD類似,但是複雜一些,和pc對連更要面臨WDM的問題,這裡建議直接使用大廠的solution,如果要發展自己的solution,建議用mess storage就好,搭配網路上找到的usb open source就可以了。

windows程式要穩定就不是我辦的到的,一定要去問專門寫WDM的人,microsoft的東西很麻煩,規格很常變,windows 7也不知道吃不吃WDM,windows部分真的無能為力。


ahkun
感謝您的回覆...^^
2010/01/17 06:18
說實在的, 小弟的 C 還真的很肉腳!
最近在摸 mp3+sd+ide 的開發板,
為了 函式參數傳遞 造成動作異常的問題, 抓了老半天
目前雖然動作已正常, 可是問題還是不知出在那裡, 於是就將就用了...^^"

也因此, 怕 linux c 與 keil c 語法會差很多,
才會厚這臉皮, 問看看有沒有 keil c 的源碼...^^"
不過這樣也好, 這樣就沒有理由摸魚打混了...^^"
同時也可看看 linux c 與 keil c 的差異性.

很少在網路上發文, 若有不得體之處, 還請見諒!

最後要再次感謝您提供的資料, 也謝謝撥空回覆.
謝謝! ^_^
彼得鄧(cchahacaptain) 於 2010-01-21 13:35 回覆:

這類的問題我倒幫得上忙,我會的很少,只能提供一點小小意見。

linux ckeil c、乃至於windows C, ARM C, x86 C的差異到底在哪裡呢?其實許多人都會問類似的問題。

c語言是幾十年前以那個時代的計算機想像出來的解決方案,某個實驗室認為只要用c語言的模式,就是int, for, while void func(xxx)等等的語法,同時包含翻譯到組合語言的介面規格,這個模式就能夠以計算機來解決問題,同時這個解決方法可以在不同的計算機都能夠用。

所以不管哪種語言,乃至於VBJava等等,終究要回歸到個機器的組合語言,組合語言更要回歸到機械碼,機械碼便是啟動cpu與各類硬體周邊的開關。

Keil只是公司,他們公司有出產各種cpucompiler,乃至於RTOS都有,同公司的tool有一個好處,就是思考模式類似,文件類似,tool產生的資訊如map檔案都類似,如果我們用同一種公司的tool,便會省去許多學習與猜測的時間。

ARM/x86/8051/PIC等等cpu,是由ARM/INTEL/MICORCHIP等等公司的專利,他們發明了各種結構來解決某類的問題,例如ARM7沒有除法指令,x86卻有,學過邏輯設計就知道,除法電路是比較龐大與複雜的電路,而一般的問題並不太需要太多的複雜除法,所以是否需要在一顆cpu內加入除法電路?可否用較慢的軟體動作來達到除法的功能?這便要看解決的問題是哪種類型,ARM7X86的精神是不同的,產品只要做到可解決便可,複雜的CPU意味著複雜的學習與製造,solution適當性牽涉PM對資源的了解與否。

Linuxwindows差別呢?windows是微軟認為如何以計算機來解決事情,它牽涉到各類資源的統合,螢幕顯示有大有小,cpu有老有舊,程式也有老舊,會新增刪除,各種奇怪的硬體,使用者有笨的聰明的,有工程師也有玩電動的,當然也有看A片的,還有相容性問題等等,是個非常龐大的solution,微軟使用了許多方法,windows APIDLLActive XWDM等等方法,所以用這類的角度來看linux等等其他作業系統,就會明白其實並無好壞,只是單純的適用性的問題,硬要拿linux的強項來比windows的弱項是不公平的,windowslinux4隻不同的企鵝也不太好,每種solution都有他的適用極限。

        所以在linuxwindows內發展軟體的精神是不同的,就算都是linuxPCembedded system也是不同的,就算都是c語言,ARM/x86操作手法也是不同的,人類的精力很有限,所以要慎選範圍,有些學習僅供吃飯用,有些學習是人生大事,要花多少力氣去搞,要好好想想了。


ahkun
關於 - 比較完整的程式碼
2010/01/10 18:47
小弟剛接觸 sd card, 也是在網路上爬文爬到這兒來.
不知您那 "比較完整的程式碼" 是什麼環境的?
如是 linux source code, 小弟無 linux 的環境
在前文有看到您先前就是用keil c發展的,
請問可否寄一份 keil c 版的,
給小弟我(ak@ahkun.com)參考嗎?
如 "比較完整的程式碼" 是 keil C source code, 就以上略過.

在此感謝您無私的分享此技術! ^^
彼得鄧(cchahacaptain) 於 2010-01-13 10:42 回覆:

那份keil C版的已經因為幾年前的電腦浩劫消失了,實在是莫可奈何。

"比較完整的程式碼"是說這份原始碼已經包含FAT16/32+sd card driver,其中fat16/32也有api可以使用,只是需要花精神移植。

這份程式碼是我從我幫某家公司做的案子中抽出的,做了好久才完成,後來發現其他人也有需求,覺得這種程式碼實在不需要所有人都走一次,才決定把他公布出來。

MCU絕對可用,最早期是用AT89C52外掛ROM/RAM發展完成,後來移植到某些32bit的cpu,要移植先做到以下動作:

1. 想盡辦法compiler完成。

2. 做出rs232,連結到pc的hyper terminal,這樣發展測試會很快

基本上c語言熟悉的人,應該幾天就可以移植完成。


彼得鄧
等級:7
留言加入好友
比較完整的程式碼
2009/11/30 09:21

移植這些東西要花些力氣來增修程式,不過內容看過是完整的,受限於時間,可能幫不上忙,除非有必要,記得把CRC關閉,這非常耗CPU時間,記得也要叫SD CARD關閉CRC。

fat部分原本是從source forge取得,但因為內容不完整被我重寫了,可支援fat32/16,不支援長檔名,同時也被我改成catch模式,這樣比較快,但要耗記憶體。

sdcmdset.h因為懶的key,所以是從網路上的某處抄來的,年代已非常久遠,也忘了在哪找到的!

sd.c部分裡面有需要200kHz來initial的命令,我發現台灣的sd card似乎不需要這樣做,反倒是有些國際大廠有這個限制,如果有硬體SPI的還好解決,沒有的就需要示波器來幫忙了。

程式碼有無問題,我也不敢保證,畢竟這是4年前寫的,寫的也不見得好,有問題就改掉吧!

這裡不建議把這些東西改的太完整,例如長檔名,就算你寫出來了也會發現沒甚麼機會用,但是這些東西會花掉你非常多的時間,也沒甚麼研究價值,就是規格罷了。

特殊應用的同志們,例如會長時間存取,千萬注意儲存裝置的讀寫特性,這部分solution的提供者不一定會幫你做好,但是這部分牽涉到儲存裝置的壽命、相容性與存取效率,差異非常的大,要搞這部分記得要把microsoft fat規格書讀熟。

搞檔案系統要小心有些存取錯誤是導因於硬體,如果傻傻的一直在程式碼裡尋找,小心會找死掉。


KENI LIN
謝謝您的回覆...
2009/11/18 13:14

感謝您的回覆!!

用8051控制SD card讀寫,有詢問過Slilcon代理商FAE,但他們是把SD Card當作一般flash讀寫用,可是我是要做成FAT16格式存成 TXT 檔,再從8051去 load TXT 檔裡面的文字.

在網路爬文找了好久,才找到您的分享,如果有進一步消息再麻煩您指點我,謝謝!

My mail : keni_lin@hotmail.com

謝謝!

keni 2009.11.18

彼得鄧(cchahacaptain) 於 2009-11-19 10:38 回覆:

不知道你有沒有去keil的網站下載uvision 2的driver,這樣就可以使用keil的ide來發展,比用silicon lab的ide要好用多了。

silicon lab的cpu還滿快的,也有硬體spi,spi把它拼到極限應該沒有關係,只要把sd card 的crc檢查關閉就可以非常快速的存取,所以我的程式你還要再修改一下。

程式碼的部分您可能還要再等一下,我最近事情太多了~~~~


KENI_LIN
請教一下程式....
2009/11/10 16:07

請問這篇文章的h檔是您定義的嗎? 還是可以在哪裡可以下載到?

#include "sd.h"
#include "uart.h"
#include "tmr_ctrl.h"
#include "sdcmdset.h"
#include "sddef.h"

如果都是您這邊自己定義,可以寄給我(keni_lin@hotmail.com)參考嗎? 最近我在研究如何用8051讀SD Card裡面的資料,爬文的時候發現您的這篇文章,希望可以跟您交流一下心得!

另外我是用Keil C編輯程式,不知到你的程式有沒有支援Keil C的平台.

彼得鄧(cchahacaptain) 於 2009-11-17 09:51 回覆:

對啊,都是我自己定義的,其實我很想把這些東西放在網路硬碟上,讓有需要的人自行取用,但我目前發現的網路硬碟都有使用時間,時間一到就自動刪除,超麻煩。

但是sd規格書好像有保密,是不能隨意傳遞的,程式碼是我自己寫的,應該沒關係吧!

fat的程式碼是在source forge找到的,但是那版的程式fat32沒做完,存取效率也不行,我把它全部改寫了,本來想放回source forge的,但是不知道怎麼做,想想就算了。

linux source code太高級了,不適用8051。

keil C可以用,我當初就是用keil c發展的,後來才移植到其他32bit平台,最近比較忙,我整理整理再寄給你參考一下。

只不過8051是8bit,fat32會使用到大量的unsigned long變數,運算速度會非常慢,尤其是上面的CRC打開後,會慢到嚇死人,如果cpu沒有SD interface但又很需要SD的話,建議增加一顆CPLD來做CRC+SPI,CPLD又可以設定成open drain,一舉數得,只是麻煩點。


qqaf9195
請教一下
2009/09/09 00:19

我看不懂...請教一下這個程式如何使用???

可以留信箱給我嗎??我希望可以請教有關這方面的問題...謝謝

彼得鄧(cchahacaptain) 於 2009-09-09 10:51 回覆:

目前許多多媒體solution的cpu都有內建sd card的處理線路,就會用不到我提供的程式,許多solution應該都有os在內,存檔機制都很完整,就更不需要了。 

但是有許多工控設備並沒有這些東西,如果他們要sd card怎麼辦,sd card非常方便,可以存很多東西,一般都喜歡用內建eeprom來解決這事,許多工控cpu都是16/32bit,處理fat是很容易的事,8bit會比較慢,如果這些cpu可以再移植一個小型os就更漂亮了。

這個是最底層的driver,連最原始的8051都可以直接使用,sd card本身就是SPI介面。

cchaha@ms35.hinet.net

頁/共 2 頁  回應文第一頁 回應文章上一頁 回應文章下一頁 回應文章最後一頁