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.
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.
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
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?
@ 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.
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?
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?
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?
@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!
@ 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!
>#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.
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.
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.
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.
guest schrieb: > Warum nicht "850 - Latin 1"? Danke für den Hinweis. Kann ich testen. Ich vermute daß es noch an anderer Stelle klemmt.
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.
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; } }
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?
@ 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.
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.
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.
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.
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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
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
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?
@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
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
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...
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.
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.
@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!
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).
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 !
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 !
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.
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.
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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.