Buen día,
Estoy usando un STM32F103C8T6 e intento conectar una tarjeta SD (tarjeta SanDisk Ultra 16GB MicroSD HC) con él. 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, tengo un problema al hacer lo mismo con mi configuración actual.
Detalles:
En el módulo SD, pasé por alto el búfer, las resistencias de cable de señal, eliminé el regulador LDO y cortocircuité su entrada y salida. Además, he conectado un condensador de 100 uF a través de la alimentación y la tierra del módulo SD. Básicamente, simplemente usándolo para conectar las líneas de tarjetas microSD al controlador.
Estoy usando STM32CubeMX para generar el código de inicio e inicialización y uso Keil MDK v5. El pin de selección de esclavo SPI se controla manualmente en código.
La tarjeta parece inicializarse bien (más de 74 ciclos con SS desactivado, CMD0, CMD1, CMD8, ACMD41, CMD58, CMD16). (Aunque la función init requiere algunas ejecuciones y, por lo tanto, se coloca en un bucle while en la función principal). La velocidad del reloj se mantiene en ~140 kHz durante la función de inicialización y aumenta a ~4,5 MHz después.
La tarjeta incluso responde con una respuesta R1 válida de 0x00 para leer un comando de bloque único (CMD17). (Pero necesita un retraso notable para una respuesta válida). Sin embargo, el byte de inicio del bloque de datos 0xFE nunca llega. Ocasionalmente detecta un 0xFE, pero cualquier lectura de datos es solo una serie de 0xFF, lo que me lleva a creer que probablemente sea solo un reloj perdido o algo así cuando se lee.
La tarjeta también responde con una respuesta R1 válida de 0x00 para escribir un comando de bloque único (CMD24), pero no se escribe ningún dato después del byte de inicio del bloque de datos y se transmite un bloque de datos con CRC.
CMD58 responde con una respuesta R1 de 0x00 y la lectura de OCR también es solo 0x00 0x00 0x00 0x00.
Estoy escribiendo mi código de inicialización, función de envío de comandos, lectura de bloque y código de escritura de bloque:
Inicialización:
uint8_t sd_ini(void)
{
uint8_t i,cmd;
int16_t tmr;
LD_OFF;
sdinfo.type = 0;
uint8_t ocr[4];
hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; //140.625kbps
HAL_SPI_Init(&hspi2);
SS_SD_DESELECT();
for(i=0;i<254;i++) //80 to init SD (74 min)
{
SPI_Release();
}
SS_SD_SELECT();
// while (SD_cmd(CMD0, 0) != 1);
if(SD_cmd(CMD0, 0) == 1)// Enter Idle state
{
SPI_Release();
if (SD_cmd(CMD8, 0x1AA) == 1) //SD v2
{
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;
}
Envío de comandos:
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 de lectura:
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;
}
Escritura en bloque:
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 el ingenio final con este problema. ¿Algunas ideas? También déjame saber cualquier información adicional requerida.
Mirando la máquina de estado que diseñé hace algún tiempo para la tarjeta micro-SD en modo SPI, veo la siguiente secuencia:
Sin embargo, si CMD55 devuelve un error, busco CMD1 para intentar 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 a fondo 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 se rechaza, es ideal para admitir ambos tipos de tarjetas.
Está utilizando CMD1 y luego ACMD41, que es la secuencia incorrecta, y la tarjeta pasa a algún modo o provoca este comportamiento que describe. Tampoco menciona CMD55 antes de ACMD41, espero que lo tenga en su lugar.
brahans
oscuroDD
oscuroDD