/*  	---------------------------------  MMC.C ----------------------------------------------
	Rutinas C de acceso a una tarjeta MMC mediante el protocolo de operacion SPI. Han
	sido probadas en un microcontrolador AVR-8515 y desarrolladas mediante la plataforma
	gratuita para Atmel y AVR-ATmega, Win-AVR.
	Version 0.0
	Jordi Bartolome
	www.tolaemon.com
	6-2004
	---------------------------------------------------------------------------------------*/
	
int ciclos_pausa=0x00;

/* RSI de la interrupción de desboradamiento del TIMER0 */
SIGNAL (SIG_OVERFLOW0) {
    	
	/* control de la variable de pausa: si la variable ciclos_pausa esta activada se decrementa */
	if (ciclos_pausa>0){
		ciclos_pausa--;
	};/*if*/
	
}/* RSI del TIMER0 */


/* procedimiento que realiza la pausa activa*/
void TIEMPO_pausa(int ciclos_pausa_ini){

	ciclos_pausa=ciclos_pausa_ini;
	while (ciclos_pausa!=0){
		/* mientras ciclos_pausa no sea 0 se hace una espera activa */
		/* es la RSI del timer quien decrementa la variable ciclos_pausa */
	};/*while*/

}/*TIEMPO_pausa*/


/* procedimiento que envia un byte a la MMCard a traves de la SPI */
uint8_t MMC_envia_byte(char valor){

	SPDR=valor;
	while (!bit_is_set(SPSR,7)); /* se espera hasta que no haya finalizado la transmision */
	SPSR=SPSR&0x7F;
	return SPDR; /* se retorna el valor cargado en el registro de datos tras la transmision */

}/* MMC_envia_byte */


/* procedimiento que envia el comando recibido a la MMC a traves de la SPI */
void MMC_envia_comando(	uint8_t byte_0,uint8_t byte_1,uint8_t byte_2,uint8_t byte_3,uint8_t byte_4,uint8_t byte_5 ){
	
	PORTD = PORTD|0x20;/* el bit 5-CS MMCard a 1 (CS desactivado) : XX1X XXXX */	
	TIEMPO_pausa(2);/* TIEMPO_pausa */		
	MMC_envia_byte(0xFF);	
	PORTD = PORTD&0xDF;/* el bit 5-CS MMCard a 0 (CS activado): XX0X XXXX */		
	TIEMPO_pausa(2);/* TIEMPO_pausa */		
	/* Se envia el COMANDO */	
	MMC_envia_byte(byte_0);
	MMC_envia_byte(byte_1);
	MMC_envia_byte(byte_2);
	MMC_envia_byte(byte_3);
	MMC_envia_byte(byte_4);
	MMC_envia_byte(byte_5);	
	TIEMPO_pausa(2);/* TIEMPO_pausa */		
	
}/*MMC_envia_comando*/


/* procedimiento que activa los puertos y perifericos necesarios para la
comunicacion con la tarjeta MMCard */
void MMC_activa(){
	uint8_t i;
	
	DDRD = DDRD|0x20;/* bit 5-CS MMCard del puerto D configurado como salida: XX1X XXXX */		
	SPCR=0x53;/* configuracion de la SPI: 0101 0011 */		
	PORTD = PORTD|0x20;/* el bit 5-CS MMCard a 1 (CS desactivado) : XX1X XXXX */	
	TIEMPO_pausa(4);/* TIEMPO_pausa */	
	for (i=0;i<20;i++){
		MMC_envia_byte(0xFF); /* se dan los 80 clocks iniciales para activar la SPI del la MMC */
	};/*for*/
	PORTD = PORTD&0xDF;/* el bit 5-CS MMCard a 0 (CS activado): XX0X XXXX */		

}/*MMC_desactiva*/


/* procedimiento que desactiva la interficie SPI usada para la comunicaicon con la MMC */
void MMC_desactiva(){

	PORTD = PORTD|0x20;/* el bit 5-CS MMCard a 1 (CS desactivado) : XX1X XXXX */	
	SPCR=0x13;/* configuracion de la SPI: 0001 0011 */
		
}/*MMC_desactiva*/


/* funcion que retorna la respuesta de la MMCard al comando enviado */
uint8_t MMC_espera_respuesta ( ){
	uint8_t i=0;	
	uint8_t valor=0xFF;

	/* entre el comando y la respuesta existe un retardo que va de 1 a 8  bytes (yo pongo 32 (4x) para que 
	haya tiempo segurisisisimo), la respuesta R1 tiene una longitud de un byte y siempre comienza con un 0 */	
	while ( (i<=32) && (valor==0xFF) ){
		valor=MMC_envia_byte(0xFF);	
		i++;	
	};/*while*/	
	return valor;

}/* MMC_espera_respuesta */


/* funcion que retorna la respuesta de la MMCard al comando enviado */
uint8_t MMC_espera_data_token( ){
	uint8_t i=0;	
	uint8_t valor=0x00;

	/* se mantiene esperando el Data Token enviado por la tarjeta */
	while ( (i<=10) && (valor!=0xFE) ){
		valor=MMC_envia_byte(0xFF);	
		i++;	
	};/*while*/	
	return valor;

}/* MMC_espera_respuesta */


/* funcion que realiza la secuencia de arranque de la tarjeta, retorna 1 si todo va bien y 0 si va mal */
char MMC_prepara_tarjeta(){
	char respuesta1;
	char respuesta2;
	char retorno;
	uint8_t intentos;


	intentos=6;
	respuesta1=0;
	while ( (intentos>0)&&(respuesta1!=1) ){
		MMC_activa();
		MMC_envia_comando(0x40,0x00,0x00,0x00,0x00,0x95);
		respuesta1=MMC_espera_respuesta();
		MMC_desactiva();			
		intentos--;
	};/* while */
	respuesta2=1;
	while ( (intentos>0)&&(respuesta2!=0) ){
		MMC_activa();					
		MMC_envia_comando(0x41,0x00,0x00,0x00,0x00,0xFF);
		respuesta2=MMC_espera_respuesta();
		MMC_desactiva();			
		intentos--;
	};/* while */
	MMC_desactiva();						
	
	/* si las respuestas recibidas son las correctas se retorna 1 sino 0 */
	if ((respuesta1==1)&&(respuesta2==0)){
		retorno=1;
	}else{
		retorno=0;
	};/*if*/
	
	return retorno;
	
}/* MMC_prepara_tarjeta */

