Subversion Repositories NaviCtrl

Compare Revisions

Ignore whitespace Rev 8 → Rev 9

/branches/V0.1 killagreg/sdc.c
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)
{
/branches/V0.1 killagreg/sdc.h
11,14 → 11,17
 
typedef enum
{
SD_SUCCESS,
SD_SUCCESS = 0,
SD_ERROR_RESET,
SD_ERROR_INITIALIZE,
SD_ERROR_BAD_RESPONSE,
SD_ERROR_BAD_VOLTAGE_RANGE,
SD_ERROR_NO_SDCARD,
SD_ERROR_READ_CID,
SD_ERROR_UNKNOWN
} Result_t;
} SD_Result_t;
 
extern Result_t SDInitState;
extern Result_t SDC_Init(void);
extern SD_Result_t SDC_Init(void);
extern u8 SDC_GetSector (u32,u8 *);
extern u8 SDC_PutSector (u32,u8 *);
extern u8 SDC_PutCommand (u8 *);