Forum: Mikrocontroller und Digitale Elektronik SD-card mit FatFs auf Arduino nano3 in Betrieb nehmen


von Matthias W. (matt007)


Lesenswert?

am Arduino nano3 PortB hängt der Catalex Micro-SD-card adapter 
(Pegelanpassung, 3.3V-Regler). Die Anpassung der 5V an die 3.3V sollte 
damit ok sein. Außerdem ist ein RTC-Modul mit DS1302 vorhanden. Der 
Treiber dazu läuft.

Als Software ist WinAVR installiert WinAVR-20100110-install.exe und 
Codeblocks als Editor. Die Umgebung arbeitet.

aus der FatFS-Datei ffsample.zip habe ich den Ordner "generic" gewählt. 
Die Dateien dort haben den aktuellen Stand 4.9.2016.

in sdmm.c habe ich die SPI-pins angepasst.
im Makefile wurden ff.c und sdmm.c zusätzlich aufgenommen.

Beim Übersetzen kommen Fehler in ff.c in der Funktion f_mkdir und 
f_open. Undefined reference to 'get_fattime'.
Bei den defines erscheint die Zeile #define GET_FATTIME() get_fattime() 
inaktiv. Wenn sie aktiv wäre könnte ich meine RTC als get_fattime() 
einbinden.

die Abfrage #if _FS_NORTC == 1 scheint true und daher wird wohl das 
define genutzt: #define GET_FATTIME()  ((DWORD)(_NORTC_YEAR - 1980) << 
25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16)

in der ffconf.h steht #define _FS_NORTC  0. Demnach müsste doch die 
Abfrage #if _FS_NORTC == 1 false sein und die Zeile danach ignoriert 
werden?

mit #define _FS_NORTC 1 ist die Fehlermeldung weg.

Muss noch etwas mit dem Tick in einer ISR gemacht werden? Im 
AVR-Beispiel sah ich dazu etwas.

von Draco (Gast)


Lesenswert?

Häng halt mal die Dateien an?! Meinst du jemand macht sich die Mühe und 
sucht jetzt in Google danach?!

Und ein paar Defines aus dem Zusammenhang gerupft bringt hier auch 
nichts weiter.

von Matthias W. (matt007)


Angehängte Dateien:

Lesenswert?

Draco schrieb:
> Häng halt mal die Dateien an

anbei die Dateien Draco.

von Matthias W. (matt007)


Lesenswert?

Fehler kommen keine mehr beim Compilien.

Diese Zeile macht er ohne Fehler:
res=f_mount(&FatFs, "", 0);  // give work area to default drive

res=f_open(&Fil, "newfile.txt", FA_WRITE | FA_CREATE_ALWAYS);
Hier kommt ein Fehler 3 zurück: FR_NOT_READY physical drive cannot work

von Matthias W. (matt007)


Lesenswert?

Matthias W. schrieb:
> res=f_open(&Fil, "newfile.txt", FA_WRITE | FA_CREATE_ALWAYS);
> Hier kommt ein Fehler 3 zurück: FR_NOT_READY physical drive cannot work

gibts eine Idee woher der Fehler kommen kann?
kennt jemand dieses Softwarepaket genauer?

von Falk B. (falk)


Lesenswert?

@ Matthias W. (matt007)

>> res=f_open(&Fil, "newfile.txt", FA_WRITE | FA_CREATE_ALWAYS);
>> Hier kommt ein Fehler 3 zurück: FR_NOT_READY physical drive cannot work

>gibts eine Idee woher der Fehler kommen kann?

Da funktioniert elementar was nicht mit der Ansteuerung.

>kennt jemand dieses Softwarepaket genauer?

Kenn ich, ist sehr gut. Das generische Beispiel hab ich nie benutzt, 
sondern immer das AVR-Beispiel mit Hardware-SPI. Das lief auf Anhieb!

Wie sieht denn deine Low Level Ansteuerung aus? Die muss man mindestens 
als Bit-Bang SPI ausführen.

von guest (Gast)


Lesenswert?

Versuchs mal mit:
1
res=f_mount(&FatFs, "", 1);

Wenn da als letzter Parameter eine 0 steht ("delayed mount"), wird erst 
beim f_open tatsächlich gemounted.
Geht denn das 'find_volume' im f_open gut? Du hast ja extra schon ne 
Ausgabe dafür eingebaut.
Ansonsten such nach "FR_NOT_READY" und hangel Dich rückwärts durch den 
Code.
Dann dürftest Du über "disk_initialize" stolpern, was wohl schiefgeht, 
usw.

Hast Du die sdmm.c angefasst? Die ist ziemlicher Schrott. Z.B:
1
#define DI_INIT()  DDRB  |= 0x03  /* PB3: Initialize port for MMC DI as output */
2
#define DI_H()    PORTB |= 0x03  /* PB3: Set MMC DI "high" */
macht mit Sicherheit nicht was da in den Kommentaren steht! Das setzt 
PB0 und PB1 als Output bzw. beide Pins auf High.

PS:
1
#define _CODE_PAGE  932
Willst Du wirklich japanische Zeichen in Dateinamen?

von Matthias W. (matt007)


Lesenswert?

Falk B. schrieb:
> Wie sieht denn deine Low Level Ansteuerung aus? Die muss man mindestens
> als Bit-Bang SPI ausführen.

in der Datei sdmm.c (Foolproof MMCv3/SDv1/SDv2 (in SPI mode) control 
module) steht dazu:
Easy to Port Bit-banging SPI
It uses only four GPIO pins. No complex peripheral needs to be used.

Die Pins habe ich definiert wie folgt:
#define DO_INIT()  /* Initialize port for MMC DO as input */
#define DO    (PINB &  0x04)  /* PB4: Test for MMC DO ('H':true, 
'L':false) */

#define DI_INIT()  DDRB  |= 0x03  /* PB3: Initialize port for MMC DI as 
output */
#define DI_H()    PORTB |= 0x03  /* PB3: Set MMC DI "high" */
#define DI_L()    PORTB &= 0xFC  /* PB3: Set MMC DI "low" */

#define CK_INIT()  DDRB  |= 0x05  /* PB5: Initialize port for MMC SCLK 
as output */
#define CK_H()    PORTB |= 0x05  /* PB5: Set MMC SCLK "high" */
#define  CK_L()    PORTB &= 0xFA  /* PB5: 1010 Set MMC SCLK "low" */

#define CS_INIT()  DDRB  |= 0x02  /* PB2: Initialize port for MMC CS as 
output */
#define  CS_H()    PORTB |= 0x02  /* PB2: Set MMC CS "high" */
#define CS_L()    PORTB &= 0xFD  /* PB2: Set MMC CS "low" */

es gibt da auch eine delay-Funktion:
void dly_us (UINT n)

es ist die Frage wie man am besten die kritischen Teile testen kann ohne 
zu viel im Detail durchgehen zu müssen.

Beim AVR-Beispiel sah ich einen Systemtick in einer ISR. So etwas ist 
mir hier bisher nicht aufgefallen. Keine Ahnung ob da etwas nötig ist.

oben steht:
No Media Change Detection
Application program needs to perform a f_mount() after media change.

vielleicht braucht die Software keinen Tick?

von Matthias W. (matt007)


Lesenswert?

guest schrieb:
> Versuchs mal mit:res=f_mount(&FatFs, "", 1);

danke für den Hinweis. Schau ich an !

> Geht denn das 'find_volume' im f_open gut? Du hast ja extra schon ne
> Ausgabe dafür eingebaut.

ja - nur probieren muss ich es noch.

> Ansonsten such nach "FR_NOT_READY" und hangel Dich rückwärts durch den
> Code.
> Dann dürftest Du über "disk_initialize" stolpern, was wohl schiefgeht,
> usw.

ok.

> Hast Du die sdmm.c angefasst? Die ist ziemlicher Schrott. Z.B:#define
> DI_INIT()  DDRB  |= 0x03
> #define DI_H()    PORTB |= 0x03
> macht mit Sicherheit nicht was da in den Kommentaren steht! Das setzt
> PB0 und PB1 als Output bzw. beide Pins auf High.

ja. Das ist mein eigener Schrott von heute. Offenbar funktioniert das 
Hirn nicht immer. Ich ändere es ab.

> PS:#define _CODE_PAGE  932
> Willst Du wirklich japanische Zeichen in Dateinamen?

sicher nicht.
"Incorrect setting of the code page can cause a file open failure."

#define _CODE_PAGE  932
/   1   - ASCII (No extended character. Non-LFN cfg. only)
/   437 - U.S.

deutsch sehe ich in ffconf.h nicht. Also wohl 1 oder 437?

von Falk B. (falk)


Lesenswert?

@Matthias W. (matt007)

>es gibt da auch eine delay-Funktion:
>void dly_us (UINT n)

Und was ist dort REAL drin? Die _delay_ms() vom gcc?

>es ist die Frage wie man am besten die kritischen Teile testen kann ohne
>zu viel im Detail durchgehen zu müssen.

Keine Ahnung. Da die Software OK ist, sollte man es mit der richtigen 
IO-Ansteuerung hinkriegen.

>Beim AVR-Beispiel sah ich einen Systemtick in einer ISR. So etwas ist
>mir hier bisher nicht aufgefallen. Keine Ahnung ob da etwas nötig ist.

DRINGEND!

>vielleicht braucht die Software keinen Tick?

JA! 10ms!

von Falk B. (falk)


Lesenswert?

@ Matthias W. (matt007)

>> Versuchs mal mit:res=f_mount(&FatFs, "", 1);

>danke für den Hinweis. Schau ich an !

Unsinn. Damit verschiebt man nur das Problem! Die Funktion muss ohne 
Fehler durchlaufen! PUNKT!

von Falk B. (falk)


Lesenswert?

>#define _CODE_PAGE  932
>/   1   - ASCII (No extended character. Non-LFN cfg. only)
>/   437 - U.S.

>deutsch sehe ich in ffconf.h nicht. Also wohl 1 oder 437?

1, ASCII.

von guest (Gast)


Lesenswert?

Falk B. schrieb:
> Unsinn. Damit verschiebt man nur das Problem! Die Funktion muss ohne
> Fehler durchlaufen! PUNKT!

Klar verschiebt man den Fehler, aber halt an die richtige Stelle. Wenn 
das Mounten nicht klappt, sollte der Fehler in f_mount passieren und 
nicht erst in f_open. Und natürlich funktioniert das Ganze nicht, 
solange die Funktionen nicht fehlerfrei laufen.

Falk B. schrieb:
>>#define _CODE_PAGE  932
>>/   1   - ASCII (No extended character. Non-LFN cfg. only)
>>/   437 - U.S.
>
>>deutsch sehe ich in ffconf.h nicht. Also wohl 1 oder 437?
>
> 1, ASCII.

Warum nicht "850 - Latin 1"?
Ok, Umlaute, 'ß' u.ä. sollte man eh vermeiden, von daher ist ASCII 
vielleicht gar nicht so schlecht.

von Matthias W. (matt007)


Lesenswert?

Matthias W. schrieb:
> Geht denn das 'find_volume' im f_open gut?

da gibt es leider dieselbe Fehlermeldung 03 = FR_NOT_READY.

> Dann dürftest Du über "disk_initialize" stolpern, was wohl schiefgeht

so ist es wohl.

von Matthias W. (matt007)


Lesenswert?

die falsch definierten Pins habe ich korrigiert. Der Test zeigt dass die 
Ausgabe über die Pins an die Pins des Kartenhalters klappt. Steile 
Impulse liegen an. 120ns werden gut übertragen. Die 3.3kOhm 
Vorwiderstände im Catalex verfälschen das also nicht.

Nicht getestet habe ich DO vom Kartenhalter zurück in den AVR. Ich nehme 
an daß auch dies nun klappt. Im Schaltplan von ChaN ist an den DO-Pin 
des Kartenhalters ein 10kOhm Pullup gehängt. Dieser fehlt am Catalex. 
Keine Ahnung ob das Weglassen zu Problemen führt.

von Matthias W. (matt007)


Lesenswert?

Falk B. schrieb:
> 1, ASCII.

Danke Falk. Ich hatte nun 437 genommen. Geht nicht.

von Matthias W. (matt007)


Lesenswert?

guest schrieb:
> Warum nicht "850 - Latin 1"?

Danke für den Hinweis. Kann ich testen. Ich vermute daß es noch an 
anderer Stelle klemmt.

von Matthias W. (matt007)


Lesenswert?

Falk B. schrieb:
> Keine Ahnung. Da die Software OK ist, sollte man es mit der richtigen
> IO-Ansteuerung hinkriegen.

die IO-Ansteuerung habe ich nun erfolgreich getestet:
#define DO_INIT()  DDRB  &= 0xEF   // 11101111 PB4: Initialize port for 
MMC DO as input
#define DO      PINB  &   0x10  // 00010000 PB4: Test for MMC DO 
('H':true, 'L':false)

#define DI_INIT()  DDRB  |= 0x08  // 00001000 PB3: Initialize port for 
MMC DI as output
#define DI_H()    PORTB |= 0x08  // 00001000 PB3: Set MMC DI "high"
#define DI_L()    PORTB &= 0xF7  // 11110111 PB3: Set MMC DI "low"

#define CK_INIT()  DDRB  |= 0x20  // 00100000 PB5: Initialize port for 
MMC SCLK as output
#define CK_H()    PORTB |= 0x20  // 00100000 PB5: Set MMC SCLK "high"
#define  CK_L()    PORTB &= 0xDF  // 11011111 PB5: Set MMC SCLK "low"

#define CS_INIT()  DDRB  |= 0x04  // 00000100 PB2: Initialize port for 
MMC CS as output
#define  CS_H()    PORTB |= 0x04  // 00000100 PB2: Set MMC CS "high"
#define CS_L()    PORTB &= 0xFB  // 11111011 PB2: Set MMC CS "low"

/* Test CS-Card - ok - kommt am Kartenhalter an
CS_INIT();
while (1){
    CS_H();
    CS_L();
} */

/* Test DI-Card - ok - kommt am Kartenhalter an
DI_INIT();
while (1){
    DI_H();
    DI_L();
} */

/* Test DI-Card - ok - kommt am Kartenhalter an
DI_INIT();
while (1){
    DI_H();
    DI_L();
} */

/* Test CK-Card - ok - kommt am Kartenhalter an
CK_INIT();
while (1){
    CK_H();
    CK_L();
} */

alle diese Pins laufen nun. Bis auf die DO-Rückmeldung der Daten sind 
die Steuersignale für die Kartenpins getestet !
Wenn ich eine Init an die Karte schicke müsste diese ja antworten. So 
etwas habe ich bisher nicht getestet.

von Matthias W. (matt007)


Lesenswert?

Falk B. schrieb:
>>Beim AVR-Beispiel sah ich einen Systemtick in einer ISR. So etwas ist
>>mir hier bisher nicht aufgefallen. Keine Ahnung ob da etwas nötig ist.
>
> DRINGEND!
>
>>vielleicht braucht die Software keinen Tick?
>
> JA! 10ms!

Danke Falk. Im AVR-Beispiel sah ich dies. Es ist die Frage ob auch das 
Generic-Model so etwas braucht/nutzt. Irgendwo müsste das ja 
herauszulesen sein.

So wie es aussieht schlägt disk_initialize in sdmm.c fehl.
Ist denn hier etwas mit den ticks gemacht?
Er fragt tmr ab. Er setzt jedoch tmr erst mal auf 1000,
decrementiert dann bis 0. Es sieht doch nicht so aus als
ob tmr ein tick wäre der über ISR incrementiert wird?

vielleicht geht auch rcvr_mmc(buf, 4); daneben?

dly_us(10000);    /* 10ms */
CS_INIT(); CS_H();  /* Initialize port pin tied to CS */
CK_INIT(); CK_L();  /* Initialize port pin tied to SCLK */
DI_INIT();    /* Initialize port pin tied to DI */
DO_INIT();    /* Initialize port pin tied to DO */

for (n = 10; n; n--) rcvr_mmc(buf, 1);  /* Apply 80 dummy clocks and the 
card gets ready to receive command */

ty = 0;
if (send_cmd(CMD0, 0) == 1) {    /* Enter Idle state */
  if (send_cmd(CMD8, 0x1AA) == 1) {  /* SDv2? */
    rcvr_mmc(buf, 4);  /* Get trailing return value of R7 resp */
    if (buf[2] == 0x01 && buf[3] == 0xAA) {  /* The card can work at vdd 
range of 2.7-3.6V */
      for (tmr = 1000; tmr; tmr--) {  /* Wait for leaving idle state 
(ACMD41 with HCS bit) */
        if (send_cmd(ACMD41, 1UL << 30) == 0) break;
  dly_us(1000);
      }
      if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR 
*/
        rcvr_mmc(buf, 4);
  ty = (buf[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
      }
    }
  } else {  /* SDv1 or MMCv3 */
    if (send_cmd(ACMD41, 0) <= 1) {
      ty = CT_SD1; cmd = ACMD41; /* SDv1 */
    } else {
      ty = CT_MMC; cmd = CMD1;  /* MMCv3 */
    }
    for (tmr = 1000; tmr; tmr--) { /* Wait for leaving idle state */
      if (send_cmd(cmd, 0) == 0) break;
        dly_us(1000);
      }
      if (!tmr || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 
512 */
        ty = 0;
     }
  }

von Mitlesa (Gast)


Lesenswert?

Matthias W. schrieb:
> ty = 0;
> if (send_cmd(CMD0, 0) == 1) {    /* Enter Idle state */
>   if (send_cmd(CMD8, 0x1AA) == 1) {  /* SDv2? */
>     rcvr_mmc(buf, 4);  /* Get trailing return value of R7 resp */
>     if (buf[2] == 0x01 && buf[3] == 0xAA) {  /* The card can work at vdd
> range of 2.7-3.6V */
>       for (tmr = 1000; tmr; tmr--) {  /* Wait for leaving idle state
> (ACMD41 with HCS bit) */
>         if (send_cmd(ACMD41, 1UL << 30) == 0) break;
>   dly_us(1000);
>       }
>       if (tmr && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR
> */

Wie soll man diesen Schrott lesen können? Kannst du mal
bitte die Hinweise zum Posten von Quelltexten berücksichtigen
bzw umsetzen?

von Falk B. (falk)


Lesenswert?

@  Matthias W. (matt007)

>>>vielleicht braucht die Software keinen Tick?
>> JA! 10ms!

>Danke Falk. Im AVR-Beispiel sah ich dies. Es ist die Frage ob auch das
>Generic-Model so etwas braucht/nutzt.

Definitiv!

> Irgendwo müsste das ja herauszulesen sein.

Kann sein.

>So wie es aussieht schlägt disk_initialize in sdmm.c fehl.
>Ist denn hier etwas mit den ticks gemacht?

Dort werden Timeouts generiert.

von Matthias W. (matt007)


Lesenswert?

Mitlesa schrieb:
> Wie soll man diesen Schrott lesen können?

vielleicht mäßigst Du Deinen herben Ton etwas. Es hat mich sehr viel 
Zeit gekostet den Wirrwarr so lange hinzuformatieren bis das dann 
herausgekommen ist. Tut mir leid wenn Du trotzdem nicht zufrieden bist.

von Matthias W. (matt007)


Lesenswert?

Falk B. schrieb:
> Definitiv!

wenn es so ist so muss dies noch hinein. Ich habe viel Code und Text 
angesehen in den letzten Tagen zu diesem Thema. Es scheint nicht so 
einfach auf Anhieb alles richtig zu machen.

von guest (Gast)


Lesenswert?

Matthias W. schrieb:
> vielleicht mäßigst Du Deinen herben Ton etwas. Es hat mich sehr viel
> Zeit gekostet den Wirrwarr so lange hinzuformatieren bis das dann
> herausgekommen ist. Tut mir leid wenn Du trotzdem nicht zufrieden bist.

Das "hinzuformatieren" hättest Du Dir sparen können, über dem 
Eingabefeld dieses Forums gibt es extra einen Hinweis "Formatierung" -> 
Lesen und dran halten!
Mitlesa hat durchaus Recht, So wie Du den Code postest sieht er einfach 
nur grausam aus und den meisten Lesern vegeht die Lust da auch nur einen 
Blick drauf zu werfen.

von Eric B. (beric)


Lesenswert?

So macht man das (aber eigentlich noch besser als Anhang):
1
    dly_us(10000);      /* 10ms */
2
    CS_INIT(); CS_H();  /* Initialize port pin tied to CS */
3
    CK_INIT(); CK_L();  /* Initialize port pin tied to SCLK */
4
    DI_INIT();          /* Initialize port pin tied to DI */
5
    DO_INIT();          /* Initialize port pin tied to DO */
6
7
    /* Apply 80 dummy clocks and the 
8
    card gets ready to receive command */
9
    for (n = 10; n; n--) {
10
        rcvr_mmc(buf, 1);
11
    }
12
13
    ty = 0;
14
    
15
    if (send_cmd(CMD0, 0) == 1) {
16
        /* Enter ide state */
17
        
18
        if (send_cmd(CMD8, 0x1AA) == 1) {
19
            /* SDv2 */
20
            
21
            /* Get trailing return value of R7 resp */
22
            rcvr_mmc(buf, 4);
23
            
24
            if (buf[2] == 0x01 && buf[3] == 0xAA) {
25
                /* The card can work at vdd range of 2.7-3.6V */
26
                
27
                for (tmr = 1000; tmr; tmr--) {
28
                    /* Wait for leaving idle state (ACMD41 with HCS bit) */
29
                    
30
                    if (send_cmd(ACMD41, 1UL << 30) == 0)
31
                        break;
32
                    dly_us(1000);
33
                }
34
                
35
                if (tmr && send_cmd(CMD58, 0) == 0) {
36
                    /* Check CCS bit in the OCR */
37
                    rcvr_mmc(buf, 4);
38
                    
39
                    /* SDv2*/
40
                    ty = (buf[0] & 0x40) ? (CT_SD2 | CT_BLOCK) : CT_SD2;
41
                }
42
            }
43
        } else {
44
            /* SDv1 or MMCv3 */
45
            
46
            if (send_cmd(ACMD41, 0) <= 1) {
47
                /* SDv1 */
48
                ty = CT_SD1; cmd = ACMD41; 
49
            } else {
50
                /* MMCv3 */
51
                ty = CT_MMC; cmd = CMD1;  
52
            }
53
            for (tmr = 1000; tmr; tmr--) {
54
                /* Wait for leaving idle state */
55
                
56
                if (send_cmd(cmd, 0) == 0)
57
                    break;
58
                dly_us(1000);
59
            }
60
            
61
            /* Set R/W block length to 512 */
62
            if (!tmr || send_cmd(CMD16, 512) != 0) {
63
                ty = 0;
64
            }
65
        }
66
    }

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Das Problem legt im nicht geposteten Code:
1
#define CK_H()    PORTB |= 0x05  /* PB5: Set MMC SCLK "high" */
2
#define  CK_L()    PORTB &= 0xFA  /* PB5: 1010 Set MMC SCLK "low" */
3
4
// [...]
5
6
static
7
void rcvr_mmc (
8
  BYTE *buff,  /* Pointer to read buffer */
9
  UINT bc    /* Number of bytes to receive */
10
)
11
{
12
  BYTE r;
13
14
15
  DI_H();  /* Send 0xFF */
16
17
  do {
18
    r = 0;   if (DO) r++;  /* bit7 */
19
    CK_H(); CK_L();
20
    r <<= 1; if (DO) r++;  /* bit6 */
21
    CK_H(); CK_L();
22
    r <<= 1; if (DO) r++;  /* bit5 */
23
    CK_H(); CK_L();
24
    r <<= 1; if (DO) r++;  /* bit4 */
25
    CK_H(); CK_L();
26
    r <<= 1; if (DO) r++;  /* bit3 */
27
    CK_H(); CK_L();
28
    r <<= 1; if (DO) r++;  /* bit2 */
29
    CK_H(); CK_L();
30
    r <<= 1; if (DO) r++;  /* bit1 */
31
    CK_H(); CK_L();
32
    r <<= 1; if (DO) r++;  /* bit0 */
33
    CK_H(); CK_L();
34
    *buff++ = r;      /* Store a received byte */
35
  } while (--bc);
36
}
37
38
//[...] in disk_initialise()
39
40
/* Apply 80 dummy clocks and the 
41
    card gets ready to receive command */
42
    for (n = 10; n; n--) {
43
        rcvr_mmc(buf, 1);
44
    }

Da werden die 400kHz beim Anfahren der Karte nicht eingehalten, das 
mögen so einige Karten nicht. Die Spec erlaubt max. 25 MHz erst nach 
der Initialisierung im SPI Mode.

Möglicherweise geht es wenn man disk_initialize (0) in einer Schleife 
aufruft, die man bei Rückgabecode "OK" verlässt. SD Karten brauchen nach 
Power-Up etwas Zeit.

: Bearbeitet durch User
von Matthias W. (matt007)


Lesenswert?

guest schrieb:
> einen Hinweis "Formatierung" ->
> Lesen und dran halten!

Danke !

von Matthias W. (matt007)


Lesenswert?

Eric B. schrieb:
> So macht man das

Danke Eric. Sieht so gut aus.

von Matthias W. (matt007)


Lesenswert?

Matthias W. schrieb:
>> Ansonsten such nach "FR_NOT_READY" und hangel Dich rückwärts durch den
>> Code.
>> Dann dürftest Du über "disk_initialize" stolpern, was wohl schiefgeht,
>> usw.

ich habe das näher untersucht mittels USART-Ausgaben:
f_mount: FRESULT 00  res=f_mount(&FatFs, "", 0); klappt also noch
disk_initialize2843: stat 01. Dies schlägt fehl.
f_open: find_volume: RESULT 03. schlägt auch fehl.
f_open: FRESULT 03. schlägt auch fehl.

von Matthias W. (matt007)


Lesenswert?

Jim M. schrieb:
> Da werden die 400kHz beim Anfahren der Karte nicht eingehalten, das
> mögen so einige Karten nicht.

Danke Jim für den Hinweis.

von Torsten S. (tse)


Lesenswert?

Jim M. schrieb:
> Da werden die 400kHz beim Anfahren der Karte nicht eingehalten, das
> mögen so einige Karten nicht.

Das mögen alle Karten nicht wenn man sich an die Specs hält.

von Matthias W. (matt007)


Lesenswert?

Torsten S. schrieb:
> Das mögen alle Karten nicht wenn man sich an die Specs hält.

als Laie kennt man die Specs der Karten nicht oder weniger gut als Herr 
ChaN der sich sicher sehr intensiv in die Thematik eingearbeitet hat.

in Chans Beitrag "How to Use MMC/SDC" steht:
"After supply voltage reached 2.2 volts, wait for one millisecond at 
least."

dies hat er auch gemacht. In disk_initialize steht dly_us(10000); /* 
10ms */ bevor er beginnt die Pins der Karte anzusprechen.

Chan schreibt weiter:
"Set SPI clock rate between 100 kHz and 400 kHz."

dies macht sein generic low level bitbanging-Treiber offenbar nicht. Bei 
den 16MHz des Arduino nano3 schickt xmit_mmc mit ~4MHz CLK.

Problematischer erscheint rcvr_mmc. Der Ausgang MOSI zur Karte wird mit 
DI_H() auf Hi gesetzt und dann bitweise über CLK HI/LO zurückgelesen. So 
wie in sdmm.c realisiert ergibt dies high-Phasen von ~125ns und 
low-Phasen von ~250ns. Das liegt dann oberhalb 2MHz. Offenbar packt das 
die Karte nicht in dieser Phase.

"Set DI and CS high and apply 74 or more clock pulses to SCLK. The card 
will enter its native operating mode and go ready to accept native 
command."

dieses Warten hilft offenbar nichts wenn man anfangs zu rasch taktet. 
Durch Einfügen von weiteren Ausgaben CK_H(); und CK_L(); habe ich den 
CLK-Zyklus auf 1.2us verlängert. Das liegt zwar mit ~800kHz Faktor 2 
über 400kHz, aber die 8GB-Karte schafft das.

von Matthias W. (matt007)


Lesenswert?

mit der Verlängerung der Clk-HI-LO-Zyklus auf 1.2us klappt das Schreiben 
nun:
Bei f_mount kommt Fresult=0.
disk_initialize bringt stat=0.
f_open find_volume bringt Result=0.
f_open: FRESULT=0.
f_write: FRESULT=0.
f_close: FRESULT=0.
Auf der Karte ist nun die Datei newfile.txt mit dem korrekten Inhalt "It 
works!" zu finden. So weit so gut.

Es stellt die Frage wann der langsame rcvr_mmc nötig ist. Vermutlich 
kann man die Geschwindigkeit nach der Initialisierung erhöhen?

rcvr_mmc wird verwendet in
- wait_ready (void)  wait for card ready
- deselect (void)    deselect the card and release SPI bus
- select (void)      select the card and wait for ready
- rcvr_datablock ()  wait for data packet in timeout of 100ms
                     receive the data block into buffer
                     discard CRC
- xmit_datablock ()  xmit dummy CRC (0xFF,0xFF)
                     receive data response

- send_cmd ()       skip a stuff byte when stop reading
- disk_initialize () apply 80 dummy clocks and the card gets ready to 
receive command
                     get trailing return value of R7 resp
                     check CCS bit in the OCR

man könnte 2 Varianten von rcvr_mmc machen wobei die eine den Takt so 
weit heruntersetzt wie nötig und die andere so schnell liest wie 
möglich. Natürlich kann man auch die SPI nehmen wenn die passenden Pins 
dazu frei sind. Dann wird sicher manches schneller.

Bei Datenloggeranwendung ist wohl vor allem interessant das Schreiben 
auf die Karte zu beschleunigen.

von Matthias W. (matt007)


Angehängte Dateien:

Lesenswert?

Hier schreibt ChaN in "How to Use MMC/SDC" etwas zum Timing:

"MMC/SDC can work at the clock frequency upto 20/25 MHz. Of course all 
native interfaces guarantee to work at the maximum clock frequency. 
However generic SPI interface integrated in the microcontrollers may not 
work at high clock frequency due to a timing issue. Right image shows 
the timing diagram of the SPI interface. In SPI mode 0/3, the data is 
shifted out by falling edge of the SCLK and latched by next rising edge. 
td is the SCLK to DO propagation delay at the SDC, 14ns maximum. tsu is 
the minimum setup time of the MISO input. Therefore the maximum 
allowable SCLK frequency can be calculated by:

FSCLK(max) = 0.5 / (td + tsu)

Some microcontrollers I have used are limited the allowable clock 
frequency around 10 MHz according to the timing specs."

das klingt so als ob manchmal nur 10MHz Takt zulässig sind. Laut dem 
Bild sieht es so aus als ob CLK recht kurz Hi sein darf und vor allem td 
+ tsu wichtig einzuhalten sind.

von Matthias W. (matt007)


Lesenswert?

Karten mit weniger MB scheinen laut ChaN schneller zu sein:

"Write: 77kB/sec, Read: 328kB/sec on the 128MB SDC,
Write: 28kB/sec, Read: 234kB/sec on the 512MB SDC and
Write: 182kB/sec, Read: 312kB/sec on the 128MB MMC.."

MMC scheint schneller als SD zu sein.

von Matthias W. (matt007)


Lesenswert?

offenbar sollte man aufpassen wie die Karten formatiert werden:

"I tried to re-format a 512MB SDC in FAT32 with a generic format 
function of the PC, the write performance measured in file copy was 
decreased to one several. Therefore the re-formatting the card should be 
done with SD format utility or SDC/MMC compliant equipments."

Eine SD-Format-Utility klingt demnach sinnvoll.

von Matthias W. (matt007)


Angehängte Dateien:

Lesenswert?

Es klingt so als ob ein Pullup zwingend nötig wäre um Ärger bei der 
Initialisierung zu vermeiden:

"A pull-up on the DO cannot be omited, or some cards will fail 
initialization process."   siehe das Bild

der Catalex Micro-SD-card adapter hat keinen solchen Widerstand verbaut. 
Demnach müsste dieser nachgerüstet werden?

Kennt jemand dieses Problem? Ist das noch so bei aktuell verkauften 
Karten?

: Bearbeitet durch User
von Brue W. (brue)


Lesenswert?

Die SD Spezifikation sieht pull-ups auf der Host Seite vor, und zwar auf 
allen Datenleitungen und der CMD Leitung. 10-100kOhm
Wenn sich ein Host nicht an die Spezifikation haltet kann es immer zu 
Problemen kommen.

Gruss

von Matthias W. (matt007)


Lesenswert?

Brue W. schrieb:
> Die SD Spezifikation sieht pull-ups auf der Host Seite vor, und
> zwar auf
> allen Datenleitungen und der CMD Leitung. 10-100kOhm

Danke Brue, Du meinst also man sollte bei diesen "Catalex Micro-SD-card 
adapter" zumindest den Widerstand nach 3.3V bei DO nachrüsten?

von Falk B. (falk)


Lesenswert?

@Matthias W. (matt007)

>Danke Brue, Du meinst also man sollte bei diesen "Catalex Micro-SD-card
>adapter" zumindest den Widerstand nach 3.3V bei DO nachrüsten?

JA!!!

Du bist gerade dabei, alle Fehler dieses Themas einmal durchzuprobieren 
;-)

MMC- und SD-Karten

von Fred (Gast)


Lesenswert?

Hallo Matthias,

Matthias W. schrieb:
> mit der Verlängerung der Clk-HI-LO-Zyklus auf 1.2us klappt das Schreiben
> nun:
> Bei f_mount kommt Fresult=0.
> disk_initialize bringt stat=0.
> f_open find_volume bringt Result=0.
> f_open: FRESULT=0.
> f_write: FRESULT=0.
> f_close: FRESULT=0.
> Auf der Karte ist nun die Datei newfile.txt mit dem korrekten Inhalt "It
> works!" zu finden. So weit so gut.

Kannst Du denn mal Dein lauffähiges Mini-Programm (Projekt) zeigen ?
Das wäre doch ein gutes Beispiel für einen erfolgreichen Test,
wenn jemand etwas Ähnliches nachbauen möchte.

LG Fred

von Matthias W. (matt007)


Lesenswert?

Falk B. schrieb:
> Du bist gerade dabei, alle Fehler dieses Themas einmal durchzuprobieren
> ;-)

Du hast schon recht Falk. Eigentlich will ich das Rad nicht neuerfinden. 
Ist es denn so vermessen zu hoffen daß "generic"-Software so geschrieben 
ist daß nicht mit dem Takt bei der Init die Karte überfahren wird und 
daher schon da scheitert? F-CPU wertet die Software ja aus. Das delay_us 
ist so gemacht.

Ist es so vermessen zu hoffen daß in Stückzahlen verkaufte Kartenleser 
die benötigten Widerstände bereits im Layout vorgesehen haben? 
Nachträglich hinzufrickeln ist für mich nicht so einfach.

Die Catalex-Dinger gibts doch länger schon. 1.170 Ergebnisse meldet 
Google bei "catalex microsd card adapter". Der Schaltplan von Fred Chu 
stammt aus 2013. Nun haben wir 2016. Im Plan ist kein Pullup. Dafür gibt 
es einen Plan wo die 3.3k-Widerstände durch 33 Ohm ersetzt wurden. Nötig 
scheint das nicht wenn ich meine Messungen betrachte.

Ok. Die Welt ist nicht perfekt und das wird sie wohl nie werden. Aber so 
einfache Sachen wie ein zusätzlicher Widerstand oder eine Funktion wo 
der kritische Takt berücksichtigt ist. Das ist wohl einfach zu viel 
verlangt...

von Matthias W. (matt007)


Lesenswert?

Hier ist ein Kartenleser wo an allen Kartenpins Pullups sind:
http://www.robotshop.com/media/files/PDF/micro-sd-card-adapter-documentation-32312.pdf

ChaN hält das offenbar nicht für erforderlich. Jedenfalls sieht sein im 
neuen Paket mitgeliefertes jpg so aus.

von Matthias W. (matt007)


Lesenswert?

Fred schrieb:
> Kannst Du denn mal Dein lauffähiges Mini-Programm (Projekt) zeigen ?

das kann ich schon machen Fred. Momentan ist das noch nicht fertig. Es 
gibt noch diverse Fragen - siehe oben - die ich gerne klären und in der 
Software berücksichtigen würde.

Leider habe ich zum Test nur eine einzige SD-Mikro-Karte. Andere Karten 
kann ich daher momentan nicht testen und daher auch nichts dazu sagen. 
Die Schreibgeschwindigkeit würde ich gerne testen.

Zum Thema RTC ist mir aufgefallen daß der Treiber 4 Byte zusammenpackt. 
Die Sekunden werden dabei unten abgeschnitten, so daß die Zeit nur alle 
2s genau geschrieben werden kann. Keine Ahnung ob das so gewünscht ist. 
Ich bin für das Thema FAT kein Fachmann. Wenn 1s besser wäre so ist das 
schon zu machen. Man könnte die RTC dazu im BurstMode auslesen.

von Falk B. (falk)


Lesenswert?

@Matthias W. (matt007)

>Du hast schon recht Falk. Eigentlich will ich das Rad nicht neuerfinden.
>Ist es denn so vermessen zu hoffen daß "generic"-Software so geschrieben
>ist daß nicht mit dem Takt bei der Init die Karte überfahren wird und
>daher schon da scheitert?

Natürlich nicht, ich bin da auch ein wenig negativ überrascht. 
Eigentlich haben die Dinge von Elm Chan überaus Qualität. Da hat der 
Meister wohl einen schlechten Tag gehabt.

>Ist es so vermessen zu hoffen daß in Stückzahlen verkaufte Kartenleser
>die benötigten Widerstände bereits im Layout vorgesehen haben?

Dito. Aber das ist halt alles Arduino-Style. Qu deren TFT/SD-Shield sind 
auch diverse Unschärfen und Bugs drauf, u.a. fehlt der Pull-Up an DO! 
Die habe das halt schnell an irgendeiner Karte getestet, lief durch 
zufall, fertig 8-0

>einfache Sachen wie ein zusätzlicher Widerstand oder eine Funktion wo
>der kritische Takt berücksichtigt ist. Das ist wohl einfach zu viel
>verlangt...

Nö, das ist schon OK so, was du da beklagst, das würde mich auch 
tierisch nerven!

von guest (Gast)


Lesenswert?

Matthias W. schrieb:
> Zum Thema RTC ist mir aufgefallen daß der Treiber 4 Byte zusammenpackt.
> Die Sekunden werden dabei unten abgeschnitten, so daß die Zeit nur alle
> 2s genau geschrieben werden kann. Keine Ahnung ob das so gewünscht ist.
> Ich bin für das Thema FAT kein Fachmann. Wenn 1s besser wäre so ist das
> schon zu machen. Man könnte die RTC dazu im BurstMode auslesen.

Das hängt mit der Auflösung der Timstamps bei FAT zusammen. Die können 
nur 'gerade' Sekunden (zumindest ursprünglich, creation time kann 
mittlerweile mehr).

von Matthias W. (matt007)


Angehängte Dateien:

Lesenswert?

Fred schrieb:
> Kannst Du denn mal Dein lauffähiges Mini-Programm (Projekt) zeigen ?
> Das wäre doch ein gutes Beispiel für einen erfolgreichen Test,
> wenn jemand etwas Ähnliches nachbauen möchte.

anbei der aktuelle Stand des Projekts.

Dies arbeitet so bei mir mit einer 8GB-SD-Karte von SanDisk.
Eine Testdatei wird erfolgreich auf der Karte erstellt und ein paar 
Zeichen hineingeschrieben.

Eine RTC-Funktion mit einem DS1302 ist nun auch dabei. Dabei werden 
Zeit/Datum wenn ChaN dies anfordert über einen ReadBurst aus der RTC 
ausgelesen, in 4 Byte gepackt und von ChaN weiterverarbeitet.

Es ist eine Funktion da um die Uhr einmal zu stellen. Dann läuft sie 
weiter bis die kleine Batterie leer ist. Die Uhr kostet derzeit ~1 EUR 
incl. Versand aus China.

Die Funktionen arbeiten mit Bitbanging. Leider ist es mir bisher nicht 
gelungen die kritische Funktion rcvr_mmc() nach der Init-Phase zu 
beschleunigen ohne Fehler zu verursachen.

Es gibt momentan 2 Funktionen:
+ rcvr_mmc_slow() wollte ich nur da verwenden wo es zwingend nötig ist
+ rcvr_mmc() ohne die zwischengeschobene Verlangsamung sollte überall 
sonst laufen.

Dieser Ansatz hat bisher nicht geklappt. Daher sind beide Funktionen 
momentan gleich, damit die Funktion ok ist und jemand anders mal schauen 
kann wie sich das trotzdem schneller bekommen lässt ohne Fehler.

Damit man die Funktion besser verfolgen kann habe ich USART-Ausgaben 
eingebaut die man mit #define DEBUG 1 einschalten oder mit #define DEBUG 
0 ausschalten kann.

Viel Spaß beim Testen !

von Matthias W. (matt007)


Lesenswert?

guest schrieb:
> Das hängt mit der Auflösung der Timstamps bei FAT zusammen. Die können
> nur 'gerade' Sekunden (zumindest ursprünglich, creation time kann
> mittlerweile mehr).

Danke für den Hinweis !

von Matthias W. (matt007)


Lesenswert?

Falk B. schrieb:
> Eigentlich haben die Dinge von Elm Chan überaus Qualität.

Ja. Der Mann kann wirklich prima programmieren !
Es gibt auch Teile von ChaN die in Assembler programmiert wurden für 
maximale Performance. Die .S-Dateien hat ChaN dann mitgegeben.

von Matthias W. (matt007)


Lesenswert?

Zum Datum der geschriebenen Dateien:
Ohne Verwendung RTC wird in ff.c das Datum aus defines 
zusammengebastelt:

((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | 
(DWORD)_NORTC_MDAY << 16)

die defines zum Datum stehen in ffconf.h:
#define _FS_NORTC  0  // 1 ignoriert RTC
#define _NORTC_MON  1
#define _NORTC_MDAY  1
#define _NORTC_YEAR  2016  // 1.1.2016 00:00

mit #define _FS_NORTC 0 wird RTC gewählt und
mit #define _FS_NORTC 1 das fest vorgegebene Datum 1.1.2016 00:00.

Tatsächlich wird bei _CODE_PAGE == 437 (#define _CODE_PAGE 437 in 
ffconf.h) beim Schreiben auf die Karte und Lesen über Laptop Datum 
31.12.2015 23:00 für die Testdatei angezeigt. Es wird also eine Stunde 
zurückgestellt.

Der Grund dafür liegt wohl in der Codepage? Vielleicht ist das weg wenn 
man eine andere Codepage wählt. Bisher habe ich das nicht probiert.

von Matthias W. (matt007)


Angehängte Dateien:

Lesenswert?

Matthias W. schrieb:
> diesen "Catalex Micro-SD-card
> adapter" zumindest den Widerstand nach 3.3V bei DO nachrüsten?

einen 10k SMD-Widerstand 0805 habe ich auf der Catalex-Platine an R4 zu 
C1 aufgelötet. Damit wird DO nach 3.3V hochgezogen. Bisher ist mir nicht 
aufgefallen daß dies eine positive Veränderung beim Lesen meiner Karte 
bewirkt hat. Vielleicht gehen andere Karten so besser.

von guest (Gast)


Lesenswert?

Matthias W. schrieb:
> Tatsächlich wird bei _CODE_PAGE == 437 (#define _CODE_PAGE 437 in
> ffconf.h) beim Schreiben auf die Karte und Lesen über Laptop Datum
> 31.12.2015 23:00 für die Testdatei angezeigt. Es wird also eine Stunde
> zurückgestellt.
>
> Der Grund dafür liegt wohl in der Codepage? Vielleicht ist das weg wenn
> man eine andere Codepage wählt. Bisher habe ich das nicht probiert.

Die Codepage dürfte egal sein, 437 ist original IBM-PC, also US. Und die 
liegen mehr als 1h daneben. Ursache ist eher die Sommerzeit.

von Matthias W. (matt007)


Lesenswert?

guest schrieb:
> Die Codepage dürfte egal sein, 437 ist original IBM-PC, also US. Und die
> liegen mehr als 1h daneben. Ursache ist eher die Sommerzeit.

Danke für den Hinweis.

Seltsam ist eben daß ich die RTC mit meiner Uhr gestellt habe.
Dieselbe Zeit zeigt ja auch der Laptop rechts unten an.

Diese Zeit hat nun also die RTC. Beim Schreiben der Datei bekommt diese 
genau diese Zeit. Und genau diese Zeit wird dann auch beim Lesen des 
Verzeichnisses als Schreibdatum angezeigt.

Seltsam ist nun daß die selbst zusammengebastelte Zeit passt und das auf 
die gleiche Weise zusammengebastelte Datum eine Stunde anders liegt. Es 
ist so als ob der Code von ChaN am Datum fummelt, nicht aber an der 
Funktion der RTC oder deren Ausgabe.

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.