//****************************************************************** //Function : to send a command to SD card //Arguments : unsigned char (8-bit command value) // & unsigned long (32-bit command argument) //return : unsigned char; response byte //****************************************************************** static unsigned char SD_sendCommand(unsigned char cmd, unsigned long arg) { unsigned char response, retry=0, status; //SD card accepts byte address while SDHC accepts block address in multiples of 512 //so, if it's SD card we need to convert block address into corresponding byte address by //multiplying it with 512. which is equivalent to shifting it left 9 times //following 'if' loop does that if(SDHC_flag == 0) if(cmd == READ_SINGLE_BLOCK || cmd == WRITE_SINGLE_BLOCK || cmd == ERASE_BLOCK_START_ADDR|| cmd == ERASE_BLOCK_END_ADDR ) { arg = arg << 9; } SD_CS_ASSERT; SpiTransmit(cmd | 0x40); //send command, first two bits always '01' SpiTransmit(arg>>24); SpiTransmit(arg>>16); SpiTransmit(arg>>8); SpiTransmit(arg); if(cmd == SEND_IF_COND) //it is compulsory to send correct CRC for CMD8 (CRC=0x87) & CMD0 (CRC=0x95) SpiTransmit(0x87); //for remaining commands, CRC is ignored in SPI mode else SpiTransmit(0x95); while((response = SpiReceive()) == 0xff) //wait response if(retry++ > 0xfe) break; //time out error if(response == 0x00 && cmd == 58) //checking response of CMD58 { status = SpiReceive() & 0x40; //first byte of the OCR register (bit 31:24) if(status == 0x40) SDHC_flag = 1; //we need it to verify SDHC card else SDHC_flag = 0; SpiReceive(); //remaining 3 bytes of the OCR register are ignored here SpiReceive(); //one can use these bytes to check power supply limits of SD SpiReceive(); } SpiReceive(); //extra 8 CLK SD_CS_DEASSERT; return response; //return state }
//****************************************************************** //Function : to write to a single block of SD card //Arguments : none //return : unsigned char; will be 0 if no error, // otherwise the response byte will be sent //****************************************************************** unsigned char SD_writeSingleBlock(unsigned long startBlock, char buffer[BLOCK]) { unsigned char response; unsigned int i, retry=0; response = SD_sendCommand(WRITE_SINGLE_BLOCK, startBlock); //write a Block command if(response != 0x00) return response; //check for SD status: 0x00 - OK (No flags set) SD_CS_ASSERT; SpiTransmit(0xfe); //Send start block token 0xfe (0x11111110) for(i=0; i<BLOCK; i++) //send 512 bytes data SpiTransmit(buffer[i]); SpiTransmit(0xff); //transmit dummy CRC (16-bit), CRC is ignored here SpiTransmit(0xff); response = SpiReceive(); if( (response & 0x1f) != 0x05) //response= 0xXXX0AAA1 ; AAA='010' - data accepted { //AAA='101'-data rejected due to CRC error SD_CS_DEASSERT; //AAA='110'-data rejected due to write error return response; } while(!SpiReceive()) //wait for SD card to complete writing and get idle if(retry++ > 0xfffe){SD_CS_DEASSERT; return 1;} SD_CS_DEASSERT; SpiTransmit(0xff); //just spend 8 clock cycle delay before reasserting the CS line SD_CS_ASSERT; //re-asserting the CS line to verify if card is still busy while(!SpiReceive()) //wait for SD card to complete writing and get idle if(retry++ > 0xfffe){SD_CS_DEASSERT; return 1;} SD_CS_DEASSERT; return 0; }
void SPI1_ISR(void) { ISR_ENTRY(); if (bit_is_set(SSPMIS, TXMIS)) { /* Tx half empty */ SpiTransmit(); SpiReceive(); SpiEnableRti(); } if ( bit_is_set(SSPMIS, RTMIS)) { /* Rx timeout */ SpiReceive(); SpiClearRti(); /* clear interrupt */ SpiDisableRti(); SpiDisable(); spi_message_received = TRUE; } VICVectAddr = 0x00000000; /* clear this interrupt from the VIC */ ISR_EXIT(); }
void SPI1_ISR(void) { ISR_ENTRY(); if (bit_is_set(SSPMIS, TXMIS)) { /* Tx fifo is half empty */ SpiTransmit(); SpiReceive(); SpiEnableRti(); } if (bit_is_set(SSPMIS, RTMIS)) { /* Rx fifo is not empty and no receive took place in the last 32 bits period */ SpiUnselectCurrentSlave(); SpiReceive(); SpiDisableRti(); SpiClearRti(); /* clear interrupt */ SpiDisable(); spi_message_received = TRUE; } VICVectAddr = 0x00000000; /* clear this interrupt from the VIC */ ISR_EXIT(); }
//****************************************************************** //Function : to initialize the SD/SDHC card in SPI mode //Arguments : none //return : unsigned char; will be 0 if no error, // otherwise the response byte will be sent //****************************************************************** unsigned char SD_init(unsigned char *cardType){ unsigned char i, response, SD_version; unsigned int retry=0 ; for(i=0;i<10;i++) SpiTransmit(0xff); //80 clock pulses spent before sending the first command SD_CS_ASSERT; do { response = SD_sendCommand(GO_IDLE_STATE, 0); //send 'reset & go idle' command retry++; if(retry>0x20) return 1; //time out, card not detected } while(response != 0x01); SD_CS_DEASSERT; SpiTransmit (0xff); SpiTransmit (0xff); retry = 0; SD_version = 2; //default set to SD compliance with ver2.x; //this may change after checking the next command do { response = SD_sendCommand(SEND_IF_COND,0x000001AA); //Check power supply status, mandatory for SDHC card retry++; if(retry>0xfe) { SD_version = 1; *cardType = 1; break; } //time out }while(response != 0x01); retry = 0; do { response = SD_sendCommand(APP_CMD,0); //CMD55, must be sent before sending any ACMD command response = SD_sendCommand(SD_SEND_OP_COND,0x40000000); //ACMD41 retry++; if(retry>0xfe) { return 2; //time out, card initialization failed } }while(response != 0x00); retry = 0; SDHC_flag = 0; if (SD_version == 2) { do { response = SD_sendCommand(READ_OCR,0); retry++; if(retry>0xfe) { *cardType = 0; break; } //time out }while(response != 0x00); if(SDHC_flag == 1) *cardType = 2; else *cardType = 3; } //SD_sendCommand(CRC_ON_OFF, OFF); //disable CRC; deafault - CRC disabled in SPI mode //SD_sendCommand(SET_BLOCK_LEN, 512); //set block size to 512; default size is 512 return 0; //successful return }