unsigned char mmc_GoIdle() { unsigned char response=0x01; CS_LOW(); //Send Command 0 to put MMC in SPI mode mmcSendCmd(MMC_GO_IDLE_STATE,0,0x95); //Now wait for READY RESPONSE if((mmc_error = mmcGetResponse())!=0x01) { CS_HIGH(); return MMC_INIT_ERROR; } while(response==0x01) { CS_HIGH(); spiSendByte(0xff); CS_LOW(); mmcSendCmd(MMC_SEND_OP_COND,0x00,0xff); response=mmcGetResponse(); } CS_HIGH(); spiSendByte(0xff); return MMC_SUCCESS; }
// Reading the contents of the CSD and CID registers in SPI mode is a simple // read-block transaction. char mmcReadRegister (const char cmd_register, const unsigned char length, unsigned char *pBuffer) { char uc; char rvalue = MMC_TIMEOUT_ERROR; if (mmcSetBlockLength (length) == MMC_SUCCESS) { MMC_CS_LOW (); mmcSendCmd(cmd_register, 0x000000, 0xff); // CRC not used: 0xff as last byte if (mmcGetResponse() == 0x00) { // Wait for R1 response (0x00 = OK) if (mmcGetXXResponse(0xfe)== 0xfe) for (uc = 0; uc < length; uc++) pBuffer[uc] = spiSendByte(DUMMY_CHAR); // get CRC bytes (not really needed by us, but required by MMC) spiSendByte(DUMMY_CHAR); spiSendByte(DUMMY_CHAR); rvalue = MMC_SUCCESS; } else rvalue = MMC_RESPONSE_ERROR; MMC_CS_HIGH (); spiSendByte(DUMMY_CHAR); // Send 8 Clock pulses of delay. } MMC_CS_HIGH (); return rvalue; } // mmc_read_register
// Reading the contents of the CSD and CID registers in SPI mode is a simple // read-block transaction. unsigned char mmcReadRegister (const char cmd_register, const unsigned char length, unsigned char *pBuffer) { unsigned char uc = 0; unsigned char rvalue = MMC_TIMEOUT_ERROR; if (mmcSetBlockLength (length) == MMC_SUCCESS) { CS_LOW (); // CRC not used: 0xff as last byte mmcSendCmd(cmd_register, 0x000000, 0xff); // wait for response // in the R1 format (0x00 is no errors) if (mmcGetResponse() == 0x00) { if (mmcGetXXResponse(0xfe)== 0xfe) for (uc = 0; uc < length; uc++) pBuffer[uc] = spiSendByte(0xff); //mmc_buffer[uc] = spiSendByte(0xff); // get CRC bytes (not really needed by us, but required by MMC) spiSendByte(0xff); spiSendByte(0xff); rvalue = MMC_SUCCESS; } else rvalue = MMC_RESPONSE_ERROR; // CS = HIGH (off) CS_HIGH (); // Send 8 Clock pulses of delay. spiSendByte(0xff); } CS_HIGH (); return rvalue; } // mmc_read_register
// set blocklength 2^n char mmcSetBlockLength (const unsigned long blocklength) { char response; MMC_CS_LOW (); mmcSendCmd(MMC_SET_BLOCKLEN, blocklength, 0xFF); // Set the block length to read response=mmcGetResponse(); // Test response = 0x00 (R1 OK format) MMC_CS_HIGH (); spiSendByte(DUMMY_CHAR); // Send 8 Clock pulses of delay. return response; } // Set block_length
// set MMC in Idle mode char mmcGoIdle() { int i; char response = 0x01; //Send Command 0 to put MMC in SPI mode MMC_CS_LOW(); mmcSendCmd(MMC_GO_IDLE_STATE,0,0x95); //Now wait for READY RESPONSE if(mmcGetResponse()!=0x01){ MMC_CS_HIGH(); return MMC_INIT_ERROR; } // This timeout has been extended (transcend cards have i = 250-350 on init) for(i = 0; response == 0x01 && i<=1000; i++) { MMC_CS_HIGH(); spiSendByte(DUMMY_CHAR); MMC_CS_LOW(); mmcSendCmd(MMC_SEND_OP_COND,0x00,0xff); response = mmcGetResponse(); } MMC_CS_HIGH(); spiSendByte(DUMMY_CHAR); setUCB0Baud(MMC_DEF_BAUD, mmcID); switch(response){ case 0: return MMC_SUCCESS; case 1: return MMC_TIMEOUT_ERROR; default: return MMC_OTHER_ERROR; } }
//--------------- set blocklength 2^n ------------------------------------------------------ char mmcSetBlockLength (const unsigned long blocklength) { // char rValue = MMC_TIMEOUT_ERROR; // char i = 0; // SS = LOW (on) CS_LOW (); // Set the block length to read //MMC_SET_BLOCKLEN =CMD16 mmcSendCmd(MMC_SET_BLOCKLEN, blocklength, 0xFF); // get response from MMC - make sure that its 0x00 (R1 ok response format) if(mmcGetResponse()!=0x00) { initMMC(); mmcSendCmd(MMC_SET_BLOCKLEN, blocklength, 0xFF); mmcGetResponse(); } CS_HIGH (); // Send 8 Clock pulses of delay. spiSendByte(0xff); return MMC_SUCCESS; } // Set block_length
char mmcMountBlock(unsigned long address) { char rvalue = MMC_RESPONSE_ERROR; // Set the block length to read if (mmcSetBlockLength (512) == MMC_SUCCESS) // block length could be set { // SS = LOW (on) CS_LOW (); // send read command MMC_READ_SINGLE_BLOCK=CMD17 mmcSendCmd (MMC_READ_SINGLE_BLOCK, address, 0xFF); // Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command // it will do this by sending an affirmative response // in the R1 format (0x00 is no errors) if (mmcGetResponse() == 0x00) { // now look for the data token to signify the start of // the data if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN) { //success, data ready to read rvalue = MMC_SUCCESS; } else { // the data token was never received rvalue = MMC_DATA_TOKEN_ERROR; // 3 CS_HIGH (); spiSendByte(0xff); } } else { // the MMC never acknowledge the read command rvalue = MMC_RESPONSE_ERROR; // 2 CS_HIGH (); spiSendByte(0xff); } } else { rvalue = MMC_BLOCK_SET_ERROR; // 1 CS_HIGH (); spiSendByte(0xff); } return rvalue; }// mmc_read_block
// read a size Byte big block beginning at the address. char mmcReadBlock(const unsigned long address, const unsigned long count, unsigned char *pBuffer) { char rvalue = MMC_RESPONSE_ERROR; // Set the block length to read if (mmcSetBlockLength (count) == MMC_SUCCESS) { // Attempt to set block length MMC_CS_LOW (); // send read command MMC_READ_SINGLE_BLOCK=CMD17 mmcSendCmd (MMC_READ_SINGLE_BLOCK,address, 0xFF); // Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command // it will do this by sending an affirmative response // in the R1 format (0x00 is no errors) if (mmcGetResponse() == 0x00) { // Look for the data token to signify the start of data if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN) { // Clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block spiReadFrame(pBuffer, count); // Get CRC bytes (not really needed by us, but required by MMC) spiSendByte(DUMMY_CHAR); spiSendByte(DUMMY_CHAR); rvalue = MMC_SUCCESS; } else { // The data token was never received rvalue = MMC_DATA_TOKEN_ERROR; // 3 } } else { // The MMC never acknowledge the read command rvalue = MMC_RESPONSE_ERROR; // 2 } } else { // The block length was not set correctly rvalue = MMC_BLOCK_SET_ERROR; // 1 } MMC_CS_HIGH (); spiSendByte(DUMMY_CHAR); return rvalue; }// mmc_read_block
unsigned long mmcReadCardSize(void) { // Read contents of Card Specific Data (CSD) int timeout = 0; unsigned long MMC_CardSize; unsigned short i, // index j, // index b, // temporary variable response, // MMC response to command mmc_C_SIZE; unsigned char mmc_READ_BL_LEN, // Read block length mmc_C_SIZE_MULT; MMC_CS_LOW (); spiSendByte(MMC_READ_CSD); // CMD 9 for(i=4; i>0; i--) spiSendByte(0); // Send four dummy byte spiSendByte(DUMMY_CHAR); // Send CRC byte (why not just add one more byte above????) response = mmcGetResponse(); b = spiSendByte(DUMMY_CHAR); // data transmission always starts with 0xFE if(!response) { // Response != 0xFF while (b != 0xFE ){ b = spiSendByte(DUMMY_CHAR); if (timeout++ >= 150) return 0; } // bits 127:87 for(j=5; j>0; j--) // Host must keep the clock running for at ????? b = spiSendByte(DUMMY_CHAR); // 4 bits of READ_BL_LEN // bits 84:80 b =spiSendByte(DUMMY_CHAR); // lower 4 bits of CCC and mmc_READ_BL_LEN = b & 0x0F; b = spiSendByte(DUMMY_CHAR); // bits 73:62 C_Size // xxCC CCCC CCCC CC mmc_C_SIZE = (b & 0x03) << 10; b = spiSendByte(DUMMY_CHAR); mmc_C_SIZE += b << 2; b = spiSendByte(DUMMY_CHAR); mmc_C_SIZE += b >> 6; // bits 55:53 b = spiSendByte(DUMMY_CHAR); // bits 49:47 mmc_C_SIZE_MULT = (b & 0x03) << 1; b = spiSendByte(DUMMY_CHAR); mmc_C_SIZE_MULT += b >> 7; // bits 41:37 b = spiSendByte(DUMMY_CHAR); b = spiSendByte(DUMMY_CHAR); b = spiSendByte(DUMMY_CHAR); b = spiSendByte(DUMMY_CHAR); b = spiSendByte(DUMMY_CHAR); } for(j=4; j>0; j--) // Host must keep the clock running for at b = spiSendByte(DUMMY_CHAR); // least Ncr (max = 4 bytes) cycles after // the card response is received b = spiSendByte(DUMMY_CHAR); MMC_CS_LOW (); MMC_CardSize = (mmc_C_SIZE + 1); // power function with base 2 is better with a loop // i = (pow(2,mmc_C_SIZE_MULT+2)+0.5); for(i = 2,j=mmc_C_SIZE_MULT+2; j>1; j--) i <<= 1; MMC_CardSize *= i; // power function with base 2 is better with a loop //i = (pow(2,mmc_READ_BL_LEN)+0.5); for(i = 2,j=mmc_READ_BL_LEN; j>1; j--) i <<= 1; MMC_CardSize *= i; return (MMC_CardSize); }
unsigned char mmcReadBlock(const unsigned long address, const unsigned long count, unsigned char *pBuffer) { unsigned long i = 0; unsigned char rvalue = MMC_RESPONSE_ERROR; // Set the block length to read if (mmcSetBlockLength (count) == MMC_SUCCESS) // block length could be set { // SS = LOW (on) CS_LOW (); // send read command MMC_READ_SINGLE_BLOCK=CMD17 mmcSendCmd (MMC_READ_SINGLE_BLOCK,address, 0xFF); // Send 8 Clock pulses of delay, check if the MMC acknowledged the read block command // it will do this by sending an affirmative response // in the R1 format (0x00 is no errors) if (mmcGetResponse() == 0x00) { // now look for the data token to signify the start of // the data mmc_error = mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN); if (mmc_error == MMC_START_DATA_BLOCK_TOKEN) // if (mmcGetXXResponse(MMC_START_DATA_BLOCK_TOKEN) == MMC_START_DATA_BLOCK_TOKEN) { #ifndef withDMA // clock the actual data transfer and receive the bytes; spi_read automatically finds the Data Block for (i = 0; i < count; i++) pBuffer[i] = spiSendByte(0xff); // is executed with card inserted #else U1IFG &= ~(URXIFG1 + URXIFG1); /* clear flags */ /* Get the block */ /* DMA trigger is UART1 receive for both DMA0 and DMA1 */ DMACTL0 &= ~(DMA0TSEL_15 | DMA1TSEL_15); DMACTL0 |= (DMA0TSEL_9 | DMA1TSEL_9); /* Source DMA address: receive register. */ DMA0SA = U1RXBUF_; /* Destination DMA address: the user data buffer. */ DMA0DA = (unsigned short)pBuffer; /* The size of the block to be transferred */ DMA0SZ = count; /* Configure the DMA transfer*/ DMA0CTL = DMAIE | /* Enable interrupt */ DMADT_0 | /* Single transfer mode */ DMASBDB | /* Byte mode */ DMAEN | /* Enable DMA */ DMADSTINCR1 | DMADSTINCR0; /* Increment the destination address */ /* We depend on the DMA priorities here. Both triggers occur at the same time, since the source is identical. DMA0 is handled first, and retrieves the byte. DMA1 is triggered next, and sends the next byte. */ /* Source DMA address: constant 0xFF (don't increment)*/ DMA1SA = U1TXBUF_; /* Destination DMA address: the transmit buffer. */ DMA1DA = U1TXBUF_; /* Increment the destination address */ /* The size of the block to be transferred */ DMA1SZ = count-1; /* Configure the DMA transfer*/ DMA1CTL = DMADT_0 | /* Single transfer mode */ DMASBDB | /* Byte mode */ DMAEN; /* Enable DMA */ /* Kick off the transfer by sending the first byte */ U1TXBUF = 0xFF; // while (DMA0CTL & DMAEN) _NOP(); //LPM0; // wait till done // while (DMA0CTL & DMAEN) _EINT(); LPM0; // wait till done _EINT(); LPM0; // wait till done #endif // get CRC bytes (not really needed by us, but required by MMC) spiSendByte(0xff); spiSendByte(0xff); rvalue = MMC_SUCCESS; } else { // the data token was never received rvalue = MMC_DATA_TOKEN_ERROR; // 3 } } else { // the MMC never acknowledge the read command rvalue = MMC_RESPONSE_ERROR; // 2 } } else { rvalue = MMC_BLOCK_SET_ERROR; // 1 } CS_HIGH (); spiSendByte(0xff); return rvalue; }// mmc_read_block