Fehler beim Initialisieren der microSD-Karte im SPI-Modus

Ich versuche, eine 32-GB-microSD-Karte über SPI-Kommunikation mit PIC32MX795F512L zu verbinden . Die SPI-Kommunikation funktioniert einwandfrei, da ich sie getestet habe, indem ich die Dateneingangs- und -ausgangsleitung kurzgeschlossen und die von mir gesendeten Daten zurückerhalten habe. Ich folge den Beispielen in Lucio de Jasios Buch Programming 32-bit Microcontrollers in C .

Folgende Aufgaben übernehme ich:

1. Initializing the SPI Communication in initSPI(), setting the baudrate=76 (250 kHz)
2. Initializing the SD card
   -> CS = 1
   -> Sending 80 clock cycles to wake the card
   -> CS = 0
   -> Sending CMD0 command (0x40, 0x00, 0x00, 0x00, 0x00, 0x95)

Aber das Problem ist, dass ich keine R1Antwort von der Karte erhalte, sondern die 0xFF. Nachfolgend der Code:

#define FCY 77000000UL
#define FPB (FCY/2)
#define BAUDRATE    9600
#pragma config POSCMOD=HS,FNOSC=PRIPLL
#pragma config FPLLIDIV=DIV_3, FPLLMUL=MUL_21, FPLLODIV=DIV_1
#pragma config FPBDIV=DIV_2, FWDTEN=OFF

#include <stdio.h>
#include <stdlib.h>
#include <plib.h>
#include <stdbool.h>

#define SDI  _RC4
#define SDCS _RA9
#define enableSD()    SDCS = 0
#define disableSD()   SDCS = 1
#define readSPI() writeSPI(0xFF)

int main(int argc, char** argv)
{
    TRISAbits.TRISA9 = 0;   // CS as output
    TRISCbits.TRISC4 = 1;   // SDI as input
    TRISDbits.TRISD0 = 0;   // SDO as output
    TRISDbits.TRISD10 = 0;  // SCK as output
    AD1PCFG = 0xFFFF;
    DDPCONbits.JTAGEN = 0;
    OpenUART1( UART_EN | UART_NO_PAR_8BIT | UART_1STOPBIT, UART_RX_ENABLE | UART_TX_ENABLE, (FPB/16/BAUDRATE)-1 );
    disableSD(); //CS PIN INITIALLY HIGH TO DISABLE CARD
    initSPI();
    initSD();

    while(1)
    {

    }
    return (EXIT_SUCCESS);
}

void initSPI( void)
{
    SPI1BRG = 76; // FPB/154=250KHZ; (76+1)*2 = 154, so brg = 76
    SPI1CONbits.MSTEN = 1; // MasterEnable
    SPI1CONbits.CKE = 1;   // CKE on
    SPI1CONbits.ON = 1;    // SPI Module ON
}

unsigned char writeSPI(unsigned int b)
{
    SPI1BUF=b; // Write to buffer for TX
    while( !SPI1STATbits.SPIRBF)
        ; // Wait transfer complete
    return(SPI1BUF);
}

int initSD(void)
{
    int i,r,rx;
    int data;

    // Step1: Disable SD card
    disableSD();

    // Step2: Send 80 clock cycles to wake up the card
    for(i=0; i<=9; i++)
    {
        data = writeSPI(0xFF);
    }

    // Step3: Enable SD card
    enableSD();

    // Step4: Send CMD0 command to RESET
    r = sendCMD0();
    disableSD();
    if(r!=1)
    {
        putsUART1("CMD reject\n");
    }
}

int sendCMD0()
{
    int i,r;
    enableSD();

    writeSPI(0x40);
    writeSPI(0x00);
    writeSPI(0x00);
    writeSPI(0x00);
    writeSPI(0x00);
    writeSPI(0x95); //CMD0 Command

    for( i=0; i<100; i++)
    {
        r = readSPI();
        if ((r & 0x80) == 0)
            break;
    }
    return ( r);
}

Hier ist das Schema :

Die Schaltpläne

Ich erhalte keine R1Antwort. Es bleibt bei step4 in hängen initSD().

Kann ich nach dem Senden von 80 Taktimpulsen feststellen, ob die Karte aufgewacht ist oder nicht? Nach 80 Taktimpulsen lautet die Antwort der Karte 0xFF.

Muss ich die Taktfrequenz reduzieren? Derzeit sind es 250 kHz.

Warum wird die Karte nicht initialisiert? Wie kann ich es reparieren?

Sie könnten mit meiner Bibliothek auf Github ( Header , Code ) vergleichen und sehen, was die Unterschiede sind. Ich habe eine anständige Anzahl von Karten getestet, um Grenzfälle auszuarbeiten.
Ich werde nach der Referenz suchen (habe sie gestern nicht gesehen), aber soweit ich mich erinnere, benötigen SdCards eine kräftige Entkopplungskappe - 10 uF // 100 nF in der Nähe des Halters. Googlen Sie den folgenden "Entkopplungskondensator für SdCard". Sie müssen wahrscheinlich nicht weiter als bis zur Google-Seite gehen :-)
Vielleicht möchten Sie sich < microchip.com/forums/m530149.aspx > ansehen , das Code in C für den Zugriff auf den Chip im SPI-Modus enthält. Es ist viel zu lang, um es als Antwort zu posten, oder ich würde es als Antwort posten.
@user3629249 kannst du den Link bitte nochmal teilen. Da steht interner Serverfehler
Hast du eine andere Karte probiert? Befreien Sie sich auch von allen ints. Verwenden Sie überall unsigned char oder uint8_t. Lassen Sie den UART auch die zurückgegebenen Werte von r drucken, damit wir sehen können, was los ist.

Antworten (2)

Ich sehe keinen Code, um den MISO-Pin zu einem Eingangs-Pin zu machen oder den SCK-Pin-Ausgang zu machen. Da Sie die SPI-Bibliothek in nicht verwenden plib, müssen Sie die gesamte Pin-Initialisierung selbst durchführen. Erhöhen Sie außerdem nach dem Senden CMD0die Anzahl der Iterationen (in Ihrer forSchleife) von 8 auf 20 (ich verwende 100), um genügend Spielraum zu haben. Verwenden Sie stattdessen auch diesen Vergleich:

if ((r & 0x80) == 0) 
   break;
return r;

rMachen Sie auch unsigned charüberall.

Ohh danke, dass du das vorgeschlagen hast. Ich dachte, nach der Initialisierung des SPI werden alle SDO-SDI-Sck automatisch konfiguriert. Jetzt mache ich SDO & SCK-Ausgabe und SDI als Eingabe.
Warum verwenden Sie diese if-Bedingung: if ((r & 0x80) == 0). Können Sie ein bisschen erklären.
Das erste Bit der Antwort der SD-Karte ist immer eine Null. Man muss also das erste Bit jedes empfangenen Bytes auf eine Null prüfen. Ihr ursprünglicher Code macht ungefähr dasselbe wie meiner, aber ich benutze meinen seit einiger Zeit mit PICs, also denke ich, dass meiner zuverlässiger ist :)
uint8_twäre besser als unsigned char.
Ich habe Ihre if-Bedingung verwendet, aber die Karte antwortet nicht mit 0x01. Gibt es einen Fehler in meinen Funktionen zum Übertragen von Daten? Kannst du es dir bitte anschauen. Gibt es einen anderen Befehl, den ich vor CMD0 senden kann, um andere Dinge zu überprüfen?
Können Sie den Code in Ihrer Frage aktualisieren? Nachdem Sie alle Pin-Inits durchgeführt haben?
@TisteAndii Ich habe meinen Code aktualisiert.
Ändern Sie alle Ihre ints zu uint8_t. Setzen Sie explizit SPICON1bits.CKP = 0.
Setzen Sie außerdem SPI1CON = 0 oben in init_spi(). Und dann versuchen Sie es mit einer anderen SD-Karte. Keine andere Idee hier :(
Okay, ich setze SPI1CON =0 und werde es damit versuchen. Danke
Und nehmen Sie die Typänderungen und die CKP-Zuweisung vor
@TisteAndii Ich bin nicht so sehr Experte in der SD-Kartenprogrammierung, aber wenn wir das SPI-Modul initialisieren, werden alle relativen Pins automatisch konfiguriert.!
Nur wenn Sie die peripheren Bibliotheken verwenden. Die werden hier nicht verwendet. Untersuchen Sie open_spi.c in der plib und Sie werden dort die gleichen Pinbelegungen sehen. Hier wird plib nicht für SPI verwendet

Sieht oberflächlich nach einem elektrischen Problem aus

  • Versuchen Sie zum Starten eine langsamere Geschwindigkeit – möglicherweise haben Sie eine übermäßige Kapazität in Ihren Leitungen oder eine langsame SD-Karte.
  • Rufen Sie ab, bis die Karte fertig ist (siehe unten)
  • Können Sie ein Zielfernrohr darauf setzen, um die Timings zu überprüfen, diese sind kritisch?
  • Probieren Sie eine andere SD-Karte oder dieselbe Karte in einem funktionierenden Gerät aus
  • Können Sie auf demselben Gerät an einem anderen Port senden und empfangen?
  • Können Sie mit demselben PIC-Gerät auf einer anderen Karte senden und empfangen?
  • Verwenden Sie Mikrochiptreiber / Softwarebibliotheken?
  • Hast du MISO/MOSI richtig verkabelt?
  • Sind die Leistungsanforderungen erfüllt - Entkopplungskappen etc? 10uF+//100nF (einige Leute verwenden 100uF!!)
  • Sind Ihre Ausgangs- und Eingangspins richtig konfiguriert?

Zu einem späteren Zeitpunkt müssen Sie möglicherweise Folgendes überprüfen - keine bestimmte Reihenfolge.

  • Überprüfen Sie die "Endianness" Ihres SPI
  • Überprüfen Sie Ihren CRC
  • Überprüfen Sie Ihr Protokoll

https://www.sdcard.org/downloads/pls/simplified_specs/archive/part1_110.pdf

Seite 47 sagt, dass Sie das Gerät abfragen müssen, bis die Karte bereit ist. Tun Sie das?

Ich verwende 250KHZ, werde es auf jeden Fall mit langsamerer Geschwindigkeit versuchen. Meine Micro-SD-Karte ist 32 GB Klasse 10 und funktioniert gut. PIC32 funktioniert auch gut, ich habe viele andere Programme darauf gemacht. Ich verwende keine Mikrochip-Bibliotheken und ja, MISO MOSI-Leitungen sind korrekt verdrahtet. Ich denke, wir müssen nur die CS-Linie manuell einstellen und der Rest der Linien wird automatisch eingestellt. Ich habe auch den Schaltplan hochgeladen. Bitte werfen Sie einen Blick darauf. Ich habe es nicht verstanden Check the 'endianness', kannst du es mir bitte kurz erklären
Endianness ist der Jargon für "senden Sie zuerst MSB oder zuerst LSB". Überprüfen Sie vielleicht Ihren Hardware-/Pin-Init-Code mit dem in den Mikrochip-Bibliotheken angegebenen. Die meiste meiner Arbeit ist mit ARM, daher kann ich leider nicht mit PIC-Besonderheiten für Pin-Geschwindigkeit, Pullup/Pulldown usw. helfen. Versuchen Sie es mit einer Verzögerung nach dem Einstellen der CS-Leitung.
Sie wollen damit sagen, dass ich nach step1 in initSD() eine Verzögerung hinzufügen sollte
@ user007 ja, und pollen Sie es, bis es in Intervallen von <50 ms bereit ist. siehe meine Bearbeitungen
Ich rufe nicht ab, sondern habe auf eine Antwort gewartet, die eine Verzögerung von bis zu 8 Bytes zulässt. Ich werde es abfragen, bis seine Antwort 0x01 ist. Danke
Gibt es nach dem Senden von 80 Taktimpulsen eine Antwort von der Karte?
Der von mir verwendete Treiber wartet nach dem Einschalten (Chipauswahl) 1 ms und sendet dann CMD8, CMD55, CMD41. Es wird empfohlen, < 24 MHz zu verwenden, es sei denn, Sie führen eine „Hochgeschwindigkeitsumschaltung“ durch. Dies ist der SDIO (4 Bit)-Modus. Polling ist in den CMDs