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:
- 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 )
- MódulodetarjetamicroSDCatalex.(similara:
enlace ) - 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.