62,19 → 62,20 |
#include "ssc.h" |
#include "timer.h" |
#include "main.h" |
#include "crc16.h" |
|
|
//________________________________________________________________________________________________________________________________________ |
// Module name: mmc.c |
// Module name: sdc.c |
// Compiler used: avr-gcc 3.4.5 |
// Last Modifikation: 24.07.2007 |
// Version: 1.05 |
// Authors: Stephan Busker |
// Last Modifikation: 08.06.2008 |
// Version: 1.06 |
// Authors: Stephan Busker, Gregor Stobrawa |
// Description: Source files for connecting to an sd-card using the SSC |
// |
//........................................................................................................................................ |
// Functions: SD_Result_t SDC_init(void); |
// u8 SDC_PutCommand (u8 *CMD); |
// u8 SDC_PutCommand (u8 *cmd); |
// SD_Result_t SDC_PutSector(u32 addr,u8 *Buffer); |
// SD_Result_t SDC_GetSector(u32 addr,u8 *Buffer); |
// |
118,10 → 119,11 |
// bit5-> address error |
// bit6-> parameter error |
// bit7-> allways zero */ |
|
#define R1_NO_ERROR 0x00 |
#define R1_IDLE_STATE 0x01 |
#define R1_ERASE_RESET 0x02 |
#define R1_ILLEGAL_CMD 0x04 |
#define R1_ILLEGAL_cmd 0x04 |
#define R1_COM_CRC_ERROR 0x08 |
#define R1_ERASE_SEQUENCE_ERROR 0x10 |
#define R1_ADDRESS_ERROR 0x20 |
129,21 → 131,15 |
#define R1_BAD_RESPONSE 0x80 |
|
#define DATA_START_TOKEN 0xFE |
#define DATA_RESPONSE_MASK 0x1F |
#define DATA_RESPONSE_OK 0x05 |
#define DATA_RESPONSE_CRC_ERROR 0x0B |
#define DATA_RESPONSE_WRITE_ERROR 0x1D |
|
typedef struct |
{ |
u8 MID; // Manufacturer ID |
u8 OID[2]; // OEM/Application ID |
u8 PNM[5]; // Product name |
u8 PRV; // Product revision |
u32 PSN; // Product serial number |
u16 MDT; // Manufacturing date |
u8 CRC7; // CRC7 checksum |
} __attribute__((packed)) CID_t; |
|
typedef enum |
{ |
VER_UNKNOWN, |
VER_1X, |
VER_20 |
} SDVersion_t; |
151,61 → 147,25 |
typedef struct |
{ |
u8 Valid; |
SDVersion_t Version; |
CID_t CID; |
SDVersion_t Version; // HW-Version |
u32 Capacity; // Memory capacity in bytes |
u8 CID[16]; // CID register |
u8 CSD[16]; // CSD register |
} __attribute__((packed)) SDCardInfo_t; |
|
volatile SDCardInfo_t SDCardInfo; |
|
|
//________________________________________________________________________________________________________________________________________ |
// Function: CRC7(u8* cmd, u32 len); |
// |
// Description: This function calculated the CRC7 checksum used in the last byte of a spi command frame. |
// |
// |
// Returnvalue: the function returns the crc7 |
//________________________________________________________________________________________________________________________________________ |
|
/* CRC16 implementation acording to CCITT standards */ |
static const u16 crc16tab[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 |
}; |
|
u16 CRC16(const u8 *pBuffer, u32 len) |
{ |
register u32 counter; |
register u16 crc = 0; |
for( counter = 0; counter < len; counter++) |
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *pBuffer++)&0x00FF]; |
return crc; |
} |
|
|
u8 CRC7(u8 * cmd, u32 len) |
{ |
u8 i, a; |
227,7 → 187,7 |
} |
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_PutCommand(* CMD); |
// Function: SDC_PutCommand(* cmd); |
// |
// Description: This function send a command frame the SDCard in spi-mode. |
// |
235,7 → 195,7 |
// Returnvalue: the function returns the first response byte |
//________________________________________________________________________________________________________________________________________ |
|
u8 SDC_PutCommand (u8 const *CMD) |
u8 SDC_PutCommand (u8 const *cmd) |
{ |
u8 rsp = 0xFF; |
u16 Timeout = 0; |
246,7 → 206,7 |
|
for (a = 0;a < 6; a++) // send the command sequence to the sdcard (6 bytes) |
{ |
SSC_PutChar(*CMD++); |
SSC_PutChar(*cmd++); |
} |
|
SSC_ClearRxFifo(); // clear the rx fifo to discard the bytes received during the transmission of the 6 command bytes |
258,36 → 218,152 |
return(rsp); |
} |
|
void PrintCID(CID_t * pCID) |
|
|
//________________________________________________________________________________________________________________________________________ |
// Function: SDC_GetData(u8 * cmd ,u8 *Buffer, u32 len); |
// |
// Description: This function sneds cmd an reads a datablock of len from the sd-card |
// |
// |
// Returnvalue: SD_Result_t |
//________________________________________________________________________________________________________________________________________ |
|
SD_Result_t SDC_GetData(const u8 * cmd, u8 *Buffer, u32 len) |
{ |
u8 rsp; |
u32 Timeout; |
u16 a, Crc16; |
SD_Result_t result = SD_ERROR_UNKNOWN; |
|
// send the command |
rsp = SDC_PutCommand (cmd); // Send command to the sdcard. |
if (rsp != R1_NO_ERROR) |
{ |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
SSC_ClearRxFifo(); |
Timeout = SetDelay(200); // wait alt least 0.2 seconds for data ready |
do |
{ |
rsp = SSC_GetChar(); |
if((rsp & 0xF0) == 0x00) // data error token |
{ |
result = SD_ERROR_READ_DATA; |
goto end; |
} |
if(CheckDelay(Timeout)) |
{ |
result = SD_ERROR_TIMEOUT; |
goto end; |
} |
}while(rsp != DATA_START_TOKEN); |
// data start token received |
for (a = 0; a < len; a++) // read the block from the SSC |
{ |
Buffer[a] = SSC_GetChar(); |
} |
// Read two bytes CRC16-Data checksum |
Crc16 = SSC_GetChar(); |
Crc16 = (Crc16<<8)|SSC_GetChar(); |
if(Crc16 != CRC16(Buffer, 512)) result = SD_ERROR_CRC_DATA; |
else result = SD_SUCCESS; |
|
end: |
SSC_Disable(); // disable sdcard. |
return(result); |
} |
|
|
//________________________________________________________________________________________________________________________________________ |
// Function: SDC_PrintCID(u8 * pCID); |
// |
// Description: This function prints the CIS register in a human readable format. |
// |
// |
// Returnvalue: the function returns nothing |
//________________________________________________________________________________________________________________________________________ |
|
void SDC_PrintCID(u8 * pCID) |
{ |
u8 text[50]; |
u8 pn[6]; |
u16 temp2; |
u16 temp3; |
sprintf(text, "Manufacturer ID: %i\r\n",pCID->MID); |
u16 temp1, temp2; |
|
sprintf(text, "\r\nManufacturer ID: %i\r\n", pCID[0]); |
SerialPutString(text); |
memcpy(pn, pCID->OID, 2); |
memcpy(pn, &pCID[1], 2); |
pn[2] = '\0'; // terminate string |
sprintf(text, "Application ID: %s\r\n",pn); |
SerialPutString(text); |
memcpy(pn, pCID->PNM, 5); |
memcpy(pn, &pCID[3], 5); |
pn[5] = '\0'; // terminate string |
sprintf(text, "Product Name: %s\r\n",pn); |
SerialPutString(text); |
sprintf(text, "Product Rev.: %i.%i\r\n",(pCID->PRV)>>4, (pCID->PRV)&0xF); |
sprintf(text, "Product Rev.: %i.%i\r\n",pCID[8]>>4, pCID[8]&0xF); |
SerialPutString(text); |
temp2 = (u16)((pCID->PSN)/65536); |
temp3 = (u16)((pCID->PSN)%65536); // ?? |
sprintf(text, "Serial Num.: %i%i\r\n", temp2, temp3); |
SerialPutString("Serial No.: "); |
for(temp1 = 0; temp1<4; temp1++) |
{ |
sprintf(text,"%02X", pCID[9+temp1]); |
SerialPutString(text); |
} |
SerialPutString("\r\n"); |
temp1 = pCID[14] & 0x0F; // month |
temp2 = ((pCID[14]>>4)|(pCID[13]<<4)) + 2000; // year |
sprintf(text, "Manufac. Date: %i/%i\r\n\r\n",temp1, temp2); |
SerialPutString(text); |
temp3 = ((pCID->MDT)>>8); // month |
temp2 = ((pCID->MDT)&0x000F) + 2000; // year |
sprintf(text, "Manufac. Date: %i/%i\r\n",temp3, temp2); |
SerialPutString(text); |
} |
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_GetCID(u8 * pCID); |
// |
// Description: This function reads the CIS register form the sd card in spi mode. |
// |
// |
// Returnvalue: the function returns error state |
//________________________________________________________________________________________________________________________________________ |
|
SD_Result_t SDC_GetCID(u8 * pCID) |
{ |
u8 cmd[6]; |
|
/* Send cmd10 (SEND_CID) */; |
cmd[0] = 0x40|10; // set command index 58 |
cmd[1] = 0x00; // set cmd argument |
cmd[2] = 0x00; |
cmd[3] = 0x00; |
cmd[4] = 0x00; |
cmd[5] = CRC7(cmd, 5); // update checksum |
return SDC_GetData(cmd, pCID, 16); |
} |
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_GetCSD(u8 * pCSD); |
// |
// Description: This function reads the CSD register form the sd card in spi mode. |
// |
// |
// Returnvalue: the function returns error state |
//________________________________________________________________________________________________________________________________________ |
|
SD_Result_t SDC_GetCSD(u8 * pCSD) |
{ |
u8 cmd[6]; |
|
/* Send cmd09 (SEND_CSD) */; |
cmd[0] = 0x40|9; // set command index 58 |
cmd[1] = 0x00; // set cmd argument |
cmd[2] = 0x00; |
cmd[3] = 0x00; |
cmd[4] = 0x00; |
cmd[5] = CRC7(cmd, 5); // update checksum |
return SDC_GetData(cmd, pCSD, 16); |
} |
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_Init(void); |
// |
// Description: This function initialises the SDCard to spi-mode. |
301,14 → 377,15 |
SerialPutString("SDC init..."); |
u32 Timeout = 0; |
u8 text[50]; |
u8 CMD[6]; // SD-SPI command buffer |
u8 RSP[6]; // SD-SPI response buffer |
|
u8 cmd[6]; // SD-SPI command buffer |
u8 rsp[6]; // SD-SPI response buffer |
SD_Result_t result = SD_ERROR_UNKNOWN; |
|
SSC_Init(); |
|
SDCardInfo.Valid = 0; |
/* The host shall supply power to the card so that the voltage is reached to Vdd_min within 250ms and |
start to supply at least 74 SD clocks to the SD card with keeping CMD line to high. In case of SPI |
start to supply at least 74 SD clocks to the SD card with keeping cmd line to high. In case of SPI |
mode, CS shall be held to high during 74 clock cycles. */ |
SSC_Disable(); // set SD_CS high |
SSC_ClearRxFifo(); // clear the rx fifo |
316,60 → 393,63 |
{ |
SSC_PutChar(0xFF); |
} |
/* In case of SPI host, CMD0 shall be the first command to send the card to SPI mode. |
Send CMD0 (GO_IDLE_STATE) to the sd-card when CS-SD is activated (lowactive) |
/* In case of SPI host, cmd0 shall be the first command to send the card to SPI mode. |
Send cmd0 (GO_IDLE_STATE) to the sd-card when CS-SD is activated (lowactive) |
until the response byte indicates no error and in idle state (0x01).*/ |
CMD[0] = 0x40|0; // set command index 0 |
CMD[1] = 0x00; // set cmd argument (4bytes) |
CMD[2] = 0x00; |
CMD[3] = 0x00; |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
cmd[0] = 0x40|0; // set command index 0 |
cmd[1] = 0x00; // set cmd argument (4bytes) |
cmd[2] = 0x00; |
cmd[3] = 0x00; |
cmd[4] = 0x00; |
cmd[5] = CRC7(cmd, 5); // update checksum |
Timeout = 0; |
while(SDC_PutCommand (CMD) != R1_IDLE_STATE) |
while(SDC_PutCommand (cmd) != R1_IDLE_STATE) |
{ |
if (Timeout++ > 200) |
{ |
SerialPutString("reset timeout.\r\n"); |
return(SD_ERROR_RESET); |
result = SD_ERROR_RESET; |
goto end; |
} |
} |
|
/* In case of SPI mode the checksum feature is disabled by default. |
CMD59 can be used to contol the checksum feature. |
Send CMD59 (CRC_ON_OFF) to the sd-card to enable CRC feature.*/ |
CMD[0] = 0x40|59; // set command index 0 |
CMD[1] = 0x00; // set cmd argument (4bytes) |
CMD[2] = 0x00; |
CMD[3] = 0x00; |
CMD[4] = 0x01; // enable CRC |
CMD[5] = CRC7(CMD, 5); // update checksum |
RSP[0] = SDC_PutCommand(CMD); |
if ( RSP[0] != R1_IDLE_STATE) |
cmd59 can be used to contol the checksum feature. |
Send cmd59 (CRC_ON_OFF) to the sd-card to enable CRC feature.*/ |
cmd[0] = 0x40|59; // set command index 0 |
cmd[1] = 0x00; // set cmd argument (4bytes) |
cmd[2] = 0x00; |
cmd[3] = 0x00; |
cmd[4] = 0x01; // enable CRC |
cmd[5] = CRC7(cmd, 5); // update checksum |
rsp[0] = SDC_PutCommand(cmd); |
if ( rsp[0] != R1_IDLE_STATE) |
{ |
sprintf(text,"Bad CMD59 R1=%02X.\r\n", RSP[0]); |
sprintf(text,"Bad cmd59 R1=%02X.\r\n", rsp[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
|
/* Send CMD8 (SEND_IF_COND). The CRC for that command is allways enabled */ |
CMD[0] = 0x40|8; // set command index 8 |
CMD[1] = 0x00; // set cmd argument |
CMD[2] = 0x00; |
CMD[3] = 0x01; // 2.7-3.6V Range |
CMD[4] = 0xAA; // check pattern |
CMD[5] = CRC7(CMD, 5); // update checksum |
RSP[0] = SDC_PutCommand(CMD); //send cmd and get first response byte |
// answer to CMD8 is an R7 response (R1 + 4 bytes) |
if(RSP[0] & R1_BAD_RESPONSE) |
/* Send cmd8 (SEND_IF_COND). The CRC for that command is allways enabled */ |
cmd[0] = 0x40|8; // set command index 8 |
cmd[1] = 0x00; // set cmd argument |
cmd[2] = 0x00; |
cmd[3] = 0x01; // 2.7-3.6V Range |
cmd[4] = 0xAA; // check pattern |
cmd[5] = CRC7(cmd, 5); // update checksum |
rsp[0] = SDC_PutCommand(cmd); //send cmd and get first response byte |
// answer to cmd8 is an R7 response (R1 + 4 bytes) |
if(rsp[0] & R1_BAD_RESPONSE) |
{ |
sprintf(text,"Bad CMD8 R1=%02X.\r\n", RSP[0]); |
sprintf(text,"Bad cmd8 R1=%02X.\r\n", rsp[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
if(RSP[0] & R1_ILLEGAL_CMD) |
if(rsp[0] & R1_ILLEGAL_cmd) |
{ |
//Ver1.X SD Memory Card or Not SD Memory Card |
//Ver1.X SD Memory Card or not a SD Memory Card |
SDCardInfo.Version = VER_1X; |
} |
else |
379,52 → 459,56 |
SDCardInfo.Version = VER_20; |
for(Timeout = 1; Timeout < 5; Timeout++) |
{ |
RSP[Timeout] = SSC_GetChar(); |
rsp[Timeout] = SSC_GetChar(); |
} |
//check pattern |
if(RSP[4]!= 0xAA) |
if(rsp[4]!= 0xAA) |
{ |
SerialPutString("Bad CMD8 R7 check pattern.\r\n"); |
return(SD_ERROR_BAD_RESPONSE); |
SerialPutString("Bad cmd8 R7 check pattern.\r\n"); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
if ( (RSP[3] & 0x0F)!= 0x01 ) // voltage range is not 2.7-3.6V |
if ( (rsp[3] & 0x0F)!= 0x01 ) // voltage range is not 2.7-3.6V |
{ |
|
SerialPutString("Card is incompatible to 3.3V.\r\n"); |
return(SD_ERROR_BAD_VOLTAGE_RANGE); |
result = SD_ERROR_BAD_VOLTAGE_RANGE; |
goto end; |
} |
} |
|
/* Send CMD58 (READ_OCR) */ |
CMD[0] = 0x40|58; // set command index 58 |
CMD[1] = 0x00; // set cmd argument |
CMD[2] = 0x00; |
CMD[3] = 0x00; |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
RSP[0] = SDC_PutCommand(CMD); //send cmd and get first response byte |
// answer to CMD58 is an R3 response (R1+ 4Byte OCR) |
if(RSP[0] & R1_BAD_RESPONSE) |
/* Send cmd58 (READ_OCR) */ |
cmd[0] = 0x40|58; // set command index 58 |
cmd[1] = 0x00; // set cmd argument |
cmd[2] = 0x00; |
cmd[3] = 0x00; |
cmd[4] = 0x00; |
cmd[5] = CRC7(cmd, 5); // update checksum |
rsp[0] = SDC_PutCommand(cmd); //send cmd and get first response byte |
// answer to cmd58 is an R3 response (R1+ 4Byte OCR) |
if(rsp[0] & R1_BAD_RESPONSE) |
{ |
sprintf(text,"Bad CMD58 R1 %02x.\r\n", RSP[0]); |
sprintf(text,"Bad cmd58 R1 %02x.\r\n", rsp[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
if(RSP[0] & R1_ILLEGAL_CMD) |
if(rsp[0] & R1_ILLEGAL_cmd) |
{ |
SerialPutString("Not an SD-CARD.\r\n"); |
return(SD_ERROR_NO_SDCARD); |
result = SD_ERROR_NO_SDCARD; |
goto end; |
} |
// read 4 bytes of OCR register |
for(Timeout = 1; Timeout < 5; Timeout++) |
{ |
RSP[Timeout] = SSC_GetChar(); |
rsp[Timeout] = SSC_GetChar(); |
} |
/* |
RSP[1] bits 31-24 |
RSP[2] bits 23-16 |
RSP[3] bits 15-08 |
RSP[4] bits 07-00 |
rsp[1] bits 31-24 |
rsp[2] bits 23-16 |
rsp[3] bits 15-08 |
rsp[4] bits 07-00 |
bit 23 -> 3.5 - 3.6 V |
bit 22 -> 3.4 - 3.5 V |
bit 21 -> 3.3 - 3.4 V |
436,83 → 520,124 |
bit 15 -> 2.7 - 2.8 V |
NavicCtrl uses 3.3 V, therefore check for bit 20 & 21 |
*/ |
if((RSP[2] & 0x30) != 0x30) |
if((rsp[2] & 0x30) != 0x30) |
{ |
// supply voltage is not supported by sd-card |
SerialPutString("Card is incompatible to 3.3V.\r\n"); |
return(SD_ERROR_BAD_VOLTAGE_RANGE); |
result = SD_ERROR_BAD_VOLTAGE_RANGE; |
goto end; |
} |
|
/* Initialize the sd-card sending continously ACMD41 (SD_SEND_OP_COND) |
/* Initialize the sd-card sending continously Acmd41 (SD_SEND_OP_COND) |
until the R1 response byte is 0x00 indicating no error and not in idle state */ |
Timeout = SetDelay(2000); // set timeout to 2000 ms (large cards tend to longer) |
CMD[1] = 0x00; // set cmd argument |
CMD[2] = 0x00; |
CMD[3] = 0x00; |
CMD[4] = 0x00; |
cmd[1] = 0x00; // set cmd argument |
cmd[2] = 0x00; |
cmd[3] = 0x00; |
cmd[4] = 0x00; |
do |
{ |
/* First send the CMD55 that defines to the card that the next command |
/* First send the cmd55 that defines to the card that the next command |
is an application specific command rather than a standard command */ |
CMD[0] = 0x40|55; // CMD55 (APP_CMD) |
CMD[5] = CRC7(CMD, 5); // update checksum |
RSP[0] = SDC_PutCommand(CMD); // send the command |
if(RSP[0] & R1_BAD_RESPONSE) |
cmd[0] = 0x40|55; // cmd55 (APP_cmd) |
cmd[5] = CRC7(cmd, 5); // update checksum |
rsp[0] = SDC_PutCommand(cmd); // send the command |
if(rsp[0] & R1_BAD_RESPONSE) |
{ |
sprintf(text,"Bad CMD55 R1=%02X.\r\n", RSP[0]); |
sprintf(text,"Bad cmd55 R1=%02X.\r\n", rsp[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
if(RSP[0] == R1_NO_ERROR) break; // not in idle state |
CMD[0] = 0x40|41; // ACMD41 (SD_SEND_OP_COND) |
CMD[5] = CRC7(CMD, 5); // update checksum |
RSP[0] = SDC_PutCommand (CMD); // send the command |
if(RSP[0] & R1_BAD_RESPONSE) |
if(rsp[0] == R1_NO_ERROR) break; // not in idle state |
cmd[0] = 0x40|41; // Acmd41 (SD_SEND_OP_COND) |
cmd[5] = CRC7(cmd, 5); // update checksum |
rsp[0] = SDC_PutCommand (cmd); // send the command |
if(rsp[0] & R1_BAD_RESPONSE) |
{ |
sprintf(text,"Bad ACMD41 R1=%02X.\r\n", RSP[0]); |
sprintf(text,"Bad Acmd41 R1=%02X.\r\n", rsp[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
if(CheckDelay(Timeout)) |
{ |
SerialPutString("Init timeout.\r\n"); |
return(SD_ERROR_INITIALIZE); |
result = SD_ERROR_INITIALIZE; |
goto end; |
} |
} while(RSP[0] & R1_IDLE_STATE); // loop until idle state |
} while(rsp[0] & R1_IDLE_STATE); // loop until idle state |
|
if(RSP[0] != R1_NO_ERROR) |
if(rsp[0] != R1_NO_ERROR) |
{ |
SerialPutString("Init error.\r\n"); |
return(SD_ERROR_INITIALIZE); |
result = SD_ERROR_INITIALIZE; |
goto end; |
} |
|
// read CID register |
/* Send CMD10 (READ_CID) */; |
CMD[0] = 0x40|10; // set command index 58 |
CMD[1] = 0x00; // set cmd argument |
CMD[2] = 0x00; |
CMD[3] = 0x00; |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
RSP[0] = SDC_PutCommand(CMD); //send cmd and get first response byte |
if(RSP[0] != R1_NO_ERROR) |
result = SDC_GetCID((u8 *)&SDCardInfo.CID); |
if(result != SD_SUCCESS) |
{ |
SerialPutString("Error reading CID.\r\n"); |
return(SD_ERROR_READ_CID); |
goto end; |
} |
u8 * pCID; |
pCID = (u8 *)&SDCardInfo.CID; |
for(Timeout = 0; Timeout < 16; Timeout++) |
|
// read CSD register |
result = SDC_GetCSD((u8 *)&SDCardInfo.CSD); |
if(result != SD_SUCCESS) |
{ |
pCID[Timeout] = SSC_GetChar(); |
SerialPutString("Error reading CSD.\r\n"); |
goto end; |
} |
// read CRC16 of data block to waist |
SSC_GetChar(); |
SSC_GetChar(); |
|
SSC_Disable(); // disable sdcard. |
SDCardInfo.Valid = 1; |
SerialPutString("ok\r\n"); |
|
u8 c_size_mult, read_bl_len; |
u32 c_size; |
|
switch(SDCardInfo.CSD[0]>>6) // check CSD Version |
{ |
case 0x00: // if CSD is V1.0 structure (2GB limit) |
|
/* |
memory capacity = BLOCKNR * BLOCK_LEN |
BLOCKNR = (C_SIZE+1) * MULT |
MULT = 2^(C_SIZE_MULT+2) |
BLOCK_LEN = 2^READ_BL_LEN |
|
C_SIZE is 12 bits [73:62] in CSD register |
C_SIZE_MULT is 3 bits [49:47] in CSD register |
READ_BL_LEN is 4 bits [83:80] in CSD register |
*/ |
|
read_bl_len = (SDCardInfo.CSD[5] & 0x0F); //CSD[05] -> [87:80] |
c_size = ((u32)(SDCardInfo.CSD[6] & 0x03))<<10; //CSD[06] -> [79:72] |
c_size |= ((u32)SDCardInfo.CSD[7])<<2; //CSD[07] -> [71:64] |
c_size |= (u32)(SDCardInfo.CSD[8]>>6); //CSD[08] -> [63:56] |
c_size_mult = (SDCardInfo.CSD[9] & 0x03)<<1; //CSD[09] -> [55:48] |
c_size_mult |=(SDCardInfo.CSD[10] & 0x80)>>7; //CSD[10] -> [47:40] |
SDCardInfo.Capacity = (u32)(c_size+1)*(1L<<(c_size_mult+2))*(1L<<read_bl_len); |
break; |
|
case 0x01: // if CSD is V2.0 structure (HC SD-Card > 2GB) |
|
/* |
memory capacity = (C_SIZE+1) * 512K byte |
C_SIZE is 22 bits [69:48] in CSR register |
*/ |
|
c_size = ((u32)(SDCardInfo.CSD[7] & 0x3F))<<16; //CSD[07] -> [71:64] |
c_size |= ((u32)SDCardInfo.CSD[8])<<8; //CSD[08] -> [63:56] |
c_size |= (u32)SDCardInfo.CSD[9]; //CSD[09] -> [55:48]; |
SDCardInfo.Capacity = (c_size + 1)* 512L * 1024L; |
break; |
|
default: //unknown CSD Version |
SDCardInfo.Capacity = 0; |
break; |
} |
|
switch(SDCardInfo.Version) |
{ |
case VER_1X: |
523,35 → 648,43 |
default: |
break; |
} |
PrintCID((CID_t *)&SDCardInfo.CID); |
return(SD_SUCCESS); |
u16 mb_size = (u16)(SDCardInfo.Capacity/(1024L*1024L)); |
sprintf(text, "Capacity = %i MB\r\n", mb_size); |
SerialPutString(text); |
|
SDC_PrintCID((u8 *)&SDCardInfo.CID); |
SDCardInfo.Valid = 1; |
|
// jump point for error condition before |
end: |
SSC_Disable(); |
return(result); |
} |
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: EXTIT1_IRQHandler(void); |
// Funtion: SDC_Deinit(void); |
// |
// Description: This function handles the extnernal interrupts from port 5.3 (SD_SWITCH) |
// Description: This function deinitialises the SDCard interface. |
// |
// |
// Returnvalue: none |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
void EXTIT1_IRQHandler(void) |
|
SD_Result_t SDC_Deinit(void) |
{ |
VIC_ITCmd(EXTIT1_ITLine, DISABLE); |
if(WIU_GetITStatus(WIU_Line11) != RESET) |
{ |
if(SD_SWITCH) // if sd-card is mechanically present |
{ |
BeepTime = 100; |
SDC_Init(); // initialize sd-card. |
} |
WIU_ClearFlag(WIU_Line1); |
WIU_ClearITPendingBit(WIU_Line11); |
} |
VIC_ITCmd(EXTIT1_ITLine, ENABLE); |
SerialPutString("SDC deinit..."); |
SSC_Deinit(); |
|
SDCardInfo.Valid = 0; |
SDCardInfo.Capacity = 0; |
SDCardInfo.Version = VER_UNKNOWN; |
|
SerialPutString("ok\r\n"); |
return(SD_SUCCESS); |
} |
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_PutSector(void); |
// |
565,40 → 698,79 |
{ |
u8 rsp; |
u16 a, Crc16; |
u8 CMD[6]; // SD-SPI command buffer |
u32 Timeout = 0; |
SD_Result_t result = SD_ERROR_UNKNOWN; |
u8 cmd[6]; // SD-SPI command buffer |
|
addr = addr << 9; // convert sectoradress to byteadress |
CMD[0] = 0x40|24; // set CMD24 (WRITE_BLOCK) |
CMD[1] = ((addr & 0xFF000000) >>24 ); |
CMD[2] = ((addr & 0x00FF0000) >>16 ); |
CMD[3] = ((addr & 0x0000FF00) >>8 ); |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
rsp = SDC_PutCommand (CMD); // send command to sdcard. |
cmd[0] = 0x40|24; // set cmd24 (WRITE_BLOCK) |
cmd[1] = ((addr & 0xFF000000) >>24 ); |
cmd[2] = ((addr & 0x00FF0000) >>16 ); |
cmd[3] = ((addr & 0x0000FF00) >>8 ); |
cmd[4] = 0x00; |
cmd[5] = CRC7(cmd, 5); // update checksum |
rsp = SDC_PutCommand (cmd); // send command to sdcard. |
if (rsp != R1_NO_ERROR) |
{ |
return(SD_ERROR_BAD_RESPONSE); |
result = SD_ERROR_BAD_RESPONSE; |
goto end; |
} |
SSC_ClearRxFifo(); |
for (a=0;a<100;a++) // wait until sdcard is ready |
for (a=0;a<10;a++) // at least one byte |
{ |
SSC_GetChar(); |
} |
Crc16 = CRC16(Buffer, 512); // calc checksum for data block |
SSC_PutChar(DATA_START_TOKEN); // send start of header to the SSC |
SSC_PutChar(DATA_START_TOKEN); // send data start of header to the SSC |
|
for (a=0;a<512;a++) // transmitt one sector (normaly 512bytes) of data to the sdcard. |
for (a=0;a<512;a++) // transmit one sector (normaly 512bytes) of data to the sdcard. |
{ |
SSC_PutChar(Buffer[a]); |
} |
|
SSC_PutChar((u8)(Crc16>>8)); // write two bytes of crc to the sdcard |
SSC_PutChar((u8)(Crc16>>8)); // write two bytes of crc16 to the sdcard |
SSC_PutChar((u8)(0x00FF&Crc16)); |
SSC_ClearRxFifo(); |
while ((rsp = SSC_GetChar()) != 0xFF){}; // wait until the sdcard is ready. |
Timeout = SetDelay(200); |
do // wait for data response token |
{ |
rsp = SSC_GetChar(); |
if(CheckDelay(Timeout)) |
{ |
result = SD_ERROR_TIMEOUT; |
goto end; |
} |
}while((rsp & 0x11) != 0x01 ); |
// analyse data response token |
switch(rsp & DATA_RESPONSE_MASK) |
{ |
case DATA_RESPONSE_OK: |
result = SD_SUCCESS; |
break; |
case DATA_RESPONSE_CRC_ERROR: |
result = SD_ERROR_CRC_DATA; |
break; |
case DATA_RESPONSE_WRITE_ERROR: |
result = SD_ERROR_WRITE_DATA; |
break; |
default: |
result = SD_ERROR_UNKNOWN; |
break; |
|
} |
// wait until the sdcard is not busy. |
Timeout = SetDelay(200); |
while (SSC_GetChar() != 0xFF) |
{ |
if(CheckDelay(Timeout)) |
{ |
result = SD_ERROR_TIMEOUT; |
goto end; |
} |
} |
end: |
SSC_Disable(); // disable sdcard. |
if( (0x1F & rsp) != DATA_RESPONSE_OK) return(SD_ERROR_WRITE_DATA); |
else return(SD_SUCCESS); |
return(result); |
} |
|
|
613,44 → 785,42 |
|
SD_Result_t SDC_GetSector(u32 addr,u8 *Buffer) |
{ |
u8 rsp; |
u32 Timeout; |
u16 Crc16; |
u16 a; |
u8 CMD[6]; // SD-SPI command buffer |
u8 cmd[6]; // SD-SPI command buffer |
|
addr = addr << 9; // convert sectoradress to byteadress. |
CMD[0] = 0x40|17; // set CMD17 (READ_SINGLE_BLOCK) |
CMD[1] = ((addr & 0xFF000000) >>24 ); |
CMD[2] = ((addr & 0x00FF0000) >>16 ); |
CMD[3] = ((addr & 0x0000FF00) >>8 ); |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
rsp = SDC_PutCommand (CMD); // Send command to the sdcard. |
if (rsp != R1_NO_ERROR) |
{ |
return(SD_ERROR_BAD_RESPONSE); |
} |
SSC_ClearRxFifo(); |
Timeout = SetDelay(200); // wait alt least 0.2 seconds for data ready |
do |
{ |
rsp = SSC_GetChar(); |
if((rsp & 0xF0) == 0x00) return(SD_ERROR_READ_DATA); |
if(CheckDelay(Timeout)) return(SD_ERROR_TIMEOUT); |
}while(rsp != DATA_START_TOKEN); |
cmd[0] = 0x40|17; // set cmd17 (READ_SINGLE_BLOCK) |
cmd[1] = ((addr & 0xFF000000) >>24 ); |
cmd[2] = ((addr & 0x00FF0000) >>16 ); |
cmd[3] = ((addr & 0x0000FF00) >>8 ); |
cmd[4] = 0x00; |
cmd[5] = CRC7(cmd, 5); // update checksum |
|
for (a=0;a < 512;a++) // read the block from the SSC (normaly 512Bytes) |
return SDC_GetData(cmd, Buffer, 512); |
} |
|
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: EXTIT1_IRQHandler(void); |
// |
// Description: This function handles the extnernal interrupts from port 5.3 (SD_SWITCH) |
// |
// |
// Returnvalue: none |
//________________________________________________________________________________________________________________________________________ |
void EXTIT1_IRQHandler(void) |
{ |
VIC_ITCmd(EXTIT1_ITLine, DISABLE); |
if(WIU_GetITStatus(WIU_Line11) != RESET) |
{ |
Buffer[a] = SSC_GetChar(); |
if(SD_SWITCH) // if sd-card is mechanically present |
{ |
BeepTime = 100; |
SDC_Init(); // initialize sd-card. |
} |
WIU_ClearFlag(WIU_Line1); |
WIU_ClearITPendingBit(WIU_Line11); |
} |
// Read two bytes CRC16-Data checksum |
Crc16 = SSC_GetChar(); |
Crc16 = (Crc16<<8)|SSC_GetChar(); |
SSC_Disable(); // disable sdcard. |
if(Crc16 != CRC16(Buffer, 512)) return(SD_ERROR_CRC_DATA); |
else return(SD_SUCCESS); |
VIC_ITCmd(EXTIT1_ITLine, ENABLE); |
} |
|
|
|