Forum: Mikrocontroller und Digitale Elektronik ATmega: Falsche Daten beim Auslesen SD-Karte mit Bit Banging


von Ralph B. (ralphb)


Lesenswert?

Ich versuche, mit einem ATmega 8515 und der Petit FatFS Bibliothek eine 
SD-Karte auszulesen, welche mit einem der üblichen Arduino-SD-Module 
angeschlossen ist (z.B. http://www.ebay.de/252117922860).

Dazu habe ich den Bit-Banging-Code aus einem der PetitFatFS-Beispiele 
entnommen; die verwendete Pinbelegung paßt zufällig sogar.

Leider funktioniert das Lesen nicht richtig.  Wenn ich die 
Low-Level-Routinen disk_initialize() und disk_readp() aufrufe und mir 
die ersten 16 Byte der SD-Karte abhole, so erhalte ich

fa b4 00 11 87 dd b8 00  bb b4 00 00 87 d6 87 cc

obwohl

fa b8 00 10 8e d0 bc 00  b0 b8 00 00 8e d8 8e c0

richtig wäre (laut dd).  Die Bytes sind also fast richtig, aber nicht 
ganz.

Ich habe schon versucht, den Takt von max. 1 MHz durch Warten zwischen
1
CK_H(); CK_L();

noch weiter zu reduzieren, aber das ändert nichts.  Auch ein anderer 
Kartenleser und/oder eine andere Karte zeigen das gleiche Problem.

Ich probiere schon den ganzen Tag herum, kann mir das Verhalten aber 
einfach nicht erklären.  So ganz kaputt kann die Kommunikation zwischen 
ATmega und SD-Karte ja nicht sein ...

Hat jemand eine Idee?

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Wie genau sieht die Hardware aus? Schaltplan bitte und Foto.

von Ralph B. (ralphb)


Angehängte Dateien:

Lesenswert?

Einen gezeichneten Schaltplan habe ich gar nicht, ich versuch's mal per 
ASCII:

8515              SD Karte
PB0 (CS)  <---->  CS
PB1 (CK)  <---->  SCK
PB2 (DI)  <---->  MOSI
PB3 (DO)  <---->  MISO

PB4 \
PB5 |
PB6 | (SPI) <-->  Programmer
PB7 /

PAx       <---->  7-Segment-Anzeige

Alles auf einem Steckbrett, siehe Foto.

5V-Spannung für alles liefert der USB-Programmer.  Der 8515 hat einen 
Stützkondensator.

Die fast richtigen Werte sind übrigens konstant, d.h. bei jedem 
Auslese-Versuch erhalte ich die gleichen, fast-richtigen Werte.

Ein ähnlicher Versuchsaufbau auf einem Steckbrett mit Arduino Uno statt 
8515 und SD Library statt Petit Fatfs hat übrigens einwandfrei 
funktioniert.

von Jim M. (turboj)


Lesenswert?

Das ist eine SDHC Karte, machst Du die dafür nötigen Initialisierungen?
Im Zweifel poste lieber den Source Code als Anhang, das Forum hier kann 
.c Dateien gut darstellen.

Mit den Spannungsteilern am SPI verträgt die übrigens nur geringe 
Taktfrequenzen.

Ralph B. schrieb:
> fa b4 00 11 87 dd b8 00  bb b4 00 00 87 d6 87 cc
> fa b8 00 10 8e d0 bc 00  b0 b8 00 00 8e d8 8e c0


Das sieht nicht unbedingt wie kaputtes SPI aus (11 vs 10, b0 vs bb, C0 
vs CC). Meine SDHC Karten hier haben in Sektor 0 übrigens gar keinen 
Boot Code am Anfang, d.h. da stehen nur viele 0x00 drin.

von Arduinoquäler (Gast)


Lesenswert?

Ich könnte mir vorstellen dass ein 5V Prozessor leichte Probleme
haben könnte ein 3.3V - Signal einer SD-Karte unter allen Umständen
korrekt eingelesen zu bekommen.

von Arduinoquäler (Gast)


Lesenswert?

... und dann könnte ich mir noch vorstellen dass mehrere Abblock-
Kondensatoren an Prozessor und anderen Bausteinen (wie auch
Netzteil/Spannungsregler, was man nicht sieht) erheblich dazu
beitragen können die Funktionssicherheit der Schaltung erheblich
zu erhöhen.

von Mario (Gast)


Lesenswert?

Vor allem scheinen die 4 Widerstände nur Pullups zu sein. Das heißt, die 
SD-Karte wird mit 5V angesteuert. Die Schaltung dürfte folgende sein: 
http://duino4projects.com/wp-content/uploads/2013/03/Schematic-Arduino-SD-Card-Logging-Shield.jpg

von Ralph B. (ralphb)


Lesenswert?

OK, ich versuche mal, die relevanten Teile zu sammeln:

main.c
1
  UINT n;
2
  FRESULT rc;
3
4
  rc = disk_initialize();
5
  if (rc) halt(0xe, rc);
6
7
  rc = disk_readp(buf, 0, 0, 16);
8
  if (rc) halt(0xf, rc);
9
  
10
  for (UINT i = 0; i < n; ++i) {
11
    unsigned char b = buf[i];
12
    show(b >> 4);  // <--- zeigt low byte auf 7-Segment an
13
    show(b % 0xf);
14
    show(0x10);
15
  }
16
17
  halt(0x10, 8);

diskio.c
1
#define  INIT_PORT()  init_port()
2
#define DLY_US(n)  _delay_us(n)  /* Delay n microseconds */
3
#define  FORWARD(d)  
4
5
#define CS_H()    PORTB |= 0x01  /* Set MMC CS "high" */
6
#define CS_L()    PORTB &= 0xFE  /* Set MMC CS "low" */
7
#define CK_H()    PORTB |= 0x02  /* Set MMC SCLK "high" */
8
#define CK_L()    PORTB &= 0xFD  /* Set MMC SCLK "low" */
9
#define DI_H()    PORTB |= 0x04  /* Set MMC DI "high" */
10
#define DI_L()    PORTB &= 0xFB  /* Set MMC DI "low" */
11
#define DO    (PINB &  0x08)
12
13
#define NN              /*_delay_us(10)*/  // <-- Taktreduktion
14
15
static void init_port (void)
16
{
17
  DDRB  = (DDRB & 0xF7) | 0x07;
18
  PORTB = (PORTB & 0xFB) | 0x39;  /* CS=H, SCK=L, DI=H, DO=pu */
19
}
20
21
static void xmit_mmc (
22
  BYTE d      /* Data to be sent */
23
)
24
{
25
  if (d & 0x80) DI_H(); else DI_L();  /* bit7 */
26
  CK_H(); NN; CK_L(); NN;
27
  if (d & 0x40) DI_H(); else DI_L();  /* bit6 */
28
  CK_H(); NN; CK_L(); NN;
29
  if (d & 0x20) DI_H(); else DI_L();  /* bit5 */
30
  CK_H(); NN; CK_L(); NN;
31
  if (d & 0x10) DI_H(); else DI_L();  /* bit4 */
32
  CK_H(); NN; CK_L(); NN;
33
  if (d & 0x08) DI_H(); else DI_L();  /* bit3 */
34
  CK_H(); NN; CK_L(); NN;
35
  if (d & 0x04) DI_H(); else DI_L();  /* bit2 */
36
  CK_H(); NN; CK_L(); NN;
37
  if (d & 0x02) DI_H(); else DI_L();  /* bit1 */
38
  CK_H(); NN; CK_L(); NN;
39
  if (d & 0x01) DI_H(); else DI_L();  /* bit0 */
40
  CK_H(); NN; CK_L(); NN;
41
}
42
43
static BYTE rcvr_mmc (void)
44
{
45
  BYTE r;
46
47
  DI_H();  NN;  /* Send 0xFF */
48
  r = 0;   if (DO) r++;  /* bit7 */
49
  CK_H(); NN; CK_L(); NN;
50
  r <<= 1; if (DO) r++;  /* bit6 */
51
  CK_H(); NN; CK_L(); NN;
52
  r <<= 1; if (DO) r++;  /* bit5 */
53
  CK_H(); NN; CK_L(); NN;
54
  r <<= 1; if (DO) r++;  /* bit4 */
55
  CK_H(); NN; CK_L(); NN;
56
  r <<= 1; if (DO) r++;  /* bit3 */
57
  CK_H(); NN; CK_L(); NN;
58
  r <<= 1; if (DO) r++;  /* bit2 */
59
  CK_H(); NN; CK_L(); NN;
60
  r <<= 1; if (DO) r++;  /* bit1 */
61
  CK_H(); NN; CK_L(); NN;
62
  r <<= 1; if (DO) r++;  /* bit0 */
63
  CK_H(); NN; CK_L(); NN;
64
65
  return r;
66
}

Der Rest (wie auch der Code aus diskio.c oben) ist ja eigentlich 
Standard-PFF.

Die Soll-Bytefolge habe ich mit dd direkt aus /dev/sdc ausgelesen, ich 
denke also schon, daß sie korrekt ist.

Der ganze Code ist ja schon vereinfacht, weil pf_mount() und pf_open() 
nicht funktioniert hat und ich den Fehler eingrenzen wollte.

Ich finde es halt komisch, daß die Bytefolge stabil und dem Soll 
ziemlich ähnlich ist.  Allerdings ist es auch nicht so, als würden 
einzelne Bits "verrutschen" ...  Und für Störsignale ist es wie gesagt 
zu stabil.

von Arduinoquäler (Gast)


Lesenswert?

Ralph B. schrieb:
> Ich finde es halt komisch, daß die Bytefolge stabil und dem Soll
> ziemlich ähnlich ist.

Ich finde es halt komisch mit welcher Ignoranz (oder auch Unwissenheit)
du dich über die Gesetze der Physik bzw der Elektrotechnik hinwegsetzen
willst.

von Ralph B. (ralphb)


Lesenswert?

Arduinoquäler schrieb:
> Ich könnte mir vorstellen dass ein 5V Prozessor leichte Probleme
> haben könnte ein 3.3V - Signal einer SD-Karte unter allen Umständen
> korrekt eingelesen zu bekommen.

Erst dachte ich, das kann es nicht sein, da ich ja ein Modul mit 
Spannungswandler benutze.  Außerdem funktioniert es am Arduino 
(ebenfalls mit 5V betrieben, wie überhaupt die ganze Schaltung, die hier 
der Einfachheit halber weggelassen ist) einwandfrei.

Bei zweiter Überlegung frage ich mich allerdings gerade, ob denn die 
Ausgangssignale des Moduls ebenfalls auf 5V transformiert werden.  Davon 
bin ich bisher eigentlich ausgegangen, sonst macht das Modul doch keinen 
Sinn.

Außerdem ist da noch die Sache mit dem Arduino, oder ist der toleranter 
gegenüber 3,3V-Signalen?

Aber wenn es tatsächlich 3,3V-Signale sind, sollte dann die Bytefolge 
nicht stärker schwanken, und eher 1 nach 0 kippen?

von Frank (Gast)


Lesenswert?

Wenn der erwartete Datenstrom stimmt, dann ist der Fehler ja immer im 
unteren Nibbel.
Auch sieht es teilweise so aus, als ob das untere Nibbel ab und zu um 1 
verschoben ist...

von Arduinoquäler (Gast)


Lesenswert?

Ralph B. schrieb:
> Davon
> bin ich bisher eigentlich ausgegangen, sonst macht das Modul doch keinen
> Sinn.

Dann zeig doch mal deinen "Transformator" in der Schaltung.

von Ralph B. (ralphb)


Lesenswert?

Arduinoquäler schrieb:
> Ralph B. schrieb:
>> Ich finde es halt komisch, daß die Bytefolge stabil und dem Soll
>> ziemlich ähnlich ist.
>
> Ich finde es halt komisch mit welcher Ignoranz (oder auch Unwissenheit)
> du dich über die Gesetze der Physik bzw der Elektrotechnik hinwegsetzen
> willst.

Wow, hier herrscht ein rauer Wind!

Falls es Dich beruhigt: es ist Unwissenheit.

von Ralph B. (ralphb)


Lesenswert?

Arduinoquäler schrieb:
> Dann zeig doch mal deinen "Transformator" in der Schaltung.

Ich kenne den Schaltplan des Moduls leider nicht.  Die Chinesen auf ebay 
bieten keine Datenblätter, sondern nur diffuse Beschreibungen wie

- All SD SPI pins output, MOSI, SCK, MISO and CS.
- Support 5V/3.3V input.
- Size:51 x 31 mm (2.01 x 1.22 inch).

Ich kann es aber gerne mal mit dem Oszi prüfen, bisher scheint das ja 
die plausibelste Antwort zu sein.

von Stefan F. (Gast)


Lesenswert?

> Außerdem ist da noch die Sache mit dem Arduino, oder
> ist der toleranter gegenüber 3,3V-Signalen?

Arduino Module enthalten in den allermeisten Fällen ganz normale AVR 
Mikrocontroller - macht also keinen Unterschied.

Im Online-Handel wird auch viel Schrott verkauft, das solltest du 
bedenken.

Dieses SD-Karten Adapter hat keine aktiven pegelwandler, soweit ich das 
an dem Foto sehen kann. Wenn er überhaupt Pegel wandelt, dann nur mit 
Widerständen. Die führen aber zu schlechten Flanken in den Signalen.

Und für die Richtung SD-Karte->AVR ist offensichtlich keine 
Pegelwandlung vorhanden. Mit 5V betriebene AVR's wollen (soweit ich mit 
erinnere) 3V als High Pegel haben. Ob die SD Karte bei diesen hohen 
Frequenzen noch zuverlässig mindestens 3V ausgibt, ist fraglich. Das 
könnte man mit einem Oszilloskop überprüfen.

Ich habe das auch mal nur mit Widerständen versucht, und es klappte bei 
mir nur mit sehr niedrigen Taktfrequenzen. Außerdem lief es erst 
zuverlässig, nachdem ich die Versorgungsspannung des AVR auf 4,5V 
verringert hatte. Das war unzufriedenstellendes gefrickel.

Mein zweiter Versuch war mit dem CrumbX1 Modul, da ist ein AVR drauf, 
der mit 3,3V betrieben wird. Da klappte es ohne Pegelwandler auf Anhieb 
und zuverlässig - außer mit einer bestimmten µSD Karte, die wollte gar 
nicht funktionieren.

Besorge Die einen besseren SD Adapter mit aktiven Pegelwandlern.

Und spare nicht an Kondensatoren. Stromversorgung über USB Kabel ist 
manchmal suboptimal, wenn das Kabel einen hohen Innenwiderstand hat. Das 
fällt dann meist erst auf, wenn man Verbraucher dran hängt, die 
Sprunghaft viel mehr Strom brauche - wie eben SD Karten.

von Ralph B. (ralphb)


Lesenswert?

Stefan, erstmal vielen Dank für die ausführliche Antwort.  Das klingt 
für mich absolut überzeugend.

Allerdings habe ich jetzt einfach mal die USB-Spannung durch eine 
3,3V-Spannung meines Labornetzteils ersetzt und das SD-Karten-Modul auf 
3,3V gesetzt -- leider immer noch der gleiche Fehler!

Das Modul mag nicht viel taugen, aber an der zu geringen Spannung für 
den 8515 kann es eigentlich nicht mehr liegen. :-(

von Ralph B. (ralphb)


Lesenswert?

OK, ich habe den Fehler gefunden -- EPIC FAIL meinerseits.

Es liegt doch am Code, und zwar an meinem eigenen:
1
  for (UINT i = 0; i < n; ++i) {
2
    unsigned char b = buf[i];
3
    show(b >> 4);  // <--- zeigt low byte auf 7-Segment an
4
    show(b % 0xf);
5
    show(0x10);
6
  }

Das muß natürlich
1
    show(b & 0xf);

heißen. m)

Trotzdem danke für die Antworten, ich habe einiges dazugelernt.

Und SD-Karten sind natürlich für uns alle Neuland.

von Arduinoquäler (Gast)


Lesenswert?

Ralph B. schrieb:
> Ein ähnlicher Versuchsaufbau auf einem Steckbrett mit Arduino Uno statt
> 8515 und SD Library statt Petit Fatfs hat übrigens einwandfrei
> funktioniert.

Ralph B. schrieb:
> OK, ich habe den Fehler gefunden -- EPIC FAIL meinerseits.

Wie geht das zusammen? Die gleiche Programmierung hat auf einem
Arduino funktioniert? Na klasse!

von Ralph B. (ralphb)


Lesenswert?

Aha, Du bist also der Board-Klugscheißer.

"ähnlich" != "gleich".

Aber trotzdem weiter so, Deine Beiträge waren die besten!

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.