73,11 → 73,10 |
// Description: Source files for connecting to an sd-card using the SSC |
// |
//........................................................................................................................................ |
// Functions: u8 SDC_init(void); |
// u8 SDC_PutCommand (u8 *CMD); |
// u8 SDC_PutSector(u32 addr,u8 *Buffer); |
// u8 SDC_GetSector(u32 addr,u8 *Buffer); |
// void SDC_GetBlock(u8 *CMD,u8 *Buffer,u16 Bytes); |
// Functions: SD_Result_t SDC_init(void); |
// u8 SDC_PutCommand (u8 *CMD); |
// SD_Result_t SDC_PutSector(u32 addr,u8 *Buffer); |
// SD_Result_t SDC_GetSector(u32 addr,u8 *Buffer); |
// |
////........................................................................................................................................ |
// ext. functions: extern void SSC_Init(void); |
93,17 → 92,6 |
//________________________________________________________________________________________________________________________________________ |
|
|
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_Init(void); |
// |
// Description: This function initialises the SDCard to spi-mode. |
// |
// |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
|
/* SD-Command Format |
// All SD-commands have a fixed code length of 48 bits (6 bytes) |
// ______________________________________________________________________________ |
130,6 → 118,7 |
// 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 |
139,6 → 128,9 |
#define R1_PARAMETER_ERROR 0x40 |
#define R1_BAD_RESPONSE 0x80 |
|
#define DATA_START_TOKEN 0xFE |
#define DATA_RESPONSE_OK 0x05 |
|
typedef struct |
{ |
u8 MID; // Manufacturer ID |
161,19 → 153,115 |
u8 Valid; |
SDVersion_t Version; |
CID_t CID; |
} SDCardInfo_t; |
} __attribute__((packed)) SDCardInfo_t; |
|
SDCardInfo_t SDCardInfo; |
volatile SDCardInfo_t SDCardInfo; |
|
u8 CMD[6]; // SD-SPI command buffer |
u8 RSP[6]; // SD-SPI response buffer |
|
|
void PrintCID(CID_t *pCID) |
/* 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; |
u8 crc, Data; |
|
crc = 0; // init CRC buffer |
for (a = 0; a < len ;a++) // for every byte in the msg |
{ |
Data = cmd[a]; |
for (i=0;i<8;i++) // for every bit in the byte |
{ |
crc <<= 1; // shift crc |
if ((Data & 0x80)^(crc & 0x80)) crc ^=0x09; //xor |
Data <<= 1; // shift data for next bit |
} |
} |
crc = (crc<<1)|1; // set terminating bit to 1 |
return(crc); |
} |
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_PutCommand(* CMD); |
// |
// Description: This function send a command frame the SDCard in spi-mode. |
// |
// |
// Returnvalue: the function returns the first response byte |
//________________________________________________________________________________________________________________________________________ |
|
u8 SDC_PutCommand (u8 const *CMD) |
{ |
u8 rsp = 0xFF; |
u16 Timeout = 0; |
u16 a; |
|
SSC_ClearRxFifo(); // clear the rx fifo |
SSC_Enable(); // enable chipselect. |
|
for (a = 0;a < 6; a++) // send the command sequence to the sdcard (6 bytes) |
{ |
SSC_PutChar(*CMD++); |
} |
|
SSC_ClearRxFifo(); // clear the rx fifo to discard the bytes received during the transmission of the 6 command bytes |
do |
{ |
rsp = SSC_GetChar(); // get byte from sd-card |
if (Timeout++ > 2000) return(rsp); |
}while(rsp == 0xFF); // wait for the response byte from sd-card. |
return(rsp); |
} |
|
void PrintCID(CID_t * pCID) |
{ |
u8 text[50]; |
u8 pn[6]; |
u8 temp1; |
u16 temp2; |
u16 temp3; |
sprintf(text, "Manufacturer ID: %i\r\n",pCID->MID); |
192,45 → 280,38 |
temp3 = (u16)((pCID->PSN)%65536); // ?? |
sprintf(text, "Serial Num.: %i%i\r\n", temp2, temp3); |
SerialPutString(text); |
temp1 = (u8)((pCID->MDT) & 0xF); // month ?? |
temp2 = ((pCID->MDT)&0x0FF0)/16 + 2000; // year ?? |
sprintf(text, "Manufac. Date: %i/%i\r\n",temp1, temp2); |
temp3 = ((pCID->MDT)>>8); // month |
temp2 = ((pCID->MDT)&0x000F) + 2000; // year |
sprintf(text, "Manufac. Date: %i/%i\r\n",temp3, temp2); |
SerialPutString(text); |
} |
|
|
u8 CRC7(u8 * cmd, u8 cnt) |
{ |
u8 i, a; |
u8 crc, Data; |
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_Init(void); |
// |
// Description: This function initialises the SDCard to spi-mode. |
// |
// |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
|
crc = 0; // init CRC buffer |
for (a = 0; a<cnt ;a++) // for every byte in the msg |
{ |
Data = cmd[a]; |
for (i=0;i<8;i++) // for every bit in the byte |
{ |
crc <<= 1; // shift crc |
if ((Data & 0x80)^(crc & 0x80)) crc ^=0x09; //xor |
Data <<= 1; // shift data for next bit |
} |
} |
crc=(crc<<1)|1; // set terminating bit to 1 |
return(crc); |
} |
|
|
|
SD_Result_t SDC_Init(void) |
{ |
SerialPutString("SD init..."); |
SerialPutString("SDC init..."); |
u32 Timeout = 0; |
u8 text[50]; |
u8 CMD[6]; // SD-SPI command buffer |
u8 RSP[6]; // SD-SPI response buffer |
|
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 |
mode, CS shall be held to high during 74 clock cycles. */ |
SSC_Disable(); // set SD_CS high |
SSC_ClearRxFifo(); // clear the rx fifo |
for (Timeout = 0; Timeout < 15; Timeout++) // 15*8 = 120 cycles |
{ |
SSC_PutChar(0xFF); |
239,7 → 320,7 |
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 (3bytes) |
CMD[1] = 0x00; // set cmd argument (4bytes) |
CMD[2] = 0x00; |
CMD[3] = 0x00; |
CMD[4] = 0x00; |
254,6 → 335,23 |
} |
} |
|
/* 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) |
{ |
sprintf(text,"Bad CMD59 R1=%02X.\r\n", RSP[0]); |
SerialPutString(text); |
return(SD_ERROR_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 |
265,7 → 363,8 |
// answer to CMD8 is an R7 response (R1 + 4 bytes) |
if(RSP[0] & R1_BAD_RESPONSE) |
{ |
SerialPutString("Bad CMD8 R1.\r\n"); |
sprintf(text,"Bad CMD8 R1=%02X.\r\n", RSP[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(RSP[0] & R1_ILLEGAL_CMD) |
307,7 → 406,8 |
// answer to CMD58 is an R3 response (R1+ 4Byte OCR) |
if(RSP[0] & R1_BAD_RESPONSE) |
{ |
SerialPutString("Bad CMD58 R1.\r\n"); |
sprintf(text,"Bad CMD58 R1 %02x.\r\n", RSP[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(RSP[0] & R1_ILLEGAL_CMD) |
356,19 → 456,21 |
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 |
RSP[0] = SDC_PutCommand(CMD); // send the command |
if(RSP[0] & R1_BAD_RESPONSE) |
{ |
SerialPutString("Bad CMD55 R1.\r\n"); |
{ |
sprintf(text,"Bad CMD55 R1=%02X.\r\n", RSP[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(RSP[0] == 0x00) break; // not in idle state |
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) |
{ |
SerialPutString("Bad ACMD41 R1.\r\n"); |
sprintf(text,"Bad ACMD41 R1=%02X.\r\n", RSP[0]); |
SerialPutString(text); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(CheckDelay(Timeout)) |
378,7 → 480,7 |
} |
} while(RSP[0] & R1_IDLE_STATE); // loop until idle state |
|
if(RSP[0] != 0x00) |
if(RSP[0] != R1_NO_ERROR) |
{ |
SerialPutString("Init error.\r\n"); |
return(SD_ERROR_INITIALIZE); |
393,7 → 495,7 |
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] != 0x00) |
if(RSP[0] != R1_NO_ERROR) |
{ |
SerialPutString("Error reading CID.\r\n"); |
return(SD_ERROR_READ_CID); |
421,7 → 523,7 |
default: |
break; |
} |
PrintCID(&SDCardInfo.CID); |
PrintCID((CID_t *)&SDCardInfo.CID); |
return(SD_SUCCESS); |
} |
|
451,58 → 553,20 |
} |
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_PutCommand(* CMD); |
// |
// Description: This function initialises the SDCard to spi-mode. |
// |
// |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
|
u8 SDC_PutCommand (u8 *CMD) |
{ |
u8 tmp = 0xFF; |
u16 Timeout = 0; |
u16 a; |
|
SSC_ClearRxFifo(); // clear the rx fifo |
SSC_Disable(); // disable chipselect |
SSC_PutChar(0xFF); // Send 8 Clocks to the sdcard while card is not selected. Why that? |
SSC_Enable(); // enable chipselect. |
|
for (a = 0;a < 6; a++) // send the command sequence to the sdcard (6 bytes) |
{ |
SSC_PutChar(*CMD++); |
} |
|
SSC_ClearRxFifo(); // clear the rx fifo to discard the bytes received during the transmission of the 6 command bytes |
while (tmp == 0xFF) // wait for the response byte from sd-card. |
{ |
tmp = SSC_GetChar(); |
if (Timeout++ > 200) |
{ |
break; // or timeout. |
} |
} |
return(tmp); |
} |
|
|
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_PutSector(void); |
// |
// Description: This function writes one sector of data to the SSC |
// |
// |
// Returnvalue: none |
// Returnvalue: SD_Result_t |
//________________________________________________________________________________________________________________________________________ |
|
u8 SDC_PutSector(u32 addr,u8 *Buffer) |
SD_Result_t SDC_PutSector(u32 addr, const u8 *Buffer) |
{ |
u8 tmp; |
u16 a; |
u8 rsp; |
u16 a, Crc16; |
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 ); |
510,10 → 574,10 |
CMD[3] = ((addr & 0x0000FF00) >>8 ); |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
tmp = SDC_PutCommand (CMD); // send command to sdcard. |
if (tmp != 0x00) |
rsp = SDC_PutCommand (CMD); // send command to sdcard. |
if (rsp != R1_NO_ERROR) |
{ |
return(tmp); |
return(SD_ERROR_BAD_RESPONSE); |
} |
SSC_ClearRxFifo(); |
for (a=0;a<100;a++) // wait until sdcard is ready |
520,26 → 584,24 |
{ |
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(0xFE); // send start of header to the SSC |
|
for (a=0;a<512;a++) // transmitt one sector (normaly 512bytes) of data to the sdcard. |
{ |
SSC_PutChar(*Buffer++); |
SSC_PutChar(Buffer[a]); |
} |
|
SSC_PutChar(0xFF); // write two bytes of crc to the sdcard (not used in spi-mode) |
SSC_PutChar(0xFF); |
SSC_PutChar((u8)(Crc16>>8)); // write two bytes of crc to the sdcard |
SSC_PutChar((u8)(0x00FF&Crc16)); |
SSC_ClearRxFifo(); |
while (SSC_GetChar() != 0xFF){}; // wait until the sdcard is ready. |
|
while ((rsp = SSC_GetChar()) != 0xFF){}; // wait until the sdcard is ready. |
SSC_Disable(); // disable sdcard. |
|
return(0); |
if( (0x1F & rsp) != DATA_RESPONSE_OK) return(SD_ERROR_WRITE_DATA); |
else return(SD_SUCCESS); |
} |
|
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_GetSector(u32 addr,u8 *Buffer); |
// |
546,11 → 608,17 |
// Description: This function reads one sector of data from the SSC |
// |
// |
// Returnvalue: none |
// Returnvalue: SD_Result_t |
//________________________________________________________________________________________________________________________________________ |
|
u8 SDC_GetSector(u32 addr,u8 *Buffer) |
{ |
SD_Result_t SDC_GetSector(u32 addr,u8 *Buffer) |
{ |
u8 rsp; |
u32 Timeout; |
u16 Crc16; |
u16 a; |
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 ); |
558,41 → 626,30 |
CMD[3] = ((addr & 0x0000FF00) >>8 ); |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
// sprintf(text,"\n\rGetSector: (%lu)", (u32)addr ); SerialPutString(text); |
|
SDC_GetBlock(CMD,Buffer,512);// read specified sector from sdcard. |
|
return(0); |
} |
|
|
|
//________________________________________________________________________________________________________________________________________ |
// Funtion: SDC_GetBlock(void); |
// |
// Description: This function reads one block of data of int bytes from the SSC. |
// |
// |
// Returnvalue: the function returns 0 if the initialisation was successfull otherwise the function returns an errorcode. |
//________________________________________________________________________________________________________________________________________ |
|
void SDC_GetBlock(u8 *CMD,u8 *Buffer,u16 Bytes) |
{ |
if (SDC_PutCommand (CMD) != 0x00) // Send command to the sdcard. |
rsp = SDC_PutCommand (CMD); // Send command to the sdcard. |
if (rsp != R1_NO_ERROR) |
{ |
return; |
return(SD_ERROR_BAD_RESPONSE); |
} |
SSC_ClearRxFifo(); |
while (SSC_GetChar() != 0xFE){}; // wait until the sdcard is ready to transmitt data. |
u16 a; |
for (a=0;a<Bytes;a++) // read the block from the SSC (normaly 512Bytes) |
SSC_ClearRxFifo(); |
Timeout = SetDelay(200); // wait alt least 0.2 seconds for data ready |
do |
{ |
*Buffer++ = SSC_GetChar(); |
rsp = SSC_GetChar(); |
if((rsp & 0xF0) == 0x00) return(SD_ERROR_READ_DATA); |
if(CheckDelay(Timeout)) return(SD_ERROR_TIMEOUT); |
}while(rsp != DATA_START_TOKEN); |
|
for (a=0;a < 512;a++) // read the block from the SSC (normaly 512Bytes) |
{ |
Buffer[a] = SSC_GetChar(); |
} |
|
SSC_GetChar(); // Read two bytes CRC- checksum (not used in spi-mode) |
SSC_GetChar(); |
SSC_Disable(); // disable sdcard. |
// 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); |
} |
|
|