Hola a todos, leyendo mucho por aqui y por aca, encontre harta diferencia entre un par de SD de distintas marcas. La que ha mostrado señales de vida es una memoria SD kingston de 1 GB. Con una Sandisc, no hubo caso. No fue posible arrancar ninguna de las dos, a menos que se envie el CRC7 del CMD0 y CMD1. Para la gente que pueda estar experimentando con estas memorias y no puede pasar del CMD0 con respuesta valida, les recomiendo probar con el CRC7 en los dos primeros comandos. El codigo lo deje en mi trabajo, a si es que mas rato cuelgo unas fotos que tome del osciloscopio.
Ojala alguien este tambien con este tema, para que hagamos un "paso a paso" de la operacion basica con SD, ya que en ningun lado aparece claro.
Saludos
chaos
COdigo:
#include <p18f452.h>
#include <spi.h>
#include <usart.h>
#include <delays.h>
#include <adc.h>
#include <stdlib.h>
#include <string.h>
#pragma config OSC = HS // xtal=10Mhz
#pragma config OSCS = OFF
#pragma config PWRT = ON
#pragma config BOR = OFF //brown-out reset, BORV = 45 brown-out voltaje (4.5v)
#pragma config WDT = OFF //WDTPS = 1, postscaler 1:1
#pragma config CCP2MUX = OFF
#pragma config LVP = OFF,DEBUG = OFF
#pragma config CP0 = OFF,CP1 = OFF,CP2 = OFF,CP3 = OFF
#pragma config CPB = OFF,CPD = OFF
#pragma config WRT0 = OFF,WRT1 = OFF,WRT2 = OFF,WRT3 = OFF
#pragma config WRTB = OFF,WRTC = OFF,WRTD = OFF
#pragma config EBTR0 = OFF,EBTR1 = OFF,EBTR2 = OFF,EBTR3 = OFF
#pragma config EBTRB = OFF
//********* PROTOTIPOS DE FUNCION ****************
// GENERAL
void Configuracion_Mcu(void);
// USART
void Verificar_DATO_RX(void);
// MMC
void Inicializacion_MMC_en_Modo_SPI(void);
//******* DEFINICION DE VARIABLE *****************
// GENERAL
unsigned char a;
unsigned long b;
// USART
unsigned char DATO_TX;
unsigned char DATO_RX;
// MMC
#define MMC_CS LATDbits.LATD3 // chip selec en RD3
//************************************************
//********* INTERRUPCION **********************
void rx_handler (void);
#pragma code rx_interrupt = 0x08
void rx_interrupt (void)
{
_asm goto rx_handler _endasm
}
#pragma code
#pragma interrupt rx_handler
void rx_handler (void)
{
DATO_RX = ReadUSART();
Verificar_DATO_RX();
}
//******* FIN INTERRUPCION *********************
//************************************************
//************************************************************
//***************** PRINCIPAL ******************************
void main(void)
{
Configuracion_Mcu();
while(1)
{
while(BusyUSART());
putrsUSART("\n\r\n\rINICIANDO SD\n\r\n\r");
Inicializacion_MMC_en_Modo_SPI();
}
}
//************************************************************
///////////////////// FUNCIONES ///////////////////////////*
//************************************************************
//************************************************************
//************** Inicializacion_MMC_en_Modo_SPI ************
void Inicializacion_MMC_en_Modo_SPI(void)
{
OpenSPI(SPI_FOSC_64, MODE_11, SMPMID);
MMC_CS = 1;
for(a=0;a<10;a++) //se envian 80 pulsos por la linea de clock
{ //el manual dice 74, pero asi parece funcionar de todas formas
putcSPI(0xFF); //los pulson viajan a 165 KHz.
}
MMC_CS = 0; //habilita SD.
a=0x00; //cero en nuestra variable, solo para estar seguros que no es 0x01.
while (a!=0x01)
{
Delay10TCYx(10);
WriteSPI(0x40); //se envia comando CMD0, resetea SD y deja en modo SPI IDLE
WriteSPI(0x00); //solo queda operativa para algunos comandos.
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x95); //CRC7 calculado previamente (esto aparece en la ficha tecnica).
WriteSPI(0x55); //8 clocks despues de cada comando. Como lo que cuentan son los pulsos
//de reloj, se envia un 0x55, para una facil identificacion del dato
//mediante un osciloscopio.
a=ReadSPI();
while(BusyUSART()); //bandera, se visualiza en la terminal, las veces que se intento leer
WriteUSART('/'); //la respuesta al comando "CMD0".
}
WriteSPI(0xFF); //pulsos necesarios para que la SD termine con algun procedo pendiente.
MMC_CS = 1; //deshabilita SD.
while(BusyUSART());
putrsUSART("MODO SPI LISTO, ESTADO=IDLE\n\r\n\r"); //bandera, avisa que el CMD0 fue aceptado por la SD.
//-----------------------
MMC_CS = 0;
a=0xFF; //unos en nuestra variable, solo para estar seguros que no es 0x00.
while(a!=0x00)
{
Delay10TCYx(10);
WriteSPI(0x41); //se envia comando CMD1, deja SD lista para recibir resto de comandos.
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0xF9); //segun manual todos los comandos deben llevar CRC7, pero si envio otro dato,
//la señal se vuelve inestable y ocurren lecturas en tiempos indeseados.
WriteSPI(0x55); //idem
a=ReadSPI();
while(BusyUSART()); //bandera, se visualiza en la terminal, las veces que se intento leer
putcUSART('*'); //la respuesta al comando "CMD1"
}
WriteSPI(0xFF); //idem
MMC_CS = 1;
while(BusyUSART());
putrsUSART("TARJETA OPERATIVA\n\r\n\r"); //bandera, avisa que el CMD1 fue aceptado por la SD.
//-----------------------
MMC_CS = 0;
a=0xFF; //unos en nuestra variable, solo para estar seguros que no es 0x00
while(a!=0x00)
{
Delay10TCYx(10);
WriteSPI(0x50); //se envia CMD16 , longitud de bloque.
WriteSPI(0x00);
WriteSPI(0x00);
WriteSPI(0x02);
WriteSPI(0x00);
WriteSPI(0x00); //para algunosvalores como por ejemplo 0xFF, la SD no envia respuesta
WriteSPI(0xFF); //idem
a=ReadSPI();
while(BusyUSART()); //bandera, se visualiza en la terminal, las veces que se intento leer
putcUSART('-'); //la respuesta al comando "CMD16"
}
WriteSPI(0xFF);
MMC_CS = 1;
while(BusyUSART());
putrsUSART("BLOQUES DE 512 BYTES\n\r\n\r");
}
//************************************************************
//************** FUNCION Configuracion_Mcu *******************
void Configuracion_Mcu(void)
{
TRISA = 0b11111111; // A7=, A6=, A5=, A4=, A3=, A2=, A1=, A0=
TRISB = 0b11011111; // B7=, B6=, B5=, B4=, B3=, B2=, B1=, B0=
TRISC = 0b10010111; // C7=RX , C6=TX, C5=SDO, C4=SDI, C3=SCK, C2=, C1=, C0=
TRISD = 0b11110011; // D7=, D6=, D5=, D4=, D3=#CS_MCC, D2=E2P_CS, D1= , D0=
TRISE = 0b11111111; // E7=, E6=, E5=, E4=PSPMODE, E3=, E2=
// E1=, E0=
PORTA = 0b00000000;
PORTB = 0b00000000;
PORTC = 0b00000000;
PORTD = 0b00000000;
PORTE = 0b00000000;
LATA = 0X00;
LATB = 0X00;
LATC = 0X00;
LATD = 0X00;
LATE = 0X00;
//**************
MMC_CS = 1; // MMC Deshabilitada
//*************
// CONFIGURACION INTERRUPCIONES
PIE1bits.RCIE = 1; // habilita INTERRUPCION POR RECEPCION
RCONbits.IPEN = 1; //se habilita modo prioridad de interrupciones
IPR1bits.RCIP = 1; //interrupcion por recepcion = alta prioridad
INTCONbits.GIEH = 1;
PIR1bits.RCIF = 0;
// CONFIGURACION USART
OpenUSART(USART_TX_INT_OFF & // USART para 9.6K baudios
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_LOW,64);
}
//************************************************************
//************* FUNCION Verificar_DATO_RX ********************
void Verificar_DATO_RX(void)
{
if (DATO_RX==0x31) //banderade control externo, mediante HyperTerminal
{
//sin actividad, por entrada de dato USART
}
}
//// FIN //////
detalle del
CMD1 = 41 00 00 00 00 F7 + 55 + ReadSPIDetalle de la respuesta al
CMD1, esta es R1 = 00Claramente se ve una lectura de 0x00 en el ultimo tren de pulsos(estos correspomden al ReadSPI)
Aqui se ve que lee 0xFF al ejecutar ReadSPI, esto ocurre porque la SD no estaba lista para enviar los datos.
El codigo esta hecho de la manera mas sencilla posible, sin utilizar funciones avanzadas, asi todos lo pueden seguir, me incluyo yo, que no manejo mucho "C" ya que he migrado desde ASM, hace poco mas de un mes.
Ojala sigan el hilo, por mi parte hoy vere si puedo escribir en la SD.
Saludos,
chaos:)