Guten Tag,
Ich verwende einen STM32F103C8T6 und versuche, eine SD-Karte (SanDisk Ultra 16 GB MicroSD HC-Karte) damit zu verbinden. Ich weiß, dass die Karte gut funktioniert, weil ich mit einem PC lesen und schreiben kann und sie funktioniert auch gut auf einem AVR-basierten Datenlogger, den ich gebaut habe (sowohl Arduino als auch Nicht-Arduino). Ich habe jedoch ein Problem mit meinem aktuellen Setup.
Einzelheiten:
Im SD-Modul habe ich den Puffer, die Signalleitungswiderstände umgangen, den LDO-Regler entfernt und seinen Ein- und Ausgang kurzgeschlossen. Zusätzlich habe ich einen 100uF-Kondensator zwischen Strom und Masse des SD-Moduls angeschlossen. Verwenden Sie es im Grunde nur, um die Leitungen der microSD-Karte mit dem Controller zu verbinden.
Ich verwende STM32CubeMX, um den Start- und Initialisierungscode zu generieren, und verwende Keil MDK v5. Der SPI-Slave-Select-Pin wird manuell im Code gesteuert.
Die Karte scheint gut zu initialisieren (74+ Zyklen mit deaktiviertem SS, CMD0, CMD1, CMD8, ACMD41, CMD58, CMD16). (Obwohl die Init-Funktion einige Durchläufe benötigt und daher in einer While-Schleife in der Main-Funktion platziert wird). Die Taktfrequenz wird während der gesamten Initialisierungsfunktion auf ~140 kHz gehalten und danach auf ~4,5 MHz erhöht.
Die Karte antwortet sogar mit einer gültigen R1-Antwort von 0x00 auf den Lese-Einzelblock-Befehl (CMD17). (Benötigt aber eine merkliche Verzögerung für eine gültige Antwort). Das Datenblock-Startbyte 0xFE kommt jedoch nie an. Gelegentlich wird ein 0xFE abgefangen, aber alle gelesenen Daten sind nur eine Reihe von 0xFF, was mich zu der Annahme veranlasst, dass es sich beim Lesen wahrscheinlich nur um eine verpasste Uhr oder etwas Ähnliches handelt.
Die Karte antwortet auch mit einer gültigen R1-Antwort von 0x00 auf den Befehl zum Schreiben eines einzelnen Blocks (CMD24), aber nach dem Datenblock-Startbyte werden keine Daten geschrieben und ein Datenblock mit CRC wird übertragen.
CMD58 antwortet mit einer R1-Antwort von 0x00 und die OCR-Anzeige ist auch nur 0x00 0x00 0x00 0x00.
Ich schreibe meinen Initialisierungscode, Befehlssendefunktion, Blocklese- und Blockschreibcode auf:
Initialisierung:
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;
}
Befehle senden:
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;
}
Lesen blockieren:
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;
}
Schreiben blockieren:
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;
}
Ich bin mit diesem Thema am Ende. Irgendwelche Ideen? Lassen Sie mich auch wissen, welche zusätzlichen Informationen erforderlich sind.
Wenn ich auf die Zustandsmaschine schaue, die ich vor einiger Zeit für Micro-SD-Karten im SPI-Modus entworfen habe, sehe ich die folgende Sequenz:
Wenn CMD55 jedoch einen Fehler zurückgibt, gehe ich zu CMD1 und versuche, die Karte als MMC-Typ zu initialisieren.
Es ist schwer zu sagen, was genau in Ihrem Fall passiert, aber ich denke, CMD1 darf nicht an dieser Stelle in Ihrer Liste der von Ihnen verwendeten Befehle stehen. Ich empfehle Ihnen, diese hervorragende Webseite von ELM ChaN gründlich zu studieren , auf der Folgendes steht:
Da ACMD41 anstelle von CMD1 für SDC empfohlen wird, ist es ideal, zuerst ACMD41 zu versuchen und es bei Ablehnung mit CMD1 erneut zu versuchen, um beide Kartentypen zu unterstützen.
Sie verwenden CMD1 und dann ACMD41, was die falsche Reihenfolge ist, und die Karte wechselt in einen Modus oder verursacht dieses von Ihnen beschriebene Verhalten. Sie erwähnen CMD55 auch nicht vor ACMD41, ich hoffe, Sie haben es an Ort und Stelle.
brhans
DarkDD
DarkDD