Forum: Mikrocontroller und Digitale Elektronik SD - Card antwortet nicht


von Klaus P. (phoenix89)


Lesenswert?

Hallo Leute,

ich versuche eine SD-Karte über SPI anzusteuern. uC (Atmega32) hängt an 
einem 4Mhz Quarz. SPI Clock liegt bei 250kHz. Für den Fall, dass die 
SD-Card nicht mit dem antwortet, was ich erwarte bzw. garnicht 
antwortet, schreibt der uC mir den Response mit einer 1 als MSB auf mein 
LCD (MSB sollte eigentlich immer 0 sein). Auf dem LCD landet eine 128, 
also gibt SD_Command eine 0 zurück. Das sollte nur passieren, wenn die 
SD Karte garnicht antwortet.

- Pegel an der SD-Card stimmen (3,3V und 0V)
- Anschluss des SPI über kleine Kabel ~17cm (schon zu lang?)
- x-Mal richtigen Anschluss geprüft.
- /SS Pin als Output
- keine Warnungen / Fehler des Compilers (avr-gcc mit Atmel Studio 4)

Hat jemand eine gute Idee (ich nehm auch ne blöde - wenns klappt ;) ), 
woran es liegen könnte?

Hier der Code (eigentlich schön in Header und C-Files ausgegliedert)
1
#include <stdint.h>
2
#include <avr/io.h> 
3
#include <string.h>  
4
#include <avr/interrupt.h>
5
#include <util/delay.h> 
6
7
uint8_t Flags;
8
unsigned char SD_Buffer[16];
9
uint8_t Temp; 
10
11
// PINS
12
#define CS          (1<<PD7)  
13
#define CS_DDR       DDRD
14
#define CS_ENABLE()   (PORTD &= ~CS)
15
#define CS_DISABLE()   (PORTD |= CS)
16
17
// SD-CARD Commands       0b01xxxxxx
18
#define _SD_IDLE       0x40  //0b01000000 - GO-IDLE-STATE
19
#define _SD_Init       0x41  //0b01000001 - Initialize
20
#define _SD_Set_Blocklenght  0x50  //0b01010000 - Set Block lenght
21
#define _SD_Read_Block    0x51  //0b01010001 - Read one Block
22
23
#define SS      (1<<PB4)
24
#define MOSI       (1<<PB5)
25
#define MISO       (1<<PB6)
26
#define SCK       (1<<PB7)  
27
#define SPI_DDR      DDRB
28
29
void SPI_Init(){
30
  // MOSI, /SS and SCK -> Output; MISO -> Input
31
  SPI_DDR = (1<<MOSI)|(1<<SCK)|(1<<SS);
32
  SPI_DDR &= ~(1<<MISO);
33
34
  // Enable SPI, Master, set clock rate
35
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1);
36
}
37
38
unsigned char SPI_Write(unsigned char ch){
39
  // write on SPI
40
    SPDR = ch;
41
  // wait for Flag
42
    while(!(SPSR & (1<<SPIF)))  
43
  // return DataRegister    
44
    return SPDR;
45
}
46
47
uint8_t SD_Init(){
48
  uint8_t i, a;
49
  a=0;
50
51
  // Deselect SD-Card
52
  CS_DISABLE();
53
  // Give the SD-Card some time to initialize
54
  for (i=0; i<10; i++)
55
    SPI_Write(0xFF);
56
57
  // GO-IDLE-STATE - Try 10 Times
58
  for (i=0; i<10 && (a = SD_Command(_SD_IDLE, 0x00000000, 0x95, 8)) != 1; i++)
59
    _delay_ms(100);
60
  if (i==10)  // Card did not response
61
    return a + 0x80;
62
63
  // Initialize!
64
  for (i=0; i<10 && (a = SD_Command(_SD_Init, 0x00000000, 0xFF, 8)) != 1; i++)
65
    _delay_ms(100);
66
  if (i==10)  // Card did not come out of idle
67
    return a;
68
69
  // Set Block length 512
70
  SD_Command(_SD_Set_Blocklenght, 0x00000200, 0xFF, 8);
71
        
72
    SD_sector = SD_pos = 0;
73
        
74
    return 0;
75
}
76
77
uint8_t SD_Command(uint8_t cmd, uint32_t arg, uint8_t crc, uint8_t read){
78
  //
79
  uint8_t i, buffer[32], resp = 0;
80
81
  // Be my Slave! :D
82
  CS_ENABLE();
83
  _delay_ms(1);
84
85
86
  SPI_Write(cmd);
87
  SPI_Write(arg>>24);
88
  SPI_Write(arg>>16);
89
  SPI_Write(arg>>8);
90
  SPI_Write(arg);
91
  SPI_Write(crc);
92
93
  for(i=0; i<read; i++)
94
        buffer[i] = SPI_Write(0xFF);
95
96
  // Bye!
97
  CS_DISABLE();
98
99
  // response isnt 0xFF, so wait until something else is send
100
  for(i=0; i<read; i++) {
101
    if(buffer[i] != 0xFF)
102
      resp = buffer[i];
103
  }
104
105
  // Return the response
106
  return resp;
107
}
108
109
int main (void){
110
  // Zeit zum starten geben
111
  _delay_ms(10);
112
  // PORTS  
113
  // DDRx = 0 -> I, = 1 -> O        
114
  DDRD   =   (1<<PD7);
115
  // PORTx= 1 -> Pull-Up bzw. Output high  
116
  
117
  // I2C, SPI, SD
118
  I2C_Init();
119
  SPI_Init();
120
121
  // LCD
122
  LCD_Init();
123
  LCD_Light(1);    
124
  // Menu
125
  //gt_Main();
126
127
  // Systemzeit initialisieren
128
  Timer0_Sys_Clock();
129
130
  // globale Interrupts aktivieren
131
  sei();
132
133
  // Test der SD Karte
134
  
135
  Temp = SD_Init();
136
  my_utoi(Temp, 4, SD_Buffer);
137
  LCD_Cursor(8, 2);
138
  lcd_string(&SD_Buffer);
139
140
  // Hauptschleife
141
  while(1){
142
     }
143
     return 0;
144
}

von S. Landolt (Gast)


Lesenswert?

> #define SS      (1<<PB4)
> #define MOSI       (1<<PB5)
> #define MISO       (1<<PB6)
> #define SCK       (1<<PB7)
> #define SPI_DDR      DDRB
>  SPI_DDR = (1<<MOSI)|(1<<SCK)|(1<<SS);
>  SPI_DDR &= ~(1<<MISO);

Diese Konstruktion verstehe ich nicht, da wird doch doppelt geschoben, 
oder?

von Klaus P. (phoenix89)


Lesenswert?

Das sind genau die Antworten die ich haben will :D
Ist wie mit Rechtschreibfehlern in seinem eigenem Text - man sieht die 
offensichtlichen Sachen nicht.. Keine Ahnung was ich da wollte ;)
Ich probiers mal aus! Danke

von Klaus P. (phoenix89)


Lesenswert?

Klappt mit
1
void SPI_Init(){
2
  // MOSI, /SS and SCK -> Output; MISO -> Input
3
  SPI_DDR = MOSI|SCK|SS;
4
  SPI_DDR &= ~(MISO);
5
6
  // Enable SPI, Master, set clock rate
7
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1);
8
}

leider immer noch nicht :(

von Falk B. (falk)


Lesenswert?

@  Klaus Peter (phoenix89)


>leider immer noch nicht :(

Betreibe eine systematische Fehlersuche. Erstmal muss deine SPI 
Daten, Takt, und SS ausspucken, egal ob die Karte reagiert oder nicht. 
Prüfe das mit einem Oszi oder Logic Analyzer. Dann geht es weiter.

>Hier der Code (eigentlich schön in Header und C-Files ausgegliedert)

Warum kopierst du das dann zusammen anstatt sinnvollerweise die 
einzelnen Dateien als Anhang zu senden? Siehe Netiquette.

von Jim M. (turboj)


Lesenswert?

Versuche mal eine der vorhandenen Libs für SD Karten an Deine 
Pinbelegung anzupassen, das wird einfacher sein. Die Ansteuerung ist 
nicht ganz trivial,
und Deine Kommandos funktionieren spätestens bei SDHC Karten so nicht 
mehr.

Deine SD_Command() Funktion würde IMHO im Zweifelsfalle wichtige 
Antwortbytes verschlucken, z.B. beim Lesen von Registern.

von Reto W. (Firma: Swissbit.com) (swissbit)


Lesenswert?

1
 
2
for(i=0; i<read; i++)
3
        buffer[i] = SPI_Write(0xFF);
4
5
  // Bye!
6
  CS_DISABLE();
7
8
  // response isnt 0xFF, so wait until something else is send
9
  for(i=0; i<read; i++) {
10
    if(buffer[i] != 0xFF)
11
      resp = buffer[i];
12
  }
Der part ist wohl Fehlerhaft. Die Karte muss die Response nicht sofort 
nach dem Command schicken. Es wird aber direkt angefangen die Anzahl 
bytes von "read" zu lesen, ohne zu prüfen ob die Karte tatsächlich Daten 
schickt. Danach wird die Karte unselektiert, der untere Code bewirkt 
also nichts mehr.

Ein korrektes CMD 0 sollte indes ausreichen.

Nachtrag: Habs nochmal angeguckt und jetzt kapiert was hier passieren 
soll.
Bei welchem Command bekommst du denn die Response 0, wo genau bleibt es 
hängen? Response 0 bedeutet eigentlich "OK".
a = SD_Command(_SD_Init, 0x00000000, 0xFF, 8)) != 1

SD_Init bzw. CMD1 SEND_OP_CMD wird dir eine response 01 zurück liefern 
solange die Karte beschäftigt ist, sobald sie bereit für weitere 
Commands ist wird sie eine Response 00 Antworten.
Gruss

: Bearbeitet durch User
von Klaus P. (phoenix89)


Lesenswert?

Danke für die Antworten.

Habs nun in
1
...
2
  // GO-IDLE-STATE - Try 10 Times
3
  for (i=0; i<10 && (a = SD_Command(_SD_IDLE, 0x00000000, 0x95, 8)) != 1; i++)
4
    _delay_ms(100);
5
  if (i==10)  // Card did not response
6
    return a;
7
8
  // Initialize!
9
  for (i=0; i<10 && (a = SD_Command(_SD_Init, 0x00000000, 0xFF, 8)) != 0; i++)
10
    _delay_ms(100);
11
  if (i==10)  // Card did not come out of idle
12
    return a;
13
...
und resp = 0xFF initialisiert.

Auf dem LCD erscheint nun "255". Heißt, auf dem BUS liegt ständig 
"high".(?)

Hab blöderweise grade kein Logic Analyzer zur Hand und komme auch erst 
nächste Woche an einen ran...

von Klaus P. (phoenix89)


Lesenswert?

Fehler (mit Logic Analyzer :D ) gefunden.
1
unsigned char SPI_Write(unsigned char ch){
2
  // write on SPI
3
    SPDR = ch;
4
  // wait for Flag
5
    while(!(SPSR & (1<<SPIF)))  
6
  // return DataRegister    
7
    return SPDR;
8
}
... da fehlt doch was! (; am Ende von while..)

von Falk B. (falk)


Lesenswert?

@  Klaus Peter (phoenix89)


>... da fehlt doch was! (; am Ende von while..)

Eine der bösen Stolperfallen von C, die man der Sprache zu recht 
anlastet!

von Daniel A. (daniel-a)


Lesenswert?

Falk B. schrieb:
> @  Klaus Peter (phoenix89)
>
>> ... da fehlt doch was! (; am Ende von while..)
>
> Eine der bösen Stolperfallen von C, die man der Sprache zu recht
> anlastet!

Das sehe ich anders. Viele moderne Sprachen wie Java, Javascript, PHP, 
glsl, etc. ermöglichen genau das auch. Nur in alten sprachen wie z.B. 
bash, wo es ein "done" oder basic mit end while, oder die Andersartigen 
wie Python mit Einrückung haben dass nicht. Ich persönlich will die 
Sonderzeichen nicht missen.

von Klaus P. (phoenix89)


Angehängte Dateien:

Lesenswert?

Werde mir dann wohl ein {} bei "leeren" Schleifen angewöhnen..

Nun hängts beim Read-Befehl:
1
void SD_read(unsigned long sector, unsigned short offset, unsigned char * buffer, unsigned short length){
2
    uint8_t i;
3
    
4
    CS_ENABLE();
5
    SPI_Write(0x51);
6
    SPI_Write(sector>>15); // sector*512 >> 24
7
    SPI_Write(sector>>7);  // sector*512 >> 16
8
    SPI_Write(sector<<1);  // sector*512 >> 8
9
    SPI_Write(0);          // sector*512
10
    SPI_Write(0xFF);
11
12
  
13
    
14
    for(i=0; i<10 && SPI_Write(0xFF) != 0x00; i++);   // wait for 0
15
    for(i=0; i<10 && SPI_Write(0xFF) != 0xFE; i++);   // wait for data
16
    
17
    for(i=0; i<offset; i++)               // "skip" bytes
18
        SPI_Write(0xFF);
19
        
20
    for(i=0; i<length; i++)                 // read length bytes
21
        buffer[i] = SPI_Write(0xFF);
22
        
23
    for(i+=offset; i<512; i++)               // "skip" again
24
        SPI_Write(0xFF);
25
        
26
    // skip checksum
27
    SPI_Write(0xFF);
28
    SPI_Write(0xFF);    
29
30
    CS_DISABLE();    
31
}

In der Main aufgerufen mit:
1
SD_read(0, 3, &SD_Buffer, 8);

In der angehängten Datei gibts den Verlauf + den ersten Sektor der 
SD-Card.
Was mich verwundert ist, dass das "Gerümpel" immer das gleiche ist, 
jedoch nicht auf der SD-Card zu finden (muss ja aber irgendwo sein?). 
Die letzten 2 Bytes sind CRC und die davor stimmen mit dem was drauf 
sein soll überein..

von Falk B. (falk)


Lesenswert?

@  Daniel Abrecht (daniel-a)

>> Eine der bösen Stolperfallen von C, die man der Sprache zu recht
>> anlastet!

>Das sehe ich anders. Viele moderne Sprachen wie Java, Javascript, PHP,
>glsl, etc. ermöglichen genau das auch.

Das macht es nicht besser.

> Nur in alten sprachen wie z.B.
>bash, wo es ein "done" oder basic mit end while, oder die Andersartigen
>wie Python mit Einrückung haben dass nicht. Ich persönlich will die
>Sonderzeichen nicht missen.

Welche Sonderzeichen? Das ;?

In Pascal wäre das nicht passiert, denn dort gibt es IMMER ein begin und 
end; Wenn es in C wengigstens immer die Klammern zwingend gäbe, würde so 
ein (Tipp)fehler nicht passieren. Was gewinnt man effektiv durch das 
Weglassen von ZWEI Klammern?

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.