Modo de lectura / escritura sin formato de MicroSD. Después de que el sector escriba una vez, no puede escribir más sectores y leer siempre los 0

1

Estoy haciendo, por primera vez, la interfaz entre un microcontrolador (PIC32MX) y una tarjeta microSD a través de SPI. Las tarjetas que estoy usando se están inicializando correctamente. El tamaño del sector / bloque se fija en 512 bytes / sector porque solo usaré tarjetas SDHC y SDXC. Estoy escribiendo / escribiendo en la tarjeta, porque para mi aplicación no necesito un sistema de archivos, es un registrador de datos simple. Puedo verificar el contenido de los sectores de la tarjeta con el software "Hex Workshop Hex Editor". El reloj SPI se encuentra actualmente en 200 KHz para un punto de partida.

Tengo una función que escribe un sector completo y una función que lee un sector completo. He notado que si uso la función sector_write con CMD24 (WRITE_BLOCK) para al menos una vez (y funciona en la primera llamada, escribiendo el sector correctamente), las siguientes llamadas sector_write no funcionarán. Siempre veo 0 almacenados en el segundo sector en el que quiero escribir. En este ejemplo, estoy tratando de llenar el sector 1000 y 1300 con el mismo contenido, pero solo el sector 1000 se llena con ese contenido, y el sector 1300 se llena con 0 (en realidad es su contenido original). Además, he intentado escribir en una secuencia los sectores 1000 y 1001 y el resultado es el mismo (el sector 1001 no se llena con el mismo contenido del sector 1000).

Es decir, si llamo a la función sector_escritura una vez , la función de lectura devuelve lecturas de un sector lleno de 0 (incorrecto). Si comento todas las llamadas de write_sector, las lecturas se realizan correctamente.

Para el siguiente código, solo se escribe el sector 1000 ... todo el sector 1300 permanece en 0s. Este código está justo después de que la tarjeta se haya inicializado correctamente con las respuestas correctas de la tarjeta.

para la inicialización yo uso: | CMD0 | CMD8 | CMD58 | repitió CMD55 + ACMD41 | CMD58 |. No uso CMD16 ...

¿Qué puedo hacer para resolver esto? ¿Alguien aquí ya ha enfrentado este problema? Saludos.

if (SD_initialized == true) 
{
    write_reply = SD_write_sector(1000);
    DelayMs(1000);
    write_reply = SD_write_sector(1300);
}

uint8_t SD_command[6];
uint8_t SD_write_buff[512];
uint8_t SD_read_buff[512];

uint8_t n = 0;

for (i=0; i<512; i++) 
{
    SD_write_buff[i] = n;
    n++;
}

if (SD_initialized == true) 
{
    write_reply = SD_write_sector(1000);
    DelayMs(1000);
    write_reply = SD_write_sector(1300);
}

uint8_t SPI_write (uint8_t byte) 
{
    while(SPI1STATbits.SPITBF);
    SPI1BUF = byte;
    while(!SPI1STATbits.SPIRBF);
    return SPI1BUF;
}

uint8_t SD_write_sector (uint32_t sector)   //sector = block number
{
    uint8_t reply;
    uint32_t i;

    do
    {
        reply = SD_send_cmd (24, sector); 
    }
    while (reply != 0); 

    SPI_write(0xFF);                      //Dummy byte
    SPI_write(0xFE);                      //Data start token (0xFE)

    for(i=0; i<512; i++)                  //Data block
    {
        SPI_write(SD_write_buff[i]);
    }

    SPI_write(0xFF);                      //2 bytes of CRC
    SPI_write(0xFF);                   

    reply = SPI_write(0xFF);
    reply &= 0x1F;     // Response of SD: xxx0sss1
                       // sss = 010 ---> Data accepted = 0x05
                       // sss = 101 ---> Data rejected due to CRC error = 0x0B
                       // sss = 110 ---> Data rejected due to writing error = 0x0D

    return reply;
}

uint8_t SD_send_cmd (uint8_t CMD, uint32_t ARG)
{
    SD_command[0] = CMD + 0x40;                 
    SD_command[1] = ARG >> 24;                 
    SD_command[2] = ARG >> 16;                  
    SD_command[3] = ARG >> 8;                   
    SD_command[4] = ARG & 0xFF;                
    SD_command[5] = getCRC7 (SD_command, 5);    

    SPI_write (SD_command[0]);
    SPI_write (SD_command[1]);
    SPI_write (SD_command[2]);
    SPI_write (SD_command[3]);
    SPI_write (SD_command[4]);
    SPI_write (SD_command[5]);

    SD_reply1 = SPI_write(0xFF);                //dummy read
    SD_reply1 = SPI_write(0xFF);                //actual read

    if (CMD == 8 || CMD == 58) 
    {
        SD_reply2 = SPI_write(0xFF);
        SD_reply3 = SPI_write(0xFF);
        SD_reply4 = SPI_write(0xFF);
        SD_reply5 = SPI_write(0xFF);
    }

    return SD_reply1;
}

uint8_t SD_read_sector (uint32_t sector)
{
    uint8_t reply;
    uint32_t i;

    reply = SD_send_cmd (17, sector);
    if (reply != 0) { return reply; }

    while (SPI_write(0xFF) != 0xFE);  //SPI return read byte

    for (i=0;i<512;i++) 
    { 
        SD_read_buff[i] = SPI_write(0xFF);
    }

    SPI_write(0xFF);        //read 16-bit CRC
    SPI_write(0xFF);

    return reply;
}
    
pregunta abomin3v3l

2 respuestas

2

Para resolver el problema, acabo de agregar la siguiente línea al final de SD_write_sector() :

while (!SPI_write(0xFF));
O
while (SPI_write(0xFF) == 0);

Ahora todo funciona correctamente (escribe y lee).

uint8_t SD_write_sector (uint32_t sector)   //sector = block number
{
    uint8_t reply;
    uint32_t i;

    do
    {
        reply = SD_send_cmd (24, sector); 
    }
    while (reply != 0); 

    SPI_write(0xFF);                      //Dummy byte
    SPI_write(0xFE);                      //Data start token (0xFE)

    for(i=0; i<512; i++)                  //Data block
    {
        SPI_write(SD_write_buff[i]);
    }

    SPI_write(0xFF);                      //2 bytes of CRC
    SPI_write(0xFF);                   

    reply = SPI_write(0xFF);
    reply &= 0x1F;     // Response of SD: xxx0sss1
                       // sss = 010 ---> Data accepted = 0x05
                       // sss = 101 ---> Data rejected due to CRC error = 0x0B
                       // sss = 110 ---> Data rejected due to writing error = 0x0D

    **while (!SPI_write(0xFF));** <-----------------------------------
    OR
    **while (SPI_write(0xFF) == 0);**

    return reply;
}

Esta línea toma alrededor de 500us para ejecutarse con mi tarjeta microSD SanDisk de 8GB y 2.5ms con mi tarjeta Kingston de 4GB. Usé un pin IO para medir esos tiempos.

    
respondido por el abomin3v3l
1

No estoy seguro de lo que se espera de esto:

do
{
    reply = SD_send_cmd (24, sector); 
}
while (reply != 0);

¿Así que sigues enviando CMD24 en bucle? Debe enviarlo una vez y esperar la respuesta, evaluando la respuesta correctamente para ver por qué la tarjeta no devolvió 0x00.

También debe esperar a que el byte con el bit 7 distinto de cero llegue a SD_send_cmd en lugar de solo leer dos bytes y devolver el último. Por supuesto, el tiempo de espera es necesario para garantizar que el bucle no se bloquee si la tarjeta no responde, pero este tiempo de espera debe ser bastante largo.

Lo que sucede aquí es que el envío de CMD24 en bucle no recibe la respuesta correctamente, luego el envío de otro CMD24, etc., pero el comando de escritura puede soportar la selección de chips inactivos como sé, por lo que el comando de escritura aparece en progreso durante este bucle incorrecto.

    
respondido por el Anonymous

Lea otras preguntas en las etiquetas