////////////////////////////////////////////////////////////////////////////////////////////////
int16 vs_command(char inout, address,a,b){//for sending non-song related data to the decoder..
int16 result;
SS=1;
xdcs=1;
SSPEN=0;
XDI_TRIS=0;
xcs=0;
vs_spi_write(inout);
vs_spi_write(address);//load the buffer with address
*(((char*)&result)+1)=vs_spi_write(a); //load buffer with hi data(ignored on read command)
*(((char*)&result)+0)=vs_spi_write(b); //load buffer with data low value
xcs=1; //deselect the vs1011 command registers (go into sdi mode)
XDI_TRIS=1;
SSPEN=1;
return (result);
}
/////////////////////////////////////////////////////////////////////////////////////////////////
void mmc_skip(char count){
for (;count>0;count--){
SPI_WRITE(0xFF);
SPI_WRITE(0xFF);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
char mmc_open_block(int32 block_number){
block_number*=512;
SS=0; // set SS = 0 (on)
SPI_WRITE(0x51); // send mmc read single block command
SPI_WRITE(*(((char*)&block_number)+3)); // arguments are address
SPI_WRITE(*(((char*)&block_number)+2));
SPI_WRITE(*(((char*)&block_number)+1));
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1; // if mmc_response returns 1 then we failed to get a 0x00 response (affirmative)
if((mmc_response(0xFE))==1) return 1; // wait for data token
return(0);
}
void mmc_close_block(void){
SPI_READ(0xFF); // CRC bytes that are not needed
SPI_READ(0xFF);
SS=1; // set SS = 1 (off)
SPI_WRITE(0xFF); // give mmc the clocks it needs to finish off
}
////////////////////////////////////////////////////////////////////////////////////////////////////
int mmc_init(){ //Initialises the MMC into SPI mode and sets block size
char p;
int i;
SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SS_DISABLED);
SSPSTAT |= 0x40; // set CKE = 1 - clock idle low
SSPCON &= 0xEF; // set CKP = 0 - data valid on rising edge
SS=1; // // set SS = 1 (off)
for(i=0;i<10;i++){ // initialise the MMC card into SPI mode by sending clks on
SPI_WRITE(0xFF);
}
SS=0; // set SS = 0 (on) tells card to go to spi mode when it receives reset
SPI_WRITE(0x40); // send reset command
for(p=4;p>0;p--){
SPI_WRITE(0x00); // all the arguments are 0x00 for the reset command
}
SPI_WRITE(0x95); // precalculated checksum as we are still in MMC mode
// puts("Sent go to SPI ");
if(mmc_response(0x01)==1) return 1; // if = 1 then there was a timeout waiting for 0x01 from the mmc (bad!)
// puts("Got response from MMC ");
i = 0;
while((i < 255) && (mmc_response(0x00)==1)){ // must keep sending command if response
SPI_WRITE(0x41); // send mmc command one to bring out of idle state
for(p=4;p>0;p--){
SPI_WRITE(0x00);
}
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
i++;
// printf("%d ",i);
}
if(i >= 254) return 1; // if >= 254 then there was a timeout waiting for 0x00 from the mmc (bad!)
// puts("Got out of idle response from MMC ");
SS=1; // set SS = 1 (off)
SPI_WRITE(0xFF); // extra clocks to allow mmc to finish off what it is doing
SS=0; // set SS = 0 (on)
SPI_WRITE(0x50); // send mmc command one to bring out of idle state
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) return 1; //(bad!)
SS=1; // set SS = 1 (off)
// puts("Got set block length response from MMC ");
return 0; //(good)
}
////////////////////////////////////////////////////////////////////////////////////////////////
int mmc_get_status(){ // Get the status register of the MMC, for debugging
char p;
xcs=1;
xdcs=1;
SS=0; // set SS = 0 (on)
SPI_WRITE(0x58); // send mmc command one
for(p=4;p>0;p--){
SPI_WRITE(0x00);
}
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
SS=1; // set SS = 1 (off)
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
int mmc_response(unsigned char response){ //reads the MMC until we get the response we want or timeout
unsigned long count = 0x0FFF; // 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
while(SPI_READ(0xFF) != response && --count > 0);
if(count==0) return 1; // loop was exited due to timeout (bad)
else return 0; // loop was exited before timeout (good)
}
////////////////////////////////////////////////////////////////////////////////////////////////
int mmc_read_block_to_serial(int32 block_number){ //read block from the MMC and outputs each byte to RS232. just for fun
unsigned long i;
mmc_open_block(block_number);
for(i=0;i<512;i++){
putc(SPI_READ(0xFF)); // we should now receive 512 bytes
}
mmc_close_block();
// puts(" ----End of read block---- ");
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
int mmc_read_block_to_vs1011(int32 block_number){
unsigned long i, ii;
SSPEN=1;
block_number*=2;
SS=0; // set SS = 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))==1) return 1; // if mmc_response returns 1 then we failed to get a 0x00 response (affirmative)
if((mmc_response(0xFE))==1) return 1; // wait for data token
// MOSI=1;
SSPEN=0;//switch to manual control of SPI port pins. the pic will not be reading these bytes into sspbuf
XdCS=0;//allow vs1011 to see the spi data
for(i=16;i>0;i--){
while(!XDREQ){;}
for(ii=0;ii<32;ii++){
XCLK=1;XCLK=0; //doing it this way (without looping) to kill off a few cycles per byte
XCLK=1;XCLK=0;//if you really want to go crazy, do this whole thing 32 times
XCLK=1;XCLK=0;// that would save you about 1000 clock cycles or so, per block
XCLK=1;XCLK=0;
XCLK=1;XCLK=0;
XCLK=1;XCLK=0;
XCLK=1;XCLK=0;
XCLK=1;XCLK=0;
}
}
XdCS=1;//turn off vs1011 chip select
SSPEN=1;//back to normal spi mode for pic to mmc communication
SPI_READ(0xFF); // CRC bytes that are not needed, so we just use 0xFF
SPI_READ(0xFF);
SS=1; // set SS = 1 (off)
SPI_WRITE(0xFF);// give mmc the clocks it needs to finish off
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////////////
#inline
void init(void){
tris_a=0b01110000;
tris_b=0b11101011;
// port_a=0;
// XCS=1;
option_reg =0b00000111;
// option_reg= 0b00000000;//allow rb pullups so that external pullup resistors are not needed
// ADCON0 = 0b00000000;//not using the adc, but here are the control bytes
// ADCON1 = 0b00000000;
// ANSEL = 0b00000000;
OSCCON = 0b01110010; // 01110010 for internal 8MHz clock, 0b01110000 otherwise
// CVRCON = 0b00000000; //00001101for 3.3 volt output in case you want it for some reason
// CMCON = 0b00000111;
}