// -------------------------------------------------------------------- // Copyright (c) 2005 by Terasic Technologies Inc. // -------------------------------------------------------------------- // // Permission: // // Terasic grants permission to use this code for all Terasic Development Boards // and Altera Development Kits made by Terasic. // Other use of this code, including the selling // ,duplication, or modification of any portion is strictly prohibited. // // // -------------------------------------------------------------------- // // Terasic Technologies Inc // 356 Fu-Shin E. Rd Sec. 1. JhuBei City, // HsinChu County, Taiwan // 302 // // web: http://www.terasic.com/ // email: support@terasic.com // // -------------------------------------------------------------------- // //--------------------------------------------------------------------------- #include // usleep #include #include "my_includes.h" #include "SDCardDriver.h" #include "debug.h" #ifdef DEBUG_SDCARD #define SDCARD_DEBUG(x) DEBUG(x) #else #define SDCARD_DEBUG(x) #endif #define DEBUG_SDCARD_HEX //DEBUG_HEX_PRINTF alt_u8 gszCSD[17]; alt_u8 gszCID[17]; bool gbActive = FALSE; //------------------------------------------------------------------------- void Ncr(void); void Ncc(void); alt_u8 send_cmd(alt_u8 *in); alt_u8 send_cmd(alt_u8 *); alt_u8 response_R(alt_u8 s); //------------------------------------------------------------------------- alt_u8 read_status; alt_u8 response_buffer[20]; alt_u8 RCA[2]; alt_u8 cmd_buffer[5]; const alt_u8 cmd0[5] = {0x40,0x00,0x00,0x00,0x00}; const alt_u8 cmd55[5] = {0x77,0x00,0x00,0x00,0x00}; const alt_u8 cmd2[5] = {0x42,0x00,0x00,0x00,0x00}; const alt_u8 cmd3[5] = {0x43,0x00,0x00,0x00,0x00}; const alt_u8 cmd7[5] = {0x47,0x00,0x00,0x00,0x00}; const alt_u8 cmd9[5] = {0x49,0x00,0x00,0x00,0x00}; const alt_u8 cmd10[5] = {0x4a,0x00,0x00,0x00,0x00}; // richard add const alt_u8 cmd16[5] = {0x50,0x00,0x00,0x02,0x00}; const alt_u8 cmd17[5] = {0x51,0x00,0x00,0x00,0x00}; const alt_u8 acmd6[5] = {0x46,0x00,0x00,0x00,0x02}; const alt_u8 acmd41[5] = {0x69,0x0f,0xf0,0x00,0x00}; const alt_u8 acmd51[5] = {0x73,0x00,0x00,0x00,0x00}; //------------------------------------------------------------------------- void Ncr(void) { SD_CMD_IN; SD_CLK_LOW; SD_CLK_HIGH; SD_CLK_LOW; SD_CLK_HIGH; } //------------------------------------------------------------------------- void Ncc(void) { int i; for(i=0;i<8;i++) { SD_CLK_LOW; SD_CLK_HIGH; } } void dump_CSD(alt_u8 szCSD[]){ SDCARD_DEBUG(("SD-CARD CSD:...\r\n")); } void dump_CID(alt_u8 szCID[]){ const int i = 1; SDCARD_DEBUG(("SD-CARD CID:\r\n")); SDCARD_DEBUG((" Manufacturer ID(MID):%02Xh\r\n", szCID[i+0])); SDCARD_DEBUG((" OEM/Application ID(OLD):%02X%02Xh\r\n", szCID[i+2], szCID[i+1])); SDCARD_DEBUG((" Product Name(PNM):%C%C%C%C%C\r\n", szCID[i+3], szCID[i+4], szCID[i+5], szCID[i+6], szCID[i+7])); SDCARD_DEBUG((" Product Revision:%02Xh\r\n", szCID[i+8])); SDCARD_DEBUG((" Serail Number(PSN):%02X%02X%02X%02Xh\r\n", szCID[i+9], szCID[i+10], szCID[i+11], szCID[i+12])); SDCARD_DEBUG((" Manufacturere Date Code(MDT):%01X%02Xh\r\n", szCID[i+13] & 0x0F, szCID[i+14])); SDCARD_DEBUG((" CRC-7 Checksum(CRC7):%02Xh\r\n", szCID[i+15] >> 1)); } bool SD_GetCSD(alt_u8 szCSD[], alt_u8 len){ if (!gbActive) return FALSE; if (len > 16) len = 16; memcpy(szCSD, &gszCSD[1], len); return TRUE; } bool SD_GetCID(alt_u8 szCID[], alt_u8 len){ if (!gbActive) return FALSE; if (len > 16) len = 16; memcpy(szCID, &gszCID[1], len); return TRUE; } //------------------------------------------------------------------------- bool SD_card_init(void) { alt_u8 x,y; // richard add: pull-high DAT3 to enter SD mode? SD_DAT3_OUT; SD_DAT3_HIGH; usleep(74*10); SD_CMD_OUT; SD_DAT_IN; SD_CLK_HIGH; SD_CMD_HIGH; SD_DAT_LOW; gbActive = FALSE; read_status=0; for(x=0;x<40;x++) Ncr(); for(x=0;x<5;x++) cmd_buffer[x]=cmd0[x]; y = send_cmd(cmd_buffer); SDCARD_DEBUG(("send cmd0\r\n")); do { // issue cmd55 & wait response for(x=0;x<40;x++); Ncc(); for(x=0;x<5;x++) cmd_buffer[x]=cmd55[x]; y = send_cmd(cmd_buffer); SDCARD_DEBUG(("send cmd55\r\n")); Ncr(); if(response_R(1)>1){ //response too long or crc error SDCARD_DEBUG(("response error for cmd55\r\n")); return FALSE; } Ncc(); // issue cmd41 & wait response for(x=0;x<5;x++) cmd_buffer[x]=acmd41[x]; y = send_cmd(cmd_buffer); SDCARD_DEBUG(("send acmd41\r\n")); Ncr(); } while(response_R(3)==1); // issue cmd2 & wait response Ncc(); for(x=0;x<5;x++) cmd_buffer[x]=cmd2[x]; y = send_cmd(cmd_buffer); SDCARD_DEBUG(("send cmd2\r\n")); Ncr(); if(response_R(2)>1) return FALSE; // issue cmd3 & wait response, finally get RCA Ncc(); for(x=0;x<5;x++) cmd_buffer[x]=cmd3[x]; y = send_cmd(cmd_buffer); Ncr(); if(response_R(6)>1) return FALSE; RCA[0]=response_buffer[1]; RCA[1]=response_buffer[2]; // above is Card Identification Mode //*************** now, wer are in Data Transfer Mode ********************************/ //### Standby-by state in Data-transfer mode // issue cmd9 with given RCA & wait response Ncc(); for(x=0;x<5;x++) cmd_buffer[x]=cmd9[x]; cmd_buffer[1] = RCA[0]; cmd_buffer[2] = RCA[1]; y = send_cmd(cmd_buffer); Ncr(); if(response_R(2)>1) return FALSE; memcpy(gszCSD,&response_buffer[0] , sizeof(gszCSD)); // richard add //DEBUG_SDCARD("\r\nCSD Hex:\r\n"); //DEBUG_SDCARD_HEX(gszCSD, sizeof(gszCSD)); //dump_CSD(gszCSD); // richard add Ncc(); for(x=0;x<5;x++) cmd_buffer[x]=cmd10[x]; cmd_buffer[1] = RCA[0]; cmd_buffer[2] = RCA[1]; y = send_cmd(cmd_buffer); Ncr(); if(response_R(2)>1) return FALSE; memcpy(gszCID,&response_buffer[0] , sizeof(gszCID)); // richard add //DEBUG_SDCARD("\r\nCID Hex:\r\n"); //DEBUG_SDCARD_HEX(gszCID, sizeof(gszCID)); //dump_CID(gszCID); // can issue cmd 4, 9, 10, in (stdandby state) // issue cmd9 with given RCA & wait response // richard: issue cmd7 enter transfer state Ncc(); for(x=0;x<5;x++) cmd_buffer[x]=cmd7[x]; cmd_buffer[1] = RCA[0]; cmd_buffer[2] = RCA[1]; y = send_cmd(cmd_buffer); Ncr(); if(response_R(1)>1) return FALSE; //### Transfer state in Data-transfer mode // issue cmd16 & wait response Ncc(); for(x=0;x<5;x++) cmd_buffer[x]=cmd16[x]; y = send_cmd(cmd_buffer); Ncr(); if(response_R(1)>1) return FALSE; SDCARD_DEBUG(("SD_card_init success\r\n")); read_status =1; //sd card ready gbActive = TRUE; return TRUE; } bool SD_read_block(alt_u32 block_number, alt_u8 *buff) { // buffer size muse be 512 byte alt_u8 c=0; alt_u32 i,addr; //j,addr; int try = 0; const int max_try = 500000; // 11/20/2007, richard 5000; // issue cmd17 for 'Single Block Read'. parameter: block address { Ncc(); addr = block_number * 512; cmd_buffer[0] = cmd17[0]; // CMD17: Read Single Block cmd_buffer[1] = (addr >> 24 ) & 0xFF; // MSB cmd_buffer[2] = (addr >> 16 ) & 0xFF; cmd_buffer[3] = (addr >> 8 ) & 0xFF; cmd_buffer[4] = addr & 0xFF; // LSB send_cmd(cmd_buffer); Ncr(); } // get response while(1) { SD_CLK_LOW; SD_CLK_HIGH; if(!(SD_TEST_DAT)) break; if (try++ > max_try){ SDCARD_DEBUG(("[SD] SD_read_block fail, reach max try %d", max_try)); return FALSE; } } // read data (512byte = 1 block) for(i=0;i<512;i++) { alt_u8 j; for(j=0;j<8;j++) { SD_CLK_LOW; SD_CLK_HIGH; c <<= 1; if(SD_TEST_DAT) c |= 0x01; } *buff=c; buff++; } // for(i=0; i<16; i++) { SD_CLK_LOW; SD_CLK_HIGH; } read_status = 1; //SD data next in return TRUE; } //------------------------------------------------------------------------- alt_u8 response_R(alt_u8 s) { alt_u8 a=0,b=0,c=0,r=0,crc=0; alt_u8 i,j=6,k; while(1) { SD_CLK_LOW; SD_CLK_HIGH; if(!(SD_TEST_CMD)) break; if(crc++ >100) return 2; } crc =0; if(s == 2) j = 17; for(k=0; k 0) //for crc culcar b = response_buffer[k-1]; for(i=0; i<8; i++) { SD_CLK_LOW; if(a > 0) c <<= 1; else i++; a++; SD_CLK_HIGH; if(SD_TEST_CMD) c |= 0x01; if(k > 0) { crc <<= 1; if((crc ^ b) & 0x80) crc ^= 0x09; b <<= 1; crc &= 0x7f; } } if(s==3) { if( k==1 &&(!(c&0x80))) r=1; } response_buffer[k] = c; } if(s==1 || s==6) { if(c != ((crc<<1)+1)) r=2; } return r; } //------------------------------------------------------------------------- alt_u8 send_cmd(alt_u8 *in) { int i,j; alt_u8 b,crc=0; SD_CMD_OUT; for(i=0; i < 5; i++) { b = in[i]; for(j=0; j<8; j++) { SD_CLK_LOW; if(b&0x80) SD_CMD_HIGH; else SD_CMD_LOW; crc <<= 1; SD_CLK_HIGH; if((crc ^ b) & 0x80) crc ^= 0x09; b<<=1; } crc &= 0x7f; } crc =((crc<<1)|0x01); b = crc; for(j=0; j<8; j++) { SD_CLK_LOW; if(crc&0x80) SD_CMD_HIGH; else SD_CMD_LOW; SD_CLK_HIGH; crc<<=1; } return b; }