Problema de lectura / escritura del bloque de la tarjeta SD en modo SPI. (STM32) (CMD17, CMD24)

2

Buen día,

Estoy usando un STM32F103C8T6 y estoy intentando conectar una tarjeta SD (tarjeta SanDisk Ultra de 16GB MicroSD HC) con ella. Sé que la tarjeta funciona bien porque puedo leer, escribir usando una PC y también funciona bien en un registrador de datos basado en AVR que construí (tanto arduino como no arduino). Sin embargo, me enfrento a un problema que hace lo mismo con mi configuración actual.

Detalles:

  1. Estoy usando una placa de desarrollo de sistema mínima STM32F103C8T6 genérica (a 72MHz). (Idéntico a la "píldora azul".) (Similar a: enlace )
  2. MódulodetarjetamicroSDCatalex.(similara: enlace )
  3. UnPCB(DIY)personalizadoparaalojarlaplacadedesarrolloylasconexionesaella.

EnelmóduloSD,omitíelbúfer,lasresistenciasdelcabledeseñal,quitéelreguladorLDOycortésuentradaysalida.Además,heconectadouncondensadorde100uFatravésdelaalimentaciónylaconexiónatierradelmóduloSD.Básicamente,soloseusaparaconectarlaslíneasdelastarjetasmicroSDalcontrolador.

EstoyutilizandoSTM32CubeMXparagenerarelcódigodeinicioeinicializaciónyusoKeilMDKv5.ElpindeseleccióndeesclavoSPIsecontrolamanualmenteenelcódigo.

Latarjetapareceinicializarsebien(másde74ciclosconSSdesactivado,CMD0,CMD1,CMD8,ACMD41,CMD58,CMD16).(Aunquelafuncióninittomaalgunosrecorridosy,porlotanto,secolocaenunbuclewhileenlafunciónprincipal).Lavelocidaddelrelojsemantieneen~140kHzatravésdelafuncióndeinicializaciónyseaumentaa~4.5MHzdespués.

LatarjetainclusorespondeconunarespuestaR1válidade0x00paraleerelcomandodebloqueúnico(CMD17).(Peronecesitaunretrasonotableparaunarespuestaválida).Sinembargo,elbytedeiniciodebloquededatos0xFEnuncallega.Ocasionalmente,capturaun0xFE,perocualquierlecturadedatosessolounaseriede0xFF,loquemellevaacreerqueesprobablequesoloseaunrelojperdidooalgoasícuandoselee.

LatarjetatambiénrespondeconunarespuestaR1válidade0x00paraescribiruncomandodebloqueúnico(CMD24)peronoseescribendatosdespuésdequeelbytedeiniciodelbloquededatosyunbloquededatosconCRCsetransmiten.

CMD58respondeconunarespuestaR1de0x00ylalecturaOCRtambiénessolo0x000x000x000x00.

Estoyescribiendomicódigodeinicialización,funcióndeenvíodecomandos,lecturadebloqueycódigodeescrituradebloque:

Inicialización:

uint8_tsd_ini(void){uint8_ti,cmd;int16_ttmr;LD_OFF;sdinfo.type=0;uint8_tocr[4];hspi2.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_256;//140.625kbpsHAL_SPI_Init(&hspi2);SS_SD_DESELECT();for(i=0;i<254;i++)//80toinitSD(74min){SPI_Release();}SS_SD_SELECT();//while(SD_cmd(CMD0,0)!=1);if(SD_cmd(CMD0,0)==1)//EnterIdlestate{SPI_Release();if(SD_cmd(CMD8,0x1AA)==1)//SDv2{for(i=0;i<4;i++){ocr[i]=SPI_ReceiveByte();}sprintf(str1,"OCR: 0x%02X 0x%02X 0x%02X 0x%02Xrn",ocr[0],ocr[1],ocr[2],ocr[3]);
            HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
            // Get trailing return value of R7 resp
            if (ocr[2] == 0x01 && ocr[3] == 0xAA) // The card can work at vdd range of 2.7-3.6V
            {
                  for (tmr = 12000; tmr && SD_cmd(ACMD41, 1UL << 30); tmr--); // Wait for leaving idle state (ACMD41 with HCS bit)
                    if (tmr && SD_cmd(CMD58, 0) == 0) 
                    { // Check CCS bit in the OCR
                        for (i = 0; i < 4; i++) 
                        {
                            ocr[i] = SPI_ReceiveByte();
                        }
                        sprintf(str1,"OCR: 0x%02X 0x%02X 0x%02X 0x%02X\r\n",ocr[0],ocr[1],ocr[2],ocr[3]);
                        HAL_UART_Transmit(&huart1,(uint8_t*)str1,strlen(str1),0x1000);
                        sdinfo.type = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; // SDv2 (HC or SC)
                    }

            }
        }
        else //SD v1
        {
            if (SD_cmd(ACMD41, 0) <= 1)
            {
                sdinfo.type = CT_SD1; cmd = ACMD41; // SDv1
            }
            else
            {
                sdinfo.type = CT_MMC; cmd = CMD1; // MMCv3
            }
            for (tmr = 25000; tmr && SD_cmd(cmd, 0); tmr--) ; // Wait for leaving idle state
            if (!tmr || SD_cmd(CMD16, 512) != 0) // Set R/W block length to 512
            {
                sdinfo.type = 0;
            }
        }
  }
  else
  {
    return 1;
  }
    i=SD_cmd(CMD16, 512);
    hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
    HAL_SPI_Init(&hspi2);
    return 0;
    //SPI_SendByte(0x35); //test
    //SPI_SendByte(0x53); //test

    //LD_OFF;
    //return sd_raw_init()? 0:1;

}

Comandos de envío:

static uint8_t SD_cmd (uint8_t cmd, uint32_t arg)
{
    uint8_t n, res;
    // ACMD<n> is the command sequense of CMD55-CMD<n>
    if (cmd == ACMD41)
    {
        cmd &= 0x7F;
        res = SD_cmd(CMD55, 0);
        if (res > 1) 
        {
            return res;
        }
    }

    // Select the card  
    SS_SD_DESELECT();
    SPI_ReceiveByte();
    SS_SD_SELECT();
    SPI_ReceiveByte();

    // Send a command packet

    SPI_SendByte(cmd); // Start + Command index
    SPI_SendByte((uint8_t)(arg >> 24)); // Argument[31..24]
    SPI_SendByte((uint8_t)(arg >> 16)); // Argument[23..16]
    SPI_SendByte((uint8_t)(arg >> 8)); // Argument[15..8]
    SPI_SendByte((uint8_t)arg); // Argument[7..0]

    n = 0x01; // Dummy CRC + Stop
    if (cmd == CMD0) {n = 0x95;} // Valid CRC for CMD0(0)
    if (cmd == CMD8) {n = 0x87;} // Valid CRC for CMD8(0x1AA)
    SPI_SendByte(n);
    if(cmd==CMD17||cmd==CMD24)
         HAL_Delay(50); //returns 0xFF otherwise

    n = 20; // Wait for a valid response in timeout of 10 attempts
    do 
    {
        res = SPI_ReceiveByte();
        n--;
    } while ((res & 0x80)&&n);
    /*SS_SD_DESELECT();
    SPI_ReceiveByte();
    SS_SD_DESELECT();
    SPI_ReceiveByte();
    SS_SD_SELECT();*/
   return res;
}

Bloque leído:

uint8_t SD_Read_Block (uint8_t *buff, uint32_t lba)
{
    uint8_t result;
    uint16_t cnt;
    if(!SPI_wait_ready()) 
    {
        return 0;
    }
    result=SD_cmd (CMD17, lba); //CMD17 datasheet pg 50,96
    if (result!=0x00)
    {
        return 5; //exit if result isxt 0x00
    }
    //SPI_Release();
    cnt=0;
    do
    { //Waiting for the beginning of the block
        result=SPI_ReceiveByte();
        cnt++;
    } while ( (result!=0xFE)&&(cnt<0xFFFF) );

    if (cnt>=0xFFFF)
    {
        return 5;
    }   
    for (cnt=0;cnt<512;cnt++)
    {
        buff[cnt]=SPI_ReceiveByte(); //get the bytes of the block from the bus to the buffer
    }
    SPI_Release(); //We omit the checksum
    SPI_Release();
    return 0;
    //return sd_raw_read(lba, buff, 1)?0:1;
}

Bloque de escritura:

 uint8_t SD_Write_Block (uint8_t *buff, uint32_t lba)
 {
   uint8_t result;
   uint16_t cnt;

   if(!SPI_wait_ready()) 
   {
        return 0;
   }
   result=SD_cmd(CMD24,lba); //CMD24 datasheet page 51 and 97-98
   if (result!=0x00)
   { 
        return 6;
   } //Exit if the result is not 0x00
   SPI_Release();
   SPI_SendByte (0xFE); //Beginning of the buffer
   for (cnt=0;cnt<512;cnt++)
   {
       SPI_SendByte(buff[cnt]); //Send data
   }
   SPI_Release(); //leave crc
   SPI_Release();
   result=SPI_ReceiveByte();
   if ((result&0x05)!=0x05)
   { 
         return 6;
   } //Exit if the result is not 0x05 (Datasheet pg 111)
   cnt=0;
   do 
   { //Waiting for the end of the state BUSY
       result=SPI_ReceiveByte();
       cnt++;
   } while ( (result!=0xFF)&&(cnt<0xFFFF) );
   if (cnt>=0xFFFF)
   { 
       return 6;
   }
   return 0;
   //return sd_raw_write(lba, buff, 1)?0:1;
}

Estoy en ingenioso final con este problema. ¿Algunas ideas? También hágamelo saber cualquier información adicional requerida.

    
pregunta DarkDD

1 respuesta

1

Mirando a la máquina de estado que diseñé hace un tiempo para la tarjeta micro-SD en modo SPI, veo la siguiente secuencia:

  • CMD0
  • CMD8
  • CMD55 + ACMD41 en bucle hasta que ACMD41 devuelva el éxito
  • CMD58
  • CMD16

Sin embargo, si CMD55 devuelve el error, voy a CMD1 intentando inicializar la tarjeta como tipo MMC.

Es difícil decir qué está sucediendo exactamente en su caso, pero creo que CMD1 no debe estar en este lugar en su lista de comandos que utilizó. Le recomiendo que estudie detenidamente esta excelente página web de ELM ChaN, que dice lo siguiente:

  

Debido a que se recomienda ACMD41 en lugar de CMD1 para SDC, probar ACMD41 primero y volver a intentar con CMD1 si es rechazado, es ideal para admitir ambos tipos de tarjetas.

Estás usando CMD1 y luego ACMD41, que es la secuencia incorrecta, y la tarjeta va a algún modo o está causando este comportamiento que describiste. Tampoco menciona el CMD55 anterior al ACMD41, espero que lo tenga en su lugar.

    
respondido por el Anonymous

Lea otras preguntas en las etiquetas