54,7 → 54,8 |
// + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
// + POSSIBILITY OF SUCH DAMAGE. |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
#include <stdio.h> |
#include <string.h> |
#include "91x_lib.h" |
#include "uart.h" |
#include "sdc.h" |
128,76 → 129,300 |
// bit4-> erase sequence error |
// bit5-> address error |
// bit6-> parameter error |
// bit7-> allways zero |
// bit7-> allways zero */ |
#define R1_IDLE_STATE 0x01 |
#define R1_ERASE_RESET 0x02 |
#define R1_ILLEGAL_CMD 0x04 |
#define R1_COM_CRC_ERROR 0x08 |
#define R1_ERASE_SEQUENCE_ERROR 0x10 |
#define R1_ADDRESS_ERROR 0x20 |
#define R1_PARAMETER_ERROR 0x40 |
#define R1_BAD_RESPONSE 0x80 |
|
// Fomat for response type R1b |
// This response token is identical to the R1 format with the optional addition of the busy signal. |
// The busy signal token can be any number of bytes. A zero value indicates card is busy. |
// A non-zero value indicates the card is ready for the next command. |
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; |
|
// for more details see: |
// SD Specifications Part 1 |
// Physical Layer |
// Simplified Specification |
// Version 2.00 |
// September 25, 2006 |
// SD Group |
*/ |
typedef enum |
{ |
VER_1X, |
VER_20 |
} SDVersion_t; |
|
typedef struct |
{ |
u8 Valid; |
SDVersion_t Version; |
CID_t CID; |
} SDCardInfo_t; |
|
Result_t SDInitState = SD_ERROR_UNKNOWN; |
SDCardInfo_t SDCardInfo; |
|
u8 CMD[6]; // SD-SPI command buffer |
u8 RSP[6]; // SD-SPI response buffer |
|
Result_t SDC_Init(void) |
|
void PrintCID(CID_t *pCID) |
{ |
SerialPutString("SD init..."); |
u32 Timeout = 0; |
// initialized to CMD0 (GO_IDLE_STATE) |
u8 CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95}; |
u8 text[50]; |
u8 pn[6]; |
u8 temp1; |
u16 temp2; |
u16 temp3; |
sprintf(text, "Manufacturer ID: %i\r\n",pCID->MID); |
SerialPutString(text); |
memcpy(pn, pCID->OID, 2); |
pn[2] = '\0'; // terminate string |
sprintf(text, "Application ID: %s\r\n",pn); |
SerialPutString(text); |
memcpy(pn, pCID->PNM, 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); |
SerialPutString(text); |
temp2 = (u16)((pCID->PSN)/65536); |
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); |
SerialPutString(text); |
} |
|
SDInitState = SD_ERROR_UNKNOWN; |
SSC_Disable(); |
// at least 72 clock cycles with CS dectivated (logic high) to initiate a hardwar reset |
for (Timeout = 0; Timeout < 10; Timeout++) // 10*8 = 80 cycles |
|
u8 CRC7(u8 * cmd, u8 cnt) |
{ |
u8 i, a; |
u8 crc, Data; |
|
crc = 0; // init CRC buffer |
for (a = 0; a<cnt ;a++) // for every byte in the msg |
{ |
SSC_PutChar(0xff); |
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..."); |
u32 Timeout = 0; |
|
// Try to enable the SPI-Mode at the sd-card. |
// 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). |
while(SDC_PutCommand (CMD) != 0x01) |
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 |
for (Timeout = 0; Timeout < 15; Timeout++) // 15*8 = 120 cycles |
{ |
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) |
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[2] = 0x00; |
CMD[3] = 0x00; |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
Timeout = 0; |
while(SDC_PutCommand (CMD) != R1_IDLE_STATE) |
{ |
if (Timeout++ > 200) |
{ |
SerialPutString("reset timeout.\r\n"); |
SDInitState = SD_ERROR_RESET; |
return(SDInitState); |
return(SD_ERROR_RESET); |
} |
} |
|
Timeout = 0; |
// Sending CMD1 (SEND_OP_COND) to the sd-card. |
// (Sends host capacity support information and activates the card's initialization process.) |
// CMD1 is valid command for the Thin (1.4mm) Standard Size SD Memory Card |
// only if used after re-initializing a card (not after power on reset). |
CMD[0] = 0x41; // update command index |
CMD[5] = 0xFF; // and CRC7 checksum |
// Send CMD1 until response byte indicates end of idle state |
Timeout = SetDelay(200); // set timeout to 200 ms (large cards tend to longer) |
while( SDC_PutCommand (CMD) != 0x00) |
/* 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) |
{ |
SerialPutString("Bad CMD8 R1.\r\n"); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(RSP[0] & R1_ILLEGAL_CMD) |
{ |
//Ver1.X SD Memory Card or Not SD Memory Card |
SDCardInfo.Version = VER_1X; |
} |
else |
{ |
// Ver2.00 or later SD Memory Card |
// reading the remaining bytes of the R7 response |
SDCardInfo.Version = VER_20; |
for(Timeout = 1; Timeout < 5; Timeout++) |
{ |
RSP[Timeout] = SSC_GetChar(); |
} |
//check pattern |
if(RSP[4]!= 0xAA) |
{ |
SerialPutString("Bad CMD8 R7 check pattern.\r\n"); |
return(SD_ERROR_BAD_RESPONSE); |
} |
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); |
} |
} |
|
/* 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) |
{ |
SerialPutString("Bad CMD58 R1.\r\n"); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(RSP[0] & R1_ILLEGAL_CMD) |
{ |
SerialPutString("Not an SD-CARD.\r\n"); |
return(SD_ERROR_NO_SDCARD); |
} |
// read 4 bytes of OCR register |
for(Timeout = 1; Timeout < 5; Timeout++) |
{ |
RSP[Timeout] = SSC_GetChar(); |
} |
/* |
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 |
bit 20 -> 3.2 - 3.3 V |
bit 19 -> 3.1 - 3.2 V |
bit 18 -> 3.0 - 3.1 V |
bit 17 -> 2.9 - 3.0 V |
bit 16 -> 2.8 - 2.9 V |
bit 15 -> 2.7 - 2.8 V |
NavicCtrl uses 3.3 V, therefore check for bit 20 & 21 |
*/ |
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); |
} |
|
/* 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; |
do |
{ |
/* 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) |
{ |
SerialPutString("Bad CMD55 R1.\r\n"); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(RSP[0] == 0x00) 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"); |
return(SD_ERROR_BAD_RESPONSE); |
} |
if(CheckDelay(Timeout)) |
{ |
SerialPutString("initialize timeout.\r\n"); |
SDInitState = SD_ERROR_RESET; |
return(SDInitState); |
SerialPutString("Init timeout.\r\n"); |
return(SD_ERROR_INITIALIZE); |
} |
} while(RSP[0] & R1_IDLE_STATE); // loop until idle state |
|
if(RSP[0] != 0x00) |
{ |
SerialPutString("Init error.\r\n"); |
return(SD_ERROR_INITIALIZE); |
} |
|
// 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] != 0x00) |
{ |
SerialPutString("Error reading CID.\r\n"); |
return(SD_ERROR_READ_CID); |
} |
SSC_Disable(); |
SerialPutString("ok.\r\n"); |
SDInitState = SD_SUCCESS; // disable sdcard. |
return(SDInitState); |
u8 * pCID; |
pCID = (u8 *)&SDCardInfo.CID; |
for(Timeout = 0; Timeout < 16; Timeout++) |
{ |
pCID[Timeout] = SSC_GetChar(); |
} |
// read CRC16 of data block to waist |
SSC_GetChar(); |
SSC_GetChar(); |
|
SSC_Disable(); // disable sdcard. |
SDCardInfo.Valid = 1; |
SerialPutString("ok\r\n"); |
switch(SDCardInfo.Version) |
{ |
case VER_1X: |
SerialPutString("SD-CARD V1.x\r\n"); |
break; |
case VER_20: |
SerialPutString("SD-CARD V2.0 or later\r\n"); |
default: |
break; |
} |
PrintCID(&SDCardInfo.CID); |
return(SD_SUCCESS); |
} |
|
|
216,8 → 441,7 |
{ |
if(SD_SWITCH) // if sd-card is mechanically present |
{ |
BeepTime = 50; |
DebugOut.Analog[4]++; |
BeepTime = 100; |
SDC_Init(); // initialize sd-card. |
} |
WIU_ClearFlag(WIU_Line1); |
237,7 → 461,7 |
|
u8 SDC_PutCommand (u8 *CMD) |
{ |
u8 tmp = 0xff; |
u8 tmp = 0xFF; |
u16 Timeout = 0; |
u16 a; |
|
246,13 → 470,13 |
SSC_PutChar(0xFF); // Send 8 Clocks to the sdcard while card is not selected. Why that? |
SSC_Enable(); // enable chipselect. |
|
for (a = 0;a<0x06;a++) // send the command sequence to the sdcard (6 bytes) |
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. |
while (tmp == 0xFF) // wait for the response byte from sd-card. |
{ |
tmp = SSC_GetChar(); |
if (Timeout++ > 200) |
277,39 → 501,39 |
|
u8 SDC_PutSector(u32 addr,u8 *Buffer) |
{ |
u8 tmp; |
u8 CMD[] = {0x58,0x00,0x00,0x00,0x00,0xFF}; |
u8 tmp; |
u16 a; |
addr = addr << 9; // convert sectoradress to byteadress |
|
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 ); |
|
tmp = SDC_PutCommand (CMD); // send command to sdcard. |
if (tmp != 0) |
CMD[4] = 0x00; |
CMD[5] = CRC7(CMD, 5); // update checksum |
tmp = SDC_PutCommand (CMD); // send command to sdcard. |
if (tmp != 0x00) |
{ |
return(tmp); |
} |
SSC_ClearRxFifo(); |
for (a=0;a<100;a++) // wait until sdcard is ready |
for (a=0;a<100;a++) // wait until sdcard is ready |
{ |
SSC_GetChar(); |
} |
|
SSC_PutChar(0xFE); // 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. |
for (a=0;a<512;a++) // transmitt one sector (normaly 512bytes) of data to the sdcard. |
{ |
SSC_PutChar(*Buffer++); |
} |
|
SSC_PutChar(0xFF); // write two bytes of crc to the sdcard (not used in spi-mode) |
SSC_PutChar(0xFF); // write two bytes of crc to the sdcard (not used in spi-mode) |
SSC_PutChar(0xFF); |
SSC_ClearRxFifo(); |
while (SSC_GetChar() != 0xff){}; // wait untile the sdcard is ready. |
while (SSC_GetChar() != 0xFF){}; // wait until the sdcard is ready. |
|
SSC_Disable(); // disable sdcard. |
SSC_Disable(); // disable sdcard. |
|
return(0); |
} |
327,17 → 551,16 |
|
u8 SDC_GetSector(u32 addr,u8 *Buffer) |
{ |
u8 CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF}; |
|
addr = addr << 9; // convert sectoradress to byteadress. |
|
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 |
// sprintf(text,"\n\rGetSector: (%lu)", (u32)addr ); SerialPutString(text); |
|
SDC_GetBlock(CMD,Buffer,512); // read specified sector from sdcard. |
SDC_GetBlock(CMD,Buffer,512);// read specified sector from sdcard. |
|
return(0); |
} |
355,14 → 578,12 |
|
void SDC_GetBlock(u8 *CMD,u8 *Buffer,u16 Bytes) |
{ |
if (SDC_PutCommand (CMD) != 0) // Send command to the sdcard. |
if (SDC_PutCommand (CMD) != 0x00) // Send command to the sdcard. |
{ |
return; |
} |
SSC_ClearRxFifo(); |
// SerialPutString("\n\rWait."); |
while (SSC_GetChar() != 0xfe){}; // wait until the sdcard is ready to transmitt data. |
// SerialPutString("Ok."); |
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) |
{ |