char mmc_open_block(int32 block_number){ char tries,i; int32 block_number_temp; for(tries=0;tries<10;tries++){ SSPCON1=throttle; block_number_temp=block_number*512; SPI_WRITE(0xFF); SPI_WRITE(0xFF); MMCSS=0; // set MMCSS = 0 (on) SPI_WRITE(0x51); // send mmc read single block command SPI_WRITE(*(((char*)&block_number_temp)+3)); // arguments are address SPI_WRITE(*(((char*)&block_number_temp)+2)); SPI_WRITE(*(((char*)&block_number_temp)+1)); SPI_WRITE(0x00); SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF if((mmc_response(0x00))==0){//((mmc_response(0x00))==0){ if((mmc_response(0xFE))==0){ return(0); } for(i=0;i<255;i++){ SPI_WRITE(0xFF); SPI_WRITE(0xFF); } } MMCSS=1; // set MMCSS = 1 (off) SPI_WRITE(0xFF);// give mmc the clocks it needs to finish off SPI_WRITE(0xFF);// give mmc the clocks it needs to finish off } return 1; }
//#inline int mmc_read_block_to_vs1011(int32 block_number){ unsigned long i, ii;//, j; SSPCON1=throttle;//used to be 0b00100001 block_number*=2; SPI_WRITE(0xFF); SPI_WRITE(0xFF); MMCSS=0; // set MMCSS = 0 (on) SPI_WRITE(0x51); // send mmc read single block command SPI_WRITE(*(((char*)&block_number)+2)); // arguments are address SPI_WRITE(*(((char*)&block_number)+1)); SPI_WRITE(*(((char*)&block_number)+0)); SPI_WRITE(0x00); SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF if((mmc_response(0x00))==0) { if((mmc_response(0xFE))==0){ XDCS=0;//allow vs1011 to see the spi data for(i=16;i>0;i--){ while(!XDREQ){ ; } //led=LEDON; for(ii=0;ii<32;ii++){ SPI_write(0xff); check_clock(1); } //led=LEDOFF; } XdCS=1;//turn off vs1011 chip select somere: SSPCON1=throttle;//used to be 0b00100001 SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SS_DISABLED); SPI_READ(0xFF); // CRC bytes that are not needed, so we just use 0xFF SPI_READ(0xFF); MMCSS=1; // set MMCSS = 1 (off) SPI_WRITE(0xFF);// give mmc the clocks it needs to finish off SPI_WRITE(0xFF); return 0; } SPI_WRITE(0xFF); SPI_WRITE(0xFF); MMCSS=1; // set MMCSS = 1 (off) SPI_WRITE(0xFF);// give mmc the clocks it needs to finish off SPI_WRITE(0xFF); return 1; } SPI_WRITE(0xFF); SPI_WRITE(0xFF); MMCSS=1; // set MMCSS = 1 (off) SPI_WRITE(0xFF);// give mmc the clocks it needs to finish off SPI_WRITE(0xFF); return 1; }
/* * Reads a 512 Byte block from the MMC * Send READ_SINGLE_BLOCK command first, wait for response come back * 0x00 followed by 0xFE. The call SSP_SendRecvByte() to read the data * block back followed by the checksum. * */ int mmc_read_block(WORD block_number) { WORD Checksum; WORD varh,varl; IOCLR0 = SPI_SEL; /* clear SPI SSEL */ varl=((block_number&0x003F)<<9); varh=((block_number&0xFFC0)>>7); /* send MMC CMD17(READ_SINGLE_BLOCK) to read the data from MMC card */ MMCCmd[0] = 0x51; /* high block address bits, varh HIGH and LOW */ MMCCmd[1] = varh >> 0x08; MMCCmd[2] = varh & 0xFF; /* low block address bits, varl HIGH and LOW */ MMCCmd[3] = varl >> 0x08; MMCCmd[4] = varl & 0xFF; /* checksum is no longer required but we always send 0xFF */ MMCCmd[5] = 0xFF; SPI_Send(MMCCmd, MMC_CMD_SIZE ); /* if mmc_response returns 1 then we failed to get a 0x00 response */ if((mmc_response(0x00))==1) { MMCStatus = READ_BLOCK_TIMEOUT; IOSET0 = SPI_SEL; /* set SPI SSEL */ return MMCStatus; } /* wait for data token */ if((mmc_response(0xFE))==1) { MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING; IOSET0 = SPI_SEL; return MMCStatus; } /* Get the block of data based on the length */ SSP_SendRecvByte( MMCRDData, MMC_DATA_SIZE ); /* CRC bytes that are not needed */ Checksum = SSP_SendRecvByteByte(); Checksum = Checksum << 0x08 | SSP_SendRecvByteByte(); IOSET0 = SPI_SEL; /* set SPI SSEL */ SSP_SendRecvByteByte(); return 0; }
int mmc_get_status(){ // Get the status register of the MMC, for debugging char ret=0; char p; xcs=1; xdcs=1; MMCSS=0; // set MMCSS = 0 (on) SPI_WRITE(0x7a); // 0x58? for(p=4;p>0;p--){ SPI_WRITE(0x00); } SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF if( mmc_response(0x00) == 0 && mmc_response(0xff) == 0) ret=1; MMCSS=1; // set MMCSS = 1 (off) SPI_WRITE(0xFF); SPI_WRITE(0xFF); return ret; }
void mmc_cancel_block(void){ mmcss=1; SPI_WRITE(0xFF); SPI_WRITE(0xFF); mmcss=0; SPI_WRITE(0xFF); SPI_WRITE(0x4C); // send mmc cancel block command SPI_WRITE(0); //no arguments SPI_WRITE(0); SPI_WRITE(0); SPI_WRITE(0); SPI_WRITE(0xFF); mmc_response(0x00); MMCSS=1; SPI_WRITE(0xFF); // printf(" MMC block cancelled"); putc(13);putc(10); SPI_WRITE(0xff); }
int mmc_init(int1 report){ //Initialises the MMC into SPI mode and sets block size //char p; int i, ii, tries; for(tries=0;tries<10;tries++){ MMC_TRANSISTOR=1; XCLK_l=0; delay_ms(30); SSPSTAT |= 0x40; // set CKE = 1 - clock idle low SSPCON1=mmc_low_speed; //was 0b00100001 MMCSS=1; // // set MMCSS = 1 (off) MMC_TRANSISTOR=0; delay_ms(30); for(i=0;i<10;i++){ // initialise the MMC card into SPI mode by sending clks on SPI_WRITE(0xFF); } MMCSS=0; // set MMCSS = 0 (on) tells card to go to spi mode when it receives reset SPI_WRITE(0x40); // send reset command SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x95); // precalculated checksum as we are still in MMC mode /* if(report){ puts(" \n\r"); puts("MMC/SD init: Sent 0x40 (cmd0) SPI\n\r"); } */ if(mmc_response(0x01)==0){// return 1; // if = 1 then there was a timeout waiting for 0x01 from the mmc (bad!) /* if(report){ puts("MMC/SD init: Got response \n\r"); } */ i = 0; ii=0; do{ // must keep sending command if response MMCSS=1; SPI_WRITE(0xff); SPI_WRITE(0xff); MMCSS=0; SPI_WRITE(0x77);//command 55 // send mmc command one to bring out of idle state SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0xF0); // checksum is no longer required but we always send 0xFF while(mmc_response_masked(0b10000000)==1){ i++; if(i>10){ ii = 0; do{ MMCSS=1; SPI_WRITE(0xff); SPI_WRITE(0xff); MMCSS=0; SPI_WRITE(0x41); // send mmc command one to bring out of idle state SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF ii++; /* if(report){ printf(".%u",ii); } */ if (mmc_response_masked(0b10000001)==0){ /* if(report){ printf("yes, it's an mmc!");putc(13);putc(10); } */ goto jump; } }while(ii < 255); // must keep sending command if response } } SPI_WRITE(0xff); SPI_WRITE(0xff); SPI_WRITE(0xff); SPI_WRITE(0xff); SPI_WRITE(0x69);//command 41, not command 1 // send mmc command one to bring out of idle state SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF i++; /* if(report){ printf("...%ud ",i);// putc(13);putc(10); } */ if (mmc_response_masked(0b10000001)==0){goto jump;} }while(i < 255);//we want a zero here, right? /* if(report){ printf("failed out of idle---");putc(13);putc(10); } */ error=3; return 1; jump: /* if(report){ putc(13);putc(10); puts("MMC/SD init: Got out of idle response \n\r");putc(13);putc(10); } */ MMCSS=1; // set MMCSS = 1 (off) SPI_WRITE(0xFF); // extra clocks to allow mmc to finish off what it is doing SPI_WRITE(0xff); SPI_WRITE(0xff); SPI_WRITE(0xff); MMCSS=0; // set MMCSS = 0 (on) SPI_WRITE(0xff); SPI_WRITE(0x50); // block size command SPI_WRITE(0x00); SPI_WRITE(0x00); SPI_WRITE(0x02); // high block length bits - 512 bytes SPI_WRITE(0x00); // low block length bits SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF if((mmc_response(0x00))==1) { error=4; return 1; //bad! } SPI_WRITE(0xff); // SPI_WRITE(0xff); // MMCSS=1; //off /* if(report){ puts("MMC/SD init: Got set block length response. Done.\n\r");putc(13);putc(10); } */ SPI_WRITE(0xff); // SPI_WRITE(0xff); // sspcon1=throttle; return 0; //good } } }
/* * Initialises the MMC into SPI mode and sets block size(512), returns * 0 on success * */ int mmc_init() { DWORD i; /* Generate a data pattern for write block */ for(i=0;i<MMC_DATA_SIZE;i++) { MMCWRData[i] = i; } MMCStatus = 0; IOSET0 = SPI_SEL; /* set SPI SSEL */ /* initialise the MMC card into SPI mode by sending 80 clks on */ /* Use MMCRDData as a temporary buffer for SPI_Send() */ for(i=0; i<10; i++) { MMCRDData[i] = 0xFF; } SPI_Send( MMCRDData, 10 ); IOCLR0 = SPI_SEL; /* clear SPI SSEL */ /* send CMD0(RESET or GO_IDLE_STATE) command, all the arguments are 0x00 for the reset command, precalculated checksum */ MMCCmd[0] = 0x40; MMCCmd[1] = 0x00; MMCCmd[2] = 0x00; MMCCmd[3] = 0x00; MMCCmd[4] = 0x00; MMCCmd[5] = 0x95; SPI_Send( MMCCmd, MMC_CMD_SIZE ); /* if = 1 then there was a timeout waiting for 0x01 from the MMC */ if( mmc_response(0x01) == 1 ) { MMCStatus = IDLE_STATE_TIMEOUT; IOSET0 = SPI_SEL; /* set SPI SSEL */ return MMCStatus; } /* Send some dummy clocks after GO_IDLE_STATE */ IOSET0 = SPI_SEL; /* set SPI SSEL */ SSP_SendRecvByteByte(); IOCLR0 = SPI_SEL; /* clear SPI SSEL */ /* must keep sending command until zero response ia back. */ i = MAX_TIMEOUT; do { /* send mmc CMD1(SEND_OP_COND) to bring out of idle state */ /* all the arguments are 0x00 for command one */ MMCCmd[0] = 0x41; MMCCmd[1] = 0x00; MMCCmd[2] = 0x00; MMCCmd[3] = 0x00; MMCCmd[4] = 0x00; /* checksum is no longer required but we always send 0xFF */ MMCCmd[5] = 0xFF; SPI_Send( MMCCmd, MMC_CMD_SIZE ); i--; } while ( (mmc_response(0x00) != 0) && (i>0) ); /* timeout waiting for 0x00 from the MMC */ if ( i == 0 ) { MMCStatus = OP_COND_TIMEOUT; IOSET0 = SPI_SEL; /* set SPI SSEL */ return MMCStatus; } /* Send some dummy clocks after SEND_OP_COND */ IOSET0 = SPI_SEL; /* set SPI SSEL */ SSP_SendRecvByteByte(); IOCLR0 = SPI_SEL; /* clear SPI SSEL */ /* send MMC CMD16(SET_BLOCKLEN) to set the block length */ MMCCmd[0] = 0x50; MMCCmd[1] = 0x00; /* 4 bytes from here is the block length */ /* LSB is first */ /* 00 00 00 10 set to 16 bytes */ /* 00 00 02 00 set to 512 bytes */ MMCCmd[2] = 0x00; /* high block length bits - 512 bytes */ MMCCmd[3] = 0x02; /* low block length bits */ MMCCmd[4] = 0x00; /* checksum is no longer required but we always send 0xFF */ MMCCmd[5] = 0xFF; SPI_Send( MMCCmd, MMC_CMD_SIZE ); if( (mmc_response(0x00))==1 ) { MMCStatus = SET_BLOCKLEN_TIMEOUT; IOSET0 = SPI_SEL; /* set SPI SSEL */ return MMCStatus; } IOSET0 = SPI_SEL; /* set SPI SSEL */ SSP_SendRecvByteByte(); return 0; }
/* write a block of data based on the length that has been set * in the SET_BLOCKLEN command. * Send the WRITE_SINGLE_BLOCK command out first, check the * R1 response, then send the data start token(bit 0 to 0) followed by * the block of data. The test program sets the block length to 512 * bytes. When the data write finishs, the response should come back * as 0xX5 bit 3 to 0 as 0101B, then another non-zero value indicating * that MMC card is in idle state again. * */ int mmc_write_block(WORD block_number) { WORD varl, varh; BYTE Status; IOCLR0 = SPI_SEL; /* clear SPI SSEL */ /* block size has been set in mmc_init() */ varl=((block_number&0x003F)<<9); varh=((block_number&0xFFC0)>>7); /* send mmc CMD24(WRITE_SINGLE_BLOCK) to write the data to MMC card */ MMCCmd[0] = 0x58; /* high block address bits, varh HIGH and LOW */ MMCCmd[1] = varh >> 0x08; MMCCmd[2] = varh & 0xFF; /* low block address bits, varl HIGH and LOW */ MMCCmd[3] = varl >> 0x08; MMCCmd[4] = varl & 0xFF; /* checksum is no longer required but we always send 0xFF */ MMCCmd[5] = 0xFF; SPI_Send(MMCCmd, MMC_CMD_SIZE ); /* if mmc_response returns 1 then we failed to get a 0x00 response */ if((mmc_response(0x00))==1) { MMCStatus = WRITE_BLOCK_TIMEOUT; IOSET0 = SPI_SEL; /* set SPI SSEL */ return MMCStatus; } /* Set bit 0 to 0 which indicates the beginning of the data block */ MMCCmd[0] = 0xFE; SPI_Send( MMCCmd, 1 ); /* send data, pattern as 0x00,0x01,0x02,0x03,0x04,0x05 ...*/ SPI_Send( MMCWRData, MMC_DATA_SIZE ); /* Send dummy checksum */ /* when the last check sum is sent, the response should come back immediately. So, check the SPI FIFO MISO and make sure the status return 0xX5, the bit 3 through 0 should be 0x05 */ MMCCmd[0] = 0xFF; MMCCmd[1] = 0xFF; SPI_Send( MMCCmd, 2 ); Status = SSP_SendRecvByteByte(); if ( (Status & 0x0F) != 0x05 ) { MMCStatus = WRITE_BLOCK_FAIL; IOSET0 = SPI_SEL; /* set SPI SSEL */ return MMCStatus; } /* if the status is already zero, the write hasn't finished yet and card is busy */ if(mmc_wait_for_write_finish()==1) { MMCStatus = WRITE_BLOCK_FAIL; IOSET0 = SPI_SEL; /* set SPI SSEL */ return MMCStatus; } IOSET0 = SPI_SEL; /* set SPI SSEL */ SSP_SendRecvByteByte(); return 0; }