#byte SSPCON1 = 0xFC6
#byte SSPSTAT = 0xFC7
#byte SSPBUF= 0xFC9
#byte PIR1=0xF9E
int8 const CMD0 =0x40; // comando reset (GO_IDLE_STATE)
int8 const CMD1 =0x41; // " idle (SEND_OP_COND)
int8 const CMD9 =0x49; // " CSD (SEND_CSD)
int8 const CMD10 =0x4A; // " CID (SEND_CID)
int8 const CMD17 =0x51; // " leer 1 sector (READ_SINGLE_BLOCK)
int8 const CMD24 =0x58; // " escribir 1 sector (WRITE_BLOCK)
int8 const CMD16 =0x50; // " define ancho del bloque (SET_BLOCKLEN)
//int8 const cmd[]={0x40,0x41,0xff,0x4A,0x49,0x51,0x58,0x50};
int16 const lTimeout=0x2fff;
//int32 Direccion_alta=0, Direccion_baja=0;
#inline
int iLeer_1Byte_SPI(){
SSPBUF=0xff; // envia puros unos en dataout
while(!bit_test(PIR1,3)){};
// mientras SSPIF=0 la transmisión contínua
// si SSPIF=1, terminó la transmisión. SSPIF-> PIR1,3
bit_clear(PIR1,3); // borro el flag SSPIF
return(SSPBUF);
}
//--------------------------------------------------------------
#inline
int iEscribir_1Byte_SPI(int dato){
SSPBUF=dato;
if(SSPCON1 & 0x80){
return(0xff);
}
else{
while(!bit_test(PIR1,3)){};
// mientras SSPIF=0 la transmisión contínua
// si SSPIF=1, terminó la transmisión. SSPIF-> PIR1,3
bit_clear(PIR1,3); // borro el flag SSPIF
}
return(0);
}
//--------------------------------------------------------------
#inline
int iComando_MMC(int8 _cmd,int32 llDireccion){
int iRespuesta=0xff;
long lTiempo_fuera=0;
output_low(MMC_CS);
iLeer_1Byte_SPI();
iEscribir_1Byte_SPI(_cmd);
iEscribir_1Byte_SPI(make8(llDireccion,3));
iEscribir_1Byte_SPI(make8(llDireccion,2));
iEscribir_1Byte_SPI(make8(llDireccion,1));
iEscribir_1Byte_SPI(make8(llDireccion,0));
iEscribir_1Byte_SPI(0x95);
while(iRespuesta==0xff){
iRespuesta=iLeer_1Byte_SPI();
if(lTiempo_fuera++>500){ break;}
}
return(iRespuesta);
}
//------------------------------------------------------------------------
#separate
int1 bLongitud_Bloque_512_Bytes(){
if(!iComando_MMC(CMD16,512)){
return 0;
}else{
return 1;
}
}
//---------------------------------------------------------------------------
#separate
int8 iIniciar_MMC(){
int t;
long lTiempo_fuera=0;
//----------------------------------------------------
// aqui se baja la velocidad a Fosc=8Mhz para tener 125Khz en el reloj
// del SPI para iniciar la MMC
//----------------------------------------------------
setup_oscillator(OSC_INTRC |OSC_8MHZ);
// cambio de oscilador primario = oscilador interno a 8 MHz
// IESO bit ignorado
delay_cycles(10); // transición de 7 ciclos + adicionales
while(!IOFS){} //espera estabilización del Fosc
// ¡¡comentar el while para la simulación en proteus!!
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_64 | SPI_XMIT_L_TO_H);
// SSPCON1=0b00110010;
// activa spi por hardware, maestro en Fosc/64,
// reloj idle en alto (CKP=1)
// SSPSTAT=0;
// transmisión ocurre en flanco bajada (CKE=0)
//----------------------------------------------------
output_high(MMC_CS);
delay_ms(100); // una especie de power-up timer para la MMC
for(t=0;t<12;t++){
output_toggle(LED_BICOLOR);
iLeer_1Byte_SPI();
}
while(iComando_MMC(CMD0,0)!=1){
delay_us(100);
if(lTiempo_fuera++>lTimeout){ return(1);}
}
lTiempo_fuera=0;
while(iComando_MMC(CMD1,0)!=0){
delay_us(100);
if(lTiempo_fuera++>lTimeout){ return(2);}
}
t=0;
t=bLongitud_Bloque_512_Bytes();
//----------------------------------------------------
// aqui se sube la velocidad a Fosc=48Mhz para tener 12Mhz en el reloj
// del SPI para hacer el resto de las operaciones en la MMC
// nota: lo hago después de setear longitud bloque, porque
// en el simulador lo pedía así, Falta probar en físico
//----------------------------------------------------
setup_oscillator(OSC_NORMAL);
// oscilador primario activo. IESO bit ignorado
delay_cycles(10); // transición de 7 ciclos + adicionales
setup_spi(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_XMIT_L_TO_H);
// SSPCON1=0b00110000;
// activa spi por hardware, maestro en Fosc/4, reloj idle en alto (CKP=1)
// SSPSTAT = 0;
// transmisión ocurre en flanco bajada (CKE=0
//----------------------------------------------------
if(!t){
output_high(MMC_CS);
return 0;
} else{
return 1;
}
}
//------------------------------------------------------------
#separate
int iLeer_CID(char *sCID){
int t;
long lTiempo_fuera=0;
output_low(MMC_CS);
while(iComando_MMC(CMD10,0)!=0){
delay_us(100);
if(lTiempo_fuera++>lTimeout){
output_high(MMC_CS);
return(2);
}
}
while(iLeer_1Byte_SPI()!=0xFE){};
for(t=0;t<18;t++){
output_toggle(LED_BICOLOR);
sCID[t]=iLeer_1Byte_SPI();
}
output_high(MMC_CS);
iLeer_1Byte_SPI();
return 0;
}
//----------------------------------------------------------------
#separate
int iLeer_CSD(char *sCSD){
int t;
long lTiempo_fuera=0;
output_low(MMC_CS);
while(iComando_MMC(CMD9,0)!=0){
delay_us(100);
if(lTiempo_fuera++>lTimeout){
output_high(MMC_CS);
return(2);
}
}
while(iLeer_1Byte_SPI()!=0xFE){};
for(t=0;t<18;t++){
output_toggle(LED_BICOLOR);
sCSD[t]=iLeer_1Byte_SPI();
}
output_high(MMC_CS);
iLeer_1Byte_SPI();
return 0;
}
#separate
int8 iLeer_bloque(int32 lNumero_Bloque){
if(!iComando_MMC(CMD17,lNumero_Bloque)){
return 0;
}else{
return 0xff;
}
//Direccion_baja=((llDireccion & 0x3F)<<9);
//Direccion_alta=((llDireccion & 0xFFC0)>>7);
}