UINT8 SD_SendCommand(UINT8 u8SDCommand,UINT8 u8SDResponse) { UINT8 u8Counter; volatile UINT8 u8Temp=0; /* Send Start byte */ WriteSPIByte(u8SDCommand); /* Send Argument */ for(u8Counter=0;u8Counter<4;u8Counter++) WriteSPIByte(gu8SD_Argument.bytes[u8Counter]); /* Send CRC */ WriteSPIByte(0x95); /* Response RHandler */ u8Counter=SD_WAIT_CYCLES; do { u8Temp=ReadSPIByte(); u8Counter--; }while((u8Temp != u8SDResponse) && u8Counter > 0); if(u8Counter) return(OK); else return(COMMAND_FAILS); }
/***************************************************************************** * * SD_SendCommand * * Description: Sends a command to the SD card and receives the response. * All data is sent MSB first, and MSb first. * NB: Does not handle SS signal. * * Input: u8SDCommand - The command to send with start bit (b7) clear * and transmission bit (b6) set. * u8SDResponse - The correct R1 response byte. * If 0x80 don't care what the response is so long as its a byte with b7 = 0. * * Response: Return OK (0x00) if a response is received, * COMMAND_FAILS (0x01) if not. * Response is stored in response[] with the number of response * bytes controlled by response_type. * *****************************************************************************/ UINT8 SD_SendCommand(UINT8 u8SDCommand, UINT8 u8SDResponse) { UINT8 u8Counter, CRC7; volatile UINT8 u8Temp = 0; loopUntilReady(); /* Send command byte */WriteSPIByte(u8SDCommand); /* Send Argument, MSB first. */ for (u8Counter = 0; u8Counter < 4; u8Counter++) WriteSPIByte(gu8SD_Argument.bytes[u8Counter]); /* Send CRC */ switch (u8SDCommand) { case (SD_CMD55 | 0x40): // CMD55 with zero argument CRC7 = 0x65; break; case (SD_CMD41 | 0x40): // ACMD41 with argument 0x40000000 CRC7 = 0x77; break; default: CRC7 = 0x95; } WriteSPIByte(CRC7); /* Response Handler */ u8Counter = SD_WAIT_CYCLES; // 10 byte reads if (u8SDResponse == 0x80) { /* Get any valid response - a byte with b7 clear */ do { u8Temp = ReadSPIByte(); // Transmit 0xFF u8Counter--; } while ((u8Temp & 0x80) && u8Counter > 0); } else { /* Get a response that matches u8SDResponse */ do { u8Temp = ReadSPIByte(); // Transmit 0xFF u8Counter--; } while ((u8Temp != u8SDResponse) && u8Counter > 0); } /* Save the response */ gu8SD_Response[0] = u8Temp; gu8SD_Response[1] = u8Counter; /* Set up return conditions */ if (u8Counter) return (OK); // 0x00 else return (COMMAND_FAILS); // 0x01 }
UINT8 SD_Init(void) { _SD_PRESENT=_IN; /* Check for SD */ if(SD_PRESENT) return(NO_SD_CARD); /* Initialize SPI Module */ InitSPI(); /* Start SD card Init */ SPI_SS=ENABLE; SD_CLKDelay(10); // Send 80 clocks SPI_SS=DISABLE; gu8SD_Argument.lword=0; SD_CLKDelay(8); /* IDLE Command */ SPI_SS=ENABLE; if(SD_SendCommand(SD_CMD0|0x40,SD_IDLE)) { SPI_SS=DISABLE; return(INIT_FAILS); } SPI_SS=DISABLE; (void)ReadSPIByte(); // Dummy SPI cycle /* Initialize SD Command */ SPI_SS=ENABLE; while(SD_SendCommand(SD_CMD1|0x40,SD_OK)) ; SPI_SS=DISABLE; (void)ReadSPIByte(); // Dummy SPI cycle /* Block Length */ SPI_SS=ENABLE; gu8SD_Argument.lword=SD_BLOCK_SIZE; if(SD_SendCommand(SD_CMD16|0x40,SD_OK)) { SPI_SS=DISABLE; return(INIT_FAILS); } SPI_SS=DISABLE; //HighSpeedSPI(); WriteSPIByte(0x00); WriteSPIByte(0x00); return(OK); }
UINT8 SD_Write_Block(UINT32 u16SD_Block,UINT8 *pu8DataPointer) { UINT16 u16Counter; UINT8 SD_response; SPI_SS=ENABLE; gu8SD_Argument.lword=u16SD_Block; gu8SD_Argument.lword=gu8SD_Argument.lword<< SD_BLOCK_SHIFT; if(SD_SendCommand(SD_CMD24|0x40,SD_OK)) { SPI_SS=DISABLE; return(WRITE_COMMAND_FAILS); } WriteSPIByte(0xFE); for(u16Counter=0;u16Counter<BLOCK_SIZE;u16Counter++) WriteSPIByte(*pu8DataPointer++); WriteSPIByte(0xFF); // checksum Bytes not needed WriteSPIByte(0xFF); /* Buggy, replaced with //-- for(u16Counter=0;u16Counter<BLOCK_SIZE;u16Counter++) ; if((ReadSPIByte() & 0x0F) != 0x05) { SPI_SS=DISABLE; return(WRITE_DATA_FAILS); } */ //-- SD_response=0xFF; // #001 created this variable while (SD_response==0xFF) SD_response=ReadSPIByte(); // #001 wait for SD response <> 0xFF if((SD_response & 0x0F) != 0x05) // #001 checks if response = 0101 = data accepted { SPI_SS=DISABLE; return(WRITE_DATA_FAILS); } //-- Thx to Celso Monteiro while(SPI_Receive_byte()==0x00) ; // Dummy SPI cycle SPI_SS=DISABLE; return(OK); }
/*************************************************************************************** * * *** SD_CBufferDataSectorWrite *** * * Description: Write a 512 bytes from the circular buffer as a data sector. * Assume: * - SD Card has been previously erased. * - Write a full sector at a time. * * Entry: void. * ****************************************************************************************/ void SD_CBufferDataSectorWrite(void) { UINT16 u16Counter; SPI_SS = ENABLE; gu8SD_Argument.lword = u32DataSector++; // Set WRITE_BLOCK command argument // to the current data segment gu8SD_Argument.lword = gu8SD_Argument.lword << SD_BLOCK_SHIFT; // Convert sector number to // byte address if (SD_SendCommand(SD_CMD24 | 0x40, SD_OK)) // WRITE_BLOCK command { SPI_SS = DISABLE; return; } WriteSPIByte(0xFE); // Start Block Token for (u16Counter = 0; u16Counter < BLOCK_SIZE; u16Counter++) // Write the block WriteSPIByte(FromCBuffer()); WriteSPIByte(0xFF); // checksum Bytes not needed WriteSPIByte(0xFF); // for(u16Counter=0;u16Counter<BLOCK_SIZE;u16Counter++); // if((ReadSPIByte() & 0x0F) != 0x05) // Read the status token. // Correct response is 0x05 // Foust p5. while ((SPI_Receive_byte() & 0x0F) != 0x05) ; // { // SPI_SS=DISABLE; // return; // } while (SPI_Receive_byte() == 0x00) ; // Wait while the card is busy SPI_SS = DISABLE; SD_CLKDelay(1); // 8 dummy clocks return; }
UINT8 SD_Write_Block(UINT32 u16SD_Block,UINT8 *pu8DataPointer) { UINT16 u16Counter; T32_8 gu8SD_Argument; /* Check for Write Protection */ if(SD_PROTECTED) return(WRITE_PROTECTED); SD_ENABLE; gu8SD_Argument.lword=u16SD_Block; gu8SD_Argument.lword=gu8SD_Argument.lword<< SD_BLOCK_SHIFT; if(SD_SendCommand(SD_CMD24|0x40,gu8SD_Argument,SD_OK)) { SD_DISABLE; return(WRITE_COMMAND_FAILS); } WriteSPIByte(SDhandle,0xFE); for(u16Counter=0;u16Counter<BLOCK_SIZE;u16Counter++) WriteSPIByte(SDhandle,*pu8DataPointer++); WriteSPIByte(SDhandle,0xFF); // checksum Bytes not needed WriteSPIByte(SDhandle,0xFF); for(u16Counter=0;u16Counter<BLOCK_SIZE;u16Counter++) ; if((ReadSPIByte(SDhandle) & 0x0F) != 0x05) { SD_DISABLE; return(WRITE_DATA_FAILS); } while(ReadSPIByte(SDhandle)==0x00) ; // Dummy SPI cycle SD_DISABLE; return(OK); }
/***************************************************************************** * **************SD_Write_Block************ * * Description: Write a 512 byte sector (block) to the SD card. * * Inputs: u16SD_Block - the sector (block) number where the block is * to be written. * pu8DataPointer - the 512 byte buffer that is to be written * to the SD card. * *****************************************************************************/ UINT8 SD_Write_Block(UINT32 u16SD_Block, UINT8 *pu8DataPointer) { UINT16 u16Counter; SPI_SS = ENABLE; gu8SD_Argument.lword = u16SD_Block; // Set WRITE_BLOCK command argument gu8SD_Argument.lword = gu8SD_Argument.lword << SD_BLOCK_SHIFT; // Convert sector number to // byte address if (SD_SendCommand(SD_CMD24 | 0x40, SD_OK)) // WRITE_BLOCK command { SPI_SS = DISABLE; return (WRITE_COMMAND_FAILS); } WriteSPIByte(0xFE); // Start Block Token for (u16Counter = 0; u16Counter < BLOCK_SIZE; u16Counter++) // Write the block WriteSPIByte(*pu8DataPointer++); WriteSPIByte(0xFF); // checksum Bytes not needed WriteSPIByte(0xFF); for (u16Counter = 0; u16Counter < BLOCK_SIZE; u16Counter++) ; if ((ReadSPIByte() & 0x0F) != 0x05) // Read the status token. // Correct response is 0x05 // Foust p5. { SPI_SS = DISABLE; return (WRITE_DATA_FAILS); } while (SPI_Receive_byte() == 0x00) ; // Wait while the card is busy SPI_SS = DISABLE; SD_CLKDelay(1); // 8 dummy clocks return (OK); }
void SD_CLKDelay(UINT8 u8Frames) { while(u8Frames--) WriteSPIByte(0xFF); }
/***************************************************************************** * * SD_SendCommandR3 * * Description: Sends a command to the SD card that requires an R3 (5 byte) response. * Used by SEND_IF_COND (CMD58) to read the OCR. * * Input: u8SDCommand - the command. * u8SDResponse - The correct R1 response for this command. * u8CRC7 - the CRC7 + end bit for the command (with Tx bit set) * and argument. * The 4 byte argument "gu8SD_Argument" must be set before * calling this function. * * Response: OK (0x00) if valid R3 response received else COMMAND_FAILS (0x01). * The R1 response is available in gu8SD_Response[0]. * The 32 bit Operation Conditions Register (OCR) is available in * gu8SD_Response[1-4] with MSB in gu8SD_Response[1]. * *****************************************************************************/ UINT8 SD_SendCommandR3(UINT8 u8SDCommand, UINT8 u8SDResponse, UINT8 u8CRC7) { UINT8 u8Counter, mlCounter, i; volatile UINT8 u8Temp = 0; loopUntilReady(); /* Debug checks */ for (i = 0; i <= 4; i++) { // Initialise gu8SD_Response[] so you can be sure its changed gu8SD_Response[i] = 0xAA; } /* Main loop - Send the command and wait for a valid response */ mlCounter = 5; // loop max of 5 times do { mlCounter--; /* Send command byte with set transmission bit (b6) set */WriteSPIByte( u8SDCommand | 0x40); /* Send Argument */ for (u8Counter = 0; u8Counter < 4; u8Counter++) { i = gu8SD_Argument.bytes[u8Counter]; WriteSPIByte(gu8SD_Argument.bytes[u8Counter]); } /* Send CRC */WriteSPIByte(u8CRC7); /* Response Handler. Do up to SD_WAIT_CYCLES card reads looking for a valid response. Valid response is 5 bytes which are stored in gu8SD_Response[]. Valid response is received MSB first. The five bytes are: - gu8SD_Response[0]; MSB is a normal R1 response which is SD_IDLE (0x01). - gu8SD_Response[1-4]; is the argument that was transmitted. The card responds with 0xFF until it transmits the valid response. */ u8Counter = SD_WAIT_CYCLES; // Do up to SD_WAIT_CYCLES card reads /* Response loop - Do up to SD_WAIT_CYCLES card reads looking for a valid response */ do // Look for a R1 response byte { u8Temp = ReadSPIByte(); // Transmit 0xFF. MOSI line must be kept high u8Counter--; } while ((u8Temp != u8SDResponse) && u8Counter > 0); // Response loop test // } while((u8Temp & 0xC0) && u8Counter > 0); // Response loop test // - exit on valid response or timeout } while ((u8Temp != u8SDResponse) && mlCounter > 0); // Main loop test // } while((u8Temp & 0xC0) && mlCounter > 0); // Main loop test // - exit on valid response or timeout /* Place the 5 byte response in gu8SD_Response[] */ gu8SD_Response[0] = u8Temp; // R1 for (i = 1; i <= 4; i++) { // OCR gu8SD_Response[i] = ReadSPIByte(); } /* Set up return condition */ if (gu8SD_Response[0] == u8SDResponse) return (OK); // 0x00 else return (COMMAND_FAILS); // 0x01 }
UINT8 SD_Init(void) { T32_8 gu8SD_Argument; SD_PRESENT_INIT; SD_PROTECTED_INIT; /* Check for SD */ if(SD_PRESENT) { return(NO_SD_CARD); } /* Initialize SPI Module */ SD_DISABLE;/*First init*/ /**********************FSL: SPI start-up*******************************/ //if SPIhandle NULL, serial cannot be used!!! SDhandle = xSPIinit((eSPIPort)SD_CARD_SPI_PORT/*BSP being used*/, spi300,/*300KHz baudrate*/ serIDLEslow, serMiddleSample, serMaster, serInterrupt, SPI_SDCARD_BUFFER_LIMIT/*defined at header file*/); /* Start SD card Init */ SD_ENABLE; SD_CLKDelay(10); // Send 80 clocks SD_DISABLE; gu8SD_Argument.lword=0; SD_CLKDelay(8); /* IDLE Command */ SD_ENABLE; if(SD_SendCommand(SD_CMD0|0x40,gu8SD_Argument,SD_IDLE)) { SD_DISABLE; return(INIT_FAILS); } SD_DISABLE; (void)ReadSPIByte(SDhandle); // Dummy SPI cycle /* Initialize SD Command */ SD_ENABLE; while(SD_SendCommand(SD_CMD1|0x40,gu8SD_Argument,SD_OK)) ; SD_DISABLE; (void)ReadSPIByte(SDhandle); // Dummy SPI cycle /* Block Length */ SD_ENABLE; gu8SD_Argument.lword=SD_BLOCK_SIZE; if(SD_SendCommand(SD_CMD16|0x40,gu8SD_Argument,SD_OK)) { SD_DISABLE; return(INIT_FAILS); } SD_DISABLE; xSPIChangeToPolling(SDhandle); HighSpeedSPI(SD_CARD_SPI_PORT); WriteSPIByte(SDhandle,0x00); WriteSPIByte(SDhandle,0x00); return(OK); }