Autor Tema: Problema con la RE-escritura en SD  (Leído 3475 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado astoroth_

  • PIC10
  • *
  • Mensajes: 20
Problema con la RE-escritura en SD
« en: 20 de Junio de 2006, 01:12:02 »
Hola a todos, tengo un problema bastante curioso. Tengo que escribir datos en una tarjeta SD. Tras hacer todos los trámites necesarios, consigo escribir un bloque de 512 bytes. El problema es que no consigo escribir más de un bloque. El programa se queda pillado después del primer bloque escrito. Yo creo que debe ser algo relacionado con la espera de algunos ciclos de reloj SPI... pero no sé muy bien por donde tirar.

El micro que utilizo es DSPIC 30F4011, con MPLAB 7.4, ICD2 R13... Os adjunto el código a ver si alguien sabe lo que ocurre:

Código: [Seleccionar]
#include "p30f4011.h"

_FOSC(CSW_FSCM_OFF & FRC_PLL4);
_FWDT(WDT_OFF);
_FBORPOR(PBOR_OFF & BORV_20 & PWRT_64 & MCLR_EN);
_FGS(CODE_PROT_OFF);

#define LED PORTDbits.RD0 // En el ejemplo RB0
#define LED_DIR TRISDbits.TRISD0


#define LED2 PORTDbits.RD2 // En el ejemplo RB0
#define LED2_DIR TRISDbits.TRISD2

#define LED3 PORTDbits.RD3 // En el ejemplo RB0
#define LED3_DIR TRISDbits.TRISD3


//SD CARD 1
#define SD_CS PORTEbits.RE2 // en el ejemplo RB3
#define SD_CS_DIR TRISEbits.TRISE2          // dirección del puerto

// Definiciones sobre SPI
#define SDI PORTFbits.RF2
#define SDI_DIR TRISFbits.TRISF2

#define SCK PORTFbits.RF6
#define SCK_DIR TRISFbits.TRISF6

#define SDO PORTFbits.RF3
#define SDO_DIR TRISFbits.TRISF3



#define SD_Enable() SD_CS = 0 /* set low to activate SD Card chip select */
#define SD_Disable() SD_CS = 1 /* set high to deactivate SD Card chip select */
#define Nop() {__asm__ volatile ("nop");}



void SPIWrite(unsigned char data)
{
// DO NOT WAIT FOR SPITBF TO BE CLEAR HERE
// (for some reason, it doesn't work on this side of the write data).

// Write the data!
SPI1BUF = data;

// Wait until send buffer is ready for more data.
while(SPI1STATbits.SPITBF);
}




unsigned char SPIRead(void)
{
unsigned char data;

if(SPI1STATbits.SPIRBF)
{
// already have some data to return, don't initiate a read
data = SPI1BUF;

SPI1STATbits.SPIROV = 0;
return data;
}

// We don't have any data to read yet, so initiate a read
SPI1BUF = 0xFF;  // write dummy data to initiate an SPI read
while(SPI1STATbits.SPITBF); // wait until the data is finished reading
data = SPI1BUF;

SPI1STATbits.SPIROV = 0;
return data;
}

void InitSPI(void)
{
//SD_PowerOff();
//SD_PWR_DIR = 0; // output
//SD_PowerOff();

SD_Disable();
SD_CS_DIR = 0; // output
SD_Disable();

SDI_DIR = 1; // input
SCK_DIR = 1;
SDO_DIR = 1;

SPI1STAT = 0x8000; // enable SPI port

// set SPI port to slowest setting
// master mode
// 8 bit
// Idle state for Clock is high level
// Primary prescaler 64:1
// Secondary prescaler 8:1
SPI1CON = 0x0060;
}

// primary prescaler 1:1
// secondary prescaler 1:1
#define SPIFastClock() SPI1CON = 0x007F

// SD Card SPI Commands are defined in the SanDisk SD Card Product Manual v1.9
// section 5.2.2.1 (page 91 of PDF)
// http://www.sandisk.com/pdf/oem/ProdManualSDCardv1.9.pdf
//
// 0 - GO_IDLE_STATE - Resets the SD Card
// 1 - SEND_OP_COND - Activates the card's initialization process
// 9 - SEND_CSD Asks card to send card-specific data
// 10 - SEND_CID Asks card to send card identification
// 12 - STOP_TRANSMISSION Forces card to stop transmission during multi-block read
// 13 - SEND_STATUS Asks card to send its status register.
// 16 - SET_BLOCKLEN Selects block length for all subsequent block commands (default is 512)
// 17 - READ_SINGLE_BLOCK Reads a block of the size specified by SET_BLOCKLEN
// 18 - READ_MULTIPLE_BLOCK Continuously transfers data until interrupted by STOP_TRANSMISSION
// 24 - WRITE_BLOCK Writes a block of the size specified by SET_BLOCKLEN
// 25 - WRITE_MULTI_BLOCK Continuously writes blocks of data until a stop transmission token is sent instead of start block token.

// R1 Response Codes (from SD Card Product Manual v1.9 section 5.2.3.1)
#define R1_IN_IDLE_STATE    (1<<0)   // The card is in idle state and running initializing process.
#define R1_ERASE_RESET      (1<<1)   // An erase sequence was cleared before executing because of an out of erase sequence command was received.
#define R1_ILLEGAL_COMMAND  (1<<2)   // An illegal command code was detected
#define R1_COM_CRC_ERROR    (1<<3)   // The CRC check of the last command failed.
#define R1_ERASE_SEQ_ERROR  (1<<4)  // An error in the sequence of erase commands occured.
#define R1_ADDRESS_ERROR    (1<<5)  // A misaligned address, which did not match the block length was used in the command.
#define R1_PARAMETER        (1<<6)  // The command's argument (e.g. address, block length) was out of the allowed range for this card.
// R1 bit (1<<7) is always 0
unsigned char SD_WriteCommand(unsigned char* cmd)
{
unsigned int i;
unsigned char response;
unsigned char savedSD_CS = SD_CS;

// SD Card Command Format
// (from Section 5.2.1 of SanDisk SD Card Product Manual v1.9).
// Frame 7 = 0
// Frame 6 = 1
// Command (6 bits)
// Address (32 bits)
// Frame 0 = 1

// Set the framing bits correctly (never change)
cmd[0] |= (1<<6);
cmd[0] &= ~(1<<7);
cmd[5] |= (1<<0);

// Send the 6 byte command
SD_Enable();
for(i = 0; i < 6; ++i)
{
SPIWrite(*cmd);
cmd++;
}

// Wait for the response
i = 0;
do
{
response = SPIRead();

if(i > 100) //antes 100
{
break;
}
i++;
} while(response == 0xFF);

SD_Disable();

// Following any command, the SD Card needs 8 clocks to finish up its work.
// (from SanDisk SD Card Product Manual v1.9 section 5.1.8)
SPIWrite(0xFF);

SD_CS = savedSD_CS;
return(response);
}

unsigned char InitSD()
{
unsigned int i = 0;
    unsigned int j = 0;
    unsigned int k = 0;
unsigned char status;

// Turn off SD Card
SD_Disable();
//SD_PowerOff();

// Wait for power to really go down
for(i = 0; i; i++);/*{
for(j=0;j;j++){
for(k=0;k;k++);
}
}*/
for(i = 0; i; i++);
for(i = 0; i; i++);
for(i = 0; i; i++);

// Turn on SD Card
//SD_PowerOn();

// Wait for power to really come up
for(status = 0; status < 100; ++status)
{
for(i = 0; i; i++);
for(i = 0; i; i++);
for(i = 0; i; i++);
for(i = 0; i; i++);
}

// We need to give SD Card about a hundred clock cycles to boot up
for(i = 0; i < 16; ++i)
{
SPIWrite(0xFF); // write dummy data to pump clock signal line
}

SD_Enable();

// This is the only command required to have a valid CRC
// After this command, CRC values are ignore unless explicitly enabled using CMD59
unsigned char CMD0_GO_IDLE_STATE[] = {0x00,0x00,0x00,0x00,0x00,0x95}; //antes 0x40

// Wait for the SD Card to go into IDLE state
i = 0;
do
{
status = SD_WriteCommand(CMD0_GO_IDLE_STATE);

// fail and return
if(i++ > 50)
{
return 1;
}

            LED=1;
} while( status  != 0x01 );

// Wait for SD Card to initialize
unsigned char CMD1_SEND_OP_COND[] = {0x01,0x00,0x00,0x00,0x00,0xFF};

i = 0;
do
{
status = SD_WriteCommand(CMD1_SEND_OP_COND);
if(i++ > 50)
{
return 2;
}
} while( (status & R1_IN_IDLE_STATE) != 0 );



/////// ......ooo000ooo.....ooo000ooo/////// Aquí llega




    // Send CMD55, required to precede all "application specific" commands
unsigned char CMD55_APP_CMD[] = {0x37,0x00,0x00,0x00,0x00,0xFF}; // antes 55 en decimal
status = SD_WriteCommand(CMD55_APP_CMD); // Do not check response here



/////// ......ooo000ooo.....ooo000ooo/////// Aquí llega




// Send the ACMD41 command to initialize SD Card mode (not supported by MMC cards)
i = 0;
unsigned char ACMD41_SD_SEND_OP_COND[] = {0x29,0x00,0x00,0x00,0x00,0xFF}; //antes 41 en decimal
do
{
status = SD_WriteCommand(ACMD41_SD_SEND_OP_COND);
// Might return 0x04 for Invalid Command if MMC card is connected

if(i++ > 50)
{
return 3;
}
} while( (status & R1_IN_IDLE_STATE) != 0 );



/////// ......ooo000ooo.....ooo000ooo/////// Aquí llega




// Set the SPI bus to full speed now that SD Card is initialized in SPI mode
SD_Disable();
SPIFastClock();

return 0;
}

// SD Card defaults to 512 byte block size
#define BLOCK_SIZE 512
unsigned char SD_ReadBlock(unsigned long addr, unsigned char *buf)
{
unsigned int i;
unsigned char status;

unsigned char CMD17_READ_SINGLE_BLOCK[] = {0x11,0x00,0x00,0x00,0x00,0xFF}; //antes 17 en decimal
CMD17_READ_SINGLE_BLOCK[1] = ((addr & 0xFF000000) >> 24);
CMD17_READ_SINGLE_BLOCK[2] = ((addr & 0x00FF0000) >> 16);
CMD17_READ_SINGLE_BLOCK[3] = ((addr & 0x0000FF00) >> 8);
CMD17_READ_SINGLE_BLOCK[4] = ((addr & 0x000000FF));

SD_Enable();

// Send the read command
status = SD_WriteCommand(CMD17_READ_SINGLE_BLOCK);
if(status != 0)
{
// ABORT: invalid response for read single command
return 1;
}

// Now wait for the "Start Block" token (0xFE)
// (see SanDisk SD Card Product Manual v1.9 section 5.2.4. Data Tokens)
do
{
status = SPIRead();
} while(status != 0xFE);

// Read off all the bytes in the block
for(i = 0; i < BLOCK_SIZE; ++i)
{
status = SPIRead();
*buf = status;
buf++;
}

// Read CRC bytes
status = SPIRead();
status = SPIRead();

SD_Disable();

// Following a read transaction, the SD Card needs 8 clocks after the end
// bit of the last data block to finish up its work.
// (from SanDisk SD Card Product Manual v1.9 section 5.1.8)
SPIWrite(0xFF);

return 0;
}

unsigned char buf[512];

unsigned char SD_WriteBlock(unsigned long addr, unsigned char *buf)
{
unsigned int i;
unsigned char status;

unsigned char CMD24_WRITE_SINGLE_BLOCK[] = {0x18,0x00,0x00,0x00,0x00,0xFF}; //antes 24
CMD24_WRITE_SINGLE_BLOCK[1] = ((addr & 0xFF000000) >> 24);
CMD24_WRITE_SINGLE_BLOCK[2] = ((addr & 0x00FF0000) >> 16);
CMD24_WRITE_SINGLE_BLOCK[3] = ((addr & 0x0000FF00) >> 8);
CMD24_WRITE_SINGLE_BLOCK[4] = ((addr & 0x000000FF));

SD_Enable();

// Send the read command
status = SD_WriteCommand(CMD24_WRITE_SINGLE_BLOCK);
if(status != 0)
{
// ABORT: invalid response for read single command
return 1;
}
    for(i=0;i<100;++i)
SPIRead();

// Now wait for the "Start Block" token (0xFE)
// (see SanDisk SD Card Product Manual v1.9 section 5.2.4. Data Tokens)
    //SPIWrite(0xFF);
    //SPIWrite(0xFF);
    SPIWrite(0xFE);



// Read off all the bytes in the block
for(i = 0; i < BLOCK_SIZE; ++i)
{   
        SPIWrite('Y');
/*status = SPIRead();
*buf = status;*/
//buf++;
}

    SPIWrite(0xFF);
    SPIWrite(0xFF);

while(SPIRead()!=0xFF);

SD_Disable();

// Following a read transaction, the SD Card needs 8 clocks after the end
// bit of the last data block to finish up its work.
// (from SanDisk SD Card Product Manual v1.9 section 5.1.8)
    SPIWrite(0xFF);

return 0;
}

int main (void)
{
unsigned int i, j;
ADPCFG = 0xFFFF; // Force all ADC pins as digital I/O

LED_DIR=0;
LED2_DIR=0;
    LED3_DIR=0;

InitSPI();
unsigned char status;
status = InitSD();

   
   
   /* do
{
//while(status)
//{
// status = InitSD();

//};
 LED = 1;
status = SD_ReadBlock(0, buf);
} while(status);*/


    //for(i=0;i<3;i++)
        //for(i=0;i<512;i++)
  // buf[i]='A';
SD_WriteBlock(0,buf);

SD_WriteBlock(512,buf);

//SD_WriteBlock(1024, buf);





    while(1) {
        for(i=0;i<20000;i++)
    {LED3=1;LED2=0;}
    for(i=0;i<20000;i++)
    {LED3=0;LED2=1;}
}

return 0;
}

Muchas gracias de antemano

Javio

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Problema con la RE-escritura en SD
« Respuesta #1 en: 20 de Junio de 2006, 01:46:30 »
Si te escribe bien sólo el primer bloque de 512 bytes, el problema debe estar relacionado con la forma en que finalizas la escritura. ¿Habrá que enviar algunos códigos de cierre o ejecutar algún proceso que dé por terminada la escritura?

Revisando el fuente, lo único que veo es esto:
// Following any command, the SD Card needs 8 clocks to finish up its work.
// (from SanDisk SD Card Product Manual v1.9 section 5.1.8)

Pero no veo que esperes esos 8 ciclos en ningún sitio. Quizás si pones delay_us(x) detrás de cada comando...

Desconectado astoroth_

  • PIC10
  • *
  • Mensajes: 20
Re: Problema con la RE-escritura en SD
« Respuesta #2 en: 20 de Junio de 2006, 11:38:25 »
Sí, tienes razón gracias, la historia es que no sirve con un delay normal, tiene que ser 8 ciclos del reloj SPI así que voy a probar a mandarle unas cuantas instrucciones SPI de paja:

SPIWrite(0xFF);

Muchas gracias, voy a probar.

Javio

Desconectado astoroth_

  • PIC10
  • *
  • Mensajes: 20
Re: Problema con la RE-escritura en SD
« Respuesta #3 en: 20 de Junio de 2006, 19:29:35 »
Nada, todo es ponerle ciclos de espera SPI (mediante instrucciones SPIRead() ) pero no se soluciona el problema. Lo que me inquieta es que he mirado unos 10 códigos similares y en todos está la función tal y como la he hecho yo. He mirado incluso sd.c del kernell de Linux y salvando las distancias arquitectónicas, sigue los mismos pasos que yo...

Saludos

Javio

Desconectado zer0

  • PIC12
  • **
  • Mensajes: 57
Re: Problema con la RE-escritura en SD
« Respuesta #4 en: 19 de Septiembre de 2006, 10:05:23 »
Hola soy al que antes conociais como zer007, estoy probando tu código y tengo varias dudas:

Estoy usando winhex con tu codigo he podido leer los primeros bytes de la SD y comprobar con el winhex que es correcto, pero en el momento de escribir no va (creo),  lo revisaré gracias por tu código y si consigo la fat32 y q funcione tu codigo lo publicaré.


« Última modificación: 19 de Septiembre de 2006, 11:51:11 por zer0 »