網路城邦
上一篇 回創作列表 下一篇   字體:
自己寫的SD CARD的driver
2008/11/25 17:12:56瀏覽16084|回應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 頁  回應文章第一頁 回應文章上一頁 回應文章下一頁 回應文章最後一頁

奇怪
奇怪
2008/11/27 09:34

請問SD_RstCmd裡面要送出10個0xff是為什麼?還有這個程式穩嗎?

彼得鄧(cchahacaptain) 於 2008-11-28 13:50 回覆:

這是spec內規範的,我已經忘掉到底是10個還是8個,其實有許多serial interface的ic,例如ADC,因為沒有reset pin的存在,所以他們會使用一連串0xff的dummy cycle來當作reset,我猜sd card應該也是一樣的原因。

程式本身的邏輯是正確的,可是所謂的"穩定"需要包含的因素有很多,例如sd card需要熱插拔,如果電路設計有問題,例如瞬間電流或是io腳有過大的漏電流,就有可能造成損壞,再來io線路太長,或是有訊號反射發生,都會造成存取錯誤,另外有的記憶卡偷懶沒有crc check,甚至是該SOC的其他不相干的電路不穩,連帶影響到SD CARD的介面,這類的問題腦袋想到爆都很難找到。

問題太多了,當在尋找bug的時候,例如剛才提到其他不相干的電路不穩造成的影響,如果傻傻的只知道拼命找sd card,那真的會找到天荒地老都找不到,找問題有時要活一點,軟體硬體不要分的太清楚,因為軟硬體只是工作分工,現象可是不分的,因為實際上就只是電子流動的現象,哪有軟硬體差別呢?

以上小小心得,看過了就好,不要太當一回事!

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