Forum: Mikrocontroller und Digitale Elektronik STM32F10x - Problem mit SD Karte per SPI


von 4toTakoe (Gast)


Lesenswert?

Hi, ich benötige mal eure Hilfe,

Bin dabei eine SD(HC) Karte per SPI an den STM32f103 zu hängen. Genutzt 
wird ein Olimex P103 Board (zum testen).

Als Code-Basis dient fatfs von elm chan. Nun habe ich beim Debuggen 
folgendes problem: ohne Breakpoint gibt die Funktion send_cmd() nie den 
richtigen wert zurück. Wenn ich jedoch per Hand durch die Funktion 
springe, wird die Karte richtig angesprochen.

DSTATUS disk_initialize (
  BYTE drv    /* Physical drive number (0) */
)
{
  BYTE n, cmd, ty, ocr[4];
  int buff = 0;


  if (drv) return STA_NOINIT;      /* Supports only drive 0 */
  init_spi();              /* Initialize SPI */

  if (Stat & STA_NODISK) return Stat;  /* Is card existing in the soket? 
*/

//  FCLK_SLOW();
  for (n = 10; n>0; n--)
    xchg_spi(0xFF);  /* Send 80 dummy clocks */

  ty = 0;
  buff = send_cmd(CMD0, 0);
  if ((buff) == 1) {      /* Put the card SPI/Idle state */
    Timer1 = 1000;            /* Initialization timeout = 1 sec */
    if (send_cmd(CMD8, 0x1AA) == 1) {  /* SDv2? */
      for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);  /* Get 32 bit 
return value of R7 resp */
      if (ocr[2] == 0x01 && ocr[3] == 0xAA) {        /* Is the card 
supports vcc of 2.7-3.6V? */
        while (Timer1 && send_cmd(ACMD41, 1UL << 30)) ;  /* Wait for end 
of initialization with ACMD41(HCS) */
        if (Timer1 && send_cmd(CMD58, 0) == 0) {    /* Check CCS bit in 
the OCR */
          for (n = 0; n < 4; n++) ocr[n] = xchg_spi(0xFF);
          ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;  /* Card id 
SDv2 */
        }
      }
    } else {  /* Not SDv2 card */
      if (send_cmd(ACMD41, 0) <= 1)   {  /* SDv1 or MMC? */
        ty = CT_SD1; cmd = ACMD41;  /* SDv1 (ACMD41(0)) */
      } else {
        ty = CT_MMC; cmd = CMD1;  /* MMCv3 (CMD1(0)) */
      }
      while (Timer1 && send_cmd(cmd, 0)) ;    /* Wait for end of 
initialization */
      if (!Timer1 || send_cmd(CMD16, 512) != 0)  /* Set block length: 
512 */
        ty = 0;
    }
  }
  CardType = ty;  /* Card type */
  deselect();

  if (ty) {      /* OK */
//    FCLK_FAST();      /* Set fast clock */
    Stat &= ~STA_NOINIT;  /* Clear STA_NOINIT flag */
  } else {      /* Failed */
    Stat = STA_NOINIT;
  }

  return Stat;
}

Damit wird die Karte nie richtig erkannt -.-

Die SPI Schnittstelle meine ich jedoch richtig initialisiert zu haben:

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
  SPI_InitStructure.SPI_CRCPolynomial = 0;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_Init(SPI2, &SPI_InitStructure);
  SPI_Cmd(SPI2, ENABLE);

Auf dem Oszi sieht man jedoch wie die Karte angesprochen wird und auch 
antwortet.

Ich hoffe das genügt erstmal um den Sachverhalt zu verdeutlichen. Hat 
schon mal jemand so ein ähnliches Problem gehabt?

Danke schonmal für sachdienliche Hinweise. Ahoi

von Grundschüler (Gast)


Lesenswert?

4toTakoe schrieb:
> SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
>   SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

könnte der Fehler sein

von Dirk K. (dekoepi)


Lesenswert?

Polarität/Phase ist bei SPI wichtig. Ein deutliches Anzeichen, dass man 
das genau falsch eingestellt hat, ist: Wenn man ganz langsam macht, 
funktioniert es, schneller jedoch nicht.

Wie Grundschüler schrieb: SPI_CPHA_1EDGE und SPI_CPOL_Low verwenden, 
schon sollte das klappen.

von 4toTakoe (Gast)


Lesenswert?

Jo danke ;)

Damit komme ich zumindest weiter. Habe die SPI Einstellungen nun 
korrigiert auf:

  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
  SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
  SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  SPI_Init(SPI2, &SPI_InitStructure);

Die Karte wird auch richtig erkannt bis zu dieser Stelle aus obiger 
Funktion:

  if (!Timer1 || send_cmd(CMD16, 512) != 0)  /* Set block length: 512 */
    ty = 0;

Da tritt vorherige Phänomen wieder auf. D.h. wenn ich manuell durch die 
if bzw. send_cmd() springe, wird die karte richtig erkannt und ty wird 
nicht auf 0 gesetzt.

Ich werde mal noch etwas mit dem takt spielen bzw. ein paar andere 
Karten versuchen. Aber irgendwie ist hier der Wurm drin...

von Grundschüler (Gast)


Lesenswert?

prüfen, ob die sd-timer laufen

von 4toTakoe (Gast)


Lesenswert?

Nochmal danke für eure Hilfe. Im Endeffekt lag es an etwas anderem.

Der Vollständigkeit halber:

ChaN schreibt in seiner Lib direkt auf die Register des Controllers. 
Irgendwie mag das entweder der aktuelle Compiler oder CooCox nicht oder 
nur teilweise verstehen.

In der Funktion xchg_spi() fehlen die assert_param(SPIx) geschichten 
damit es ordentlich funktioniert. Oder man nutzt die Standard-SPI Lib. 
Das sieht dann so aus:
1
/* Exchange a byte */
2
static
3
BYTE xchg_spi (
4
  BYTE dat  /* Data to send */
5
)
6
{
7
  /* Send byte through the SPI peripheral */
8
  SPI_I2S_SendData(SPI2, dat);
9
  /* Wait to receive a byte */
10
  while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) { ; }
11
  /* Return the byte read from the SPI bus */
12
  return SPI_I2S_ReceiveData(SPI2);
13
}

Nachdem ich mir damit jetzt einen abgequält habe läuft es sauber mit 
sämtlichen SD karten.

Schönen Tag allen noch ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.