Hallo Allerseits, ich hab hier schon seit 2 Tagen ein Problem mit einer Micro-SD-Karte. Die Karte ist von Intenso, 4GB, class 4, nix Besonderes. Das Ganze soll auf einem selbstentwickelten Board laufen, ATXmega128A1U, alles 3,3V. An CS, DO und den 2 ungenutzten IOs hängt je ein 10K Pull-Up gegen 3,3V. Über UART kriege ich meine Debug-Ausgaben. Als Lib habe ich die von ELM Chan, die hatte ich schon erfolgreich in einem anderen Projekt benutzt, wenn gleich dort mit einem ATmega64. Also flink die Dateien kopiert, die Low Level Sachen angepasst, los gehts. Oder auch nicht :-( Zu Testzwecken öffne ich einfach eine Datei und schreibe dort ein paar Zeichen rein. Das geht aber leider nicht. Wenn ich nun mehrfach einen Reset am Controller mache, bekomme ich von der Funktion f_open() abwechselnd den Fehler FR_NOT_READY, /* (3) The physical drive cannot work */ oder FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */ Den SPI-Bus sehe ich auf meinem Logicanalyzer. Beim Fehler 3 schlägt schon die elementare Initialisierung mit 200kHz SPI-Takt fehl. Bei Fehler 13 funktioniert sie, die Lib schaltet auf vollen SPI Takt von 8 MHz um und will dann weiter machen. Dort gibt es scheinbar nur ein Kommando, das liefert einmal eine 0, dann viele 0xFF. Dann wird ein Blockzugriff gemacht (sieht man am lückenlosen SPI-Takt), komischerweise werden dort aber nur ~160 Byte gelesen, wobei ALLE gelesenen Daten 0 sind! Sehr mehrwürdig! Zur Initialisierung des FAT muss doch erstmal der Bootsektor gelesen werden, das sieht man auch im Code von ff.c. Aber soweit kommt es scheinbar nicht :-( Hat irgendjemand eine Idee? Ich habe schon mal 33 Ohm in die SCK Leitung zur SD-Karte eingelötet, ich vermutete schlechte Signalflangen, auch wenn das eher unwahrlscheinlich ist (Die Platine hat 4 Lagen und eine vollständige Massefläche). 100nF sind auch ca. 5mm von der Karte entfernt an VCC/GND. Im Anhang mal der SPI-Datenverkehr. Ab 16.52ms geht der High Speed Verkehr los. MFG Falk
:
Bearbeitet durch User
Kann es sein, dass es ein Problem mit der CS Leitung gibt und sich die Karte manchmal garnicht angesprochen fühlt? Es gibt ja an ein paar Stellen im Code wo er einen Softwaretimer (aus ISR und Zähler) verwendet. Hast Du das korrekt übernommen oder wird da vlt. was wegoptimiert? Mal die Optimierung ausgeschaltet? Musst Du bei Deiner Lowlevel-Implementierung den SPI zwischen 8 und 16 Bit umschalten? (habe jetzt nicht mehr im Kopf ob der XMega 16-Bit SPI kann). Das hatte bei meiner STM32F0 Anpassung für Probleme gesorgt.
Der Dump (SPI.TXT) sieht 100%ig OK aus, bis der Code den Lesevorgang abbricht. Der Sektor 0 einer SD-Karte enthält normalerweise keinen Bootloader, und die Partitionstabelle steht sehr weit hinten. Dass Du da 160 mal "00" bekommtst, ist also normal! Unter Windoof bekommt man diesen Sektor nur mit Admin-Rechten zu sehen, viele Tools zeigen Dir nur den 1. Sektor der FAT Partition an, selbst dann wenn sie Admin Rechte haben. Das Lesekommando sieht gut aus:
1 | 1652993 (16.53ms) MISO:MOSI 0xFF ÿ : 0x51 Q ; CMD17 |
2 | 1653273 (16.53ms) MISO:MOSI 0xFF ÿ : 0x00 ; |
3 | 1653542 (16.54ms) MISO:MOSI 0xFF ÿ : 0x00 ; |
4 | 1653823 (16.54ms) MISO:MOSI 0xFF ÿ : 0x00 ; |
5 | 1654103 (16.54ms) MISO:MOSI 0xFF ÿ : 0x00 ; Sektor Null |
6 | 1654384 (16.54ms) MISO:MOSI 0xFF ÿ : 0x01 ; Dummy CRC |
7 | 1654677 (16.55ms) MISO:MOSI 0xFF ÿ : 0xFF ÿ ; ... |
8 | 1654970 (16.55ms) MISO:MOSI 0x00 : 0xFF ÿ ; ReturnCode 0 = OK |
9 | 1655263 (16.55ms) MISO:MOSI 0xFF ÿ : 0xFF ÿ ; warten ... |
10 | ... |
11 | 1719550 (17.20ms) MISO:MOSI 0xFE þ : 0xFF ÿ ; Start Data Token |
12 | 1719843 (17.20ms) MISO:MOSI 0x00 : 0xFF ÿ ; ab hier gibts die Daten |
13 | ... |
14 | 1738970 (17.39ms) MISO:MOSI 0x00 : 0xFF ÿ |
Die SD Karte bestätigt das Lesekommando schon nach dem ersten Dummy Byte mit 0x00 = OK. Dann braucht sie ca. 0.7 ms, bis die Daten zur Verfügung stehen - es folgt das "Start Data" Token 0xFE. Alles weitere sind die Daten, die im Auslieferzustand 0x00 enthalten - die Partitionstabelle beginnt erst ab Byte 446, die Übertragung endet vorher. Dass es danach abbricht, ist vermutilch ein Fehler im AVR Code. Schau mal nach den Interrupts - und ob deren Handler existieren - oder dem Watchdog.
:
Bearbeitet durch User
zur Eingrenzung des Fehlers bietet sich chan-foolproof an. Damit kann man Fehler an der Hardware feststellen oder eingrenzen.
@ Markus M. (adrock) >Kann es sein, dass es ein Problem mit der CS Leitung gibt und sich die >Karte manchmal garnicht angesprochen fühlt? Nein, das Signal ist OK. >Es gibt ja an ein paar Stellen im Code wo er einen Softwaretimer (aus >ISR und Zähler) verwendet. Hast Du das korrekt übernommen Ja, das habe ich geprüft, mittel Testpin. Der Interrupt läuft und ruft alle 10ms die Funktion disk_timerproc() auf, >>vlt. was wegoptimiert? Mal die Optimierung ausgeschaltet? Geht nicht, ich hab diverse _delay_ms() im Code. >Musst Du bei Deiner Lowlevel-Implementierung den SPI zwischen 8 und 16 >Bit umschalten? Nein, der ATXmega kann nur 8 Bit. Es wird UARTE1 im SPI-Modus verwendet.
Falk Brunner schrieb: > SPI Takt von 8 > MHz Ne ganz doofe Frage - kann die Micro-SD-Karte so schnell liefern? Da gibt es doch Geschwindigkeits-Klassen, oder? Der Code wäre auch ganz interessant :-)
@Jim Meba (turboj) >Der Dump (SPI.TXT) sieht 100%ig OK aus, bis der Code den Lesevorgang >abbricht. Eben, SEHR seltsam! >Der Sektor 0 einer SD-Karte enthält normalerweise keinen Bootloader, und >die Partitionstabelle steht sehr weit hinten. Dass Du da 160 mal "00" >bekommtst, ist also normal! Nein. Auch phne Bootloader kommt die Kennung FAT32 recvht weit am Anfang an Offset 82, das müsste man sehen. Ausserdem ist dort noch diverses anderes "Gemüse" Verstreut, das man im HEX-Editor sieht. >Unter Windoof bekommt man diesen Sektor nur mit Admin-Rechten zu sehen, Ist bekannt, schaue ich mit als Admin an, mit WinHex. >Das Lesekommando sieht gut aus: >1652993 (16.53ms) MISO:MOSI 0xFF ÿ : 0x51 Q ; CMD17 >1653273 (16.53ms) MISO:MOSI 0xFF ÿ : 0x00 ; Ja,k hab ich mittlerweile auch bis dahin verfolgt. Dann folgen viele Polling-Zyklen, bis die Karte mit 0xFE antwortet. Danach wird es mysteriös. Eigenlich sollte dann DIREKT der Blocklesezugriff folgen, dabei ist der SPI-Takt lückenlos. Auf dem Logicanalyzer sieht man aber noch drei Bytes mit Lücken. Das kann nicht sein! >Die SD Karte bestätigt das Lesekommando schon nach dem ersten Dummy Byte >mit 0x00 = OK. Dann braucht sie ca. 0.7 ms, bis die Daten zur Verfügung >stehen - es folgt das "Start Data" Token 0xFE. Alles weitere sind die >Daten, die im Auslieferzustand 0x00 enthalten Nein, da seht diverses Zeug drin. Ausserdem hab ich die Karte nochmal mit Windows formatiert, dort hat das dämliche System einen Bootloader draufgeschrieben. Warum auch immer. Aber davon sehe ich rein gar nichts im Datenstrom! >- die Partitionstabelle >beginnt erst ab Byte 446, die Übertragung endet vorher. >Dass es danach abbricht, ist vermutilch ein Fehler im AVR Code. Schau >mal nach den Interrupts - und ob deren Handler existieren - oder dem >Watchdog. Es ist nur ein Interrupt aktiv, ein Timer. Der läuft normal. Wenn es einen Reset geben würde, würde ich das im Terminal sehen (Debugausschrift nach Reset). Aus irgend einem Grund, wird diese Funktion nicht korrekt umgesetzt! Sie wird, da nur einmalig genutzt, per Inline eingefügt.
1 | static
|
2 | void rcvr_spi_multi ( |
3 | BYTE *p, /* Data buffer */ |
4 | UINT cnt /* Size of data block */ |
5 | )
|
6 | {
|
7 | BYTE tmp; |
8 | |
9 | USARTE1.STATUS = USART_TXCIF_bm; // clear TXC |
10 | USARTE1.DATA = 0xFF; |
11 | cnt--; |
12 | for (; cnt != 0; cnt--) { |
13 | while(!(USARTE1.STATUS & USART_TXCIF_bm)); |
14 | tmp = USARTE1.DATA; |
15 | USARTE1.DATA = 0xFF; |
16 | *p++=tmp; |
17 | }
|
18 | while(!(USARTE1.STATUS & USART_TXCIF_bm)); |
19 | *p++=USARTE1.DATA; |
20 | }
|
@ Dieter Frohnapfel (jim_quakenbush) >> SPI Takt von 8 >> MHz >Ne ganz doofe Frage - kann die Micro-SD-Karte so schnell liefern? Kann sie, weil JEDE SD-Karte 25 MHz Takt verkraftet. Class 4 heißt, 4MB/s (nicht im SPI-Modus, aber mit 4 Bit SDIO). >gibt es doch Geschwindigkeits-Klassen, oder? Der Code wäre auch ganz >interessant :-) Nö, der funktioniert ja problemlos auf dem alten Board. Es ist der voM Meister ELM Chan. http://elm-chan.org/fsw/ff/00index_e.html
Hier mal der Ausschnit aus dem .lss File. Wenn gleich der Compilier ein paar Verwürfelungen (Optimierung -Os) macht, ist der Code FAST korrekt. Aber das einmalig cnt-- wird verschluckt! Oder sehe ich es nicht? Edit: OK, ich sehe es. Es wird mit 1 verglichen, nicht 0 (Schleifenabbruch) Dennoch darf der Code nicht nach ~160 Byte abbrechen! Er wird mit 512 Byte = 1 Sektor aufgerufen!
1 | 00002952 <rcvr_datablock>: |
2 | static |
3 | int rcvr_datablock ( |
4 | BYTE *buff, /* Data buffer to store received data */ |
5 | UINT btr /* Byte count (must be multiple of 4) */ |
6 | ) |
7 | { |
8 | 2952: 0f 93 push r16 |
9 | 2954: 1f 93 push r17 |
10 | 2956: cf 93 push r28 |
11 | 2958: df 93 push r29 |
12 | 295a: ec 01 movw r28, r24 |
13 | 295c: 8b 01 movw r16, r22 |
14 | BYTE token; |
15 | |
16 | |
17 | Timer1 = 20; |
18 | 295e: 84 e1 ldi r24, 0x14 ; 20 |
19 | 2960: 80 93 b9 20 sts 0x20B9, r24 |
20 | do { /* Wait for data packet in timeout of 200ms */ |
21 | token = xchg_spi(0xFF); |
22 | 2964: 8f ef ldi r24, 0xFF ; 255 |
23 | 2966: 71 df rcall .-286 ; 0x284a <xchg_spi> |
24 | } while ((token == 0xFF) && Timer1); |
25 | 2968: 8f 3f cpi r24, 0xFF ; 255 |
26 | 296a: 29 f4 brne .+10 ; 0x2976 <rcvr_datablock+0x24> |
27 | 296c: 80 91 b9 20 lds r24, 0x20B9 |
28 | 2970: 81 11 cpse r24, r1 |
29 | 2972: f8 cf rjmp .-16 ; 0x2964 <rcvr_datablock+0x12> |
30 | 2974: 2c c0 rjmp .+88 ; 0x29ce <rcvr_datablock+0x7c> |
31 | if (token != 0xFE) return 0; /* If not valid data token, return with error */ |
32 | 2976: 8e 3f cpi r24, 0xFE ; 254 |
33 | 2978: 51 f5 brne .+84 ; 0x29ce <rcvr_datablock+0x7c> |
34 | UINT cnt /* Size of data block */ |
35 | ) |
36 | { |
37 | BYTE tmp; |
38 | |
39 | USARTE1.STATUS = USART_TXCIF_bm; // clear TXC |
40 | 297a: 80 e4 ldi r24, 0x40 ; 64 |
41 | 297c: 80 93 b1 0a sts 0x0AB1, r24 |
42 | USARTE1.DATA = 0xFF; |
43 | 2980: 8f ef ldi r24, 0xFF ; 255 |
44 | 2982: 80 93 b0 0a sts 0x0AB0, r24 |
45 | cnt--; |
46 | 2986: c8 01 movw r24, r16 |
47 | 2988: 01 97 sbiw r24, 0x01 ; 1 |
48 | 298a: fe 01 movw r30, r28 |
49 | 298c: b8 01 movw r22, r16 |
50 | for (; cnt != 0; cnt--) { |
51 | while(!(USARTE1.STATUS & USART_TXCIF_bm)); |
52 | tmp = USARTE1.DATA; |
53 | USARTE1.DATA = 0xFF; |
54 | 298e: 2f ef ldi r18, 0xFF ; 255 |
55 | BYTE tmp; |
56 | |
57 | USARTE1.STATUS = USART_TXCIF_bm; // clear TXC |
58 | USARTE1.DATA = 0xFF; |
59 | cnt--; |
60 | for (; cnt != 0; cnt--) { |
61 | 2990: 61 30 cpi r22, 0x01 ; 1 |
62 | 2992: 71 05 cpc r23, r1 |
63 | 2994: 61 f0 breq .+24 ; 0x29ae <rcvr_datablock+0x5c> |
64 | while(!(USARTE1.STATUS & USART_TXCIF_bm)); |
65 | 2996: 30 91 b1 0a lds r19, 0x0AB1 |
66 | 299a: 36 ff sbrs r19, 6 |
67 | 299c: fc cf rjmp .-8 ; 0x2996 <rcvr_datablock+0x44> |
68 | tmp = USARTE1.DATA; |
69 | 299e: 30 91 b0 0a lds r19, 0x0AB0 |
70 | USARTE1.DATA = 0xFF; |
71 | 29a2: 20 93 b0 0a sts 0x0AB0, r18 |
72 | *p++=tmp; |
73 | 29a6: 31 93 st Z+, r19 |
74 | 29a8: 61 50 subi r22, 0x01 ; 1 |
75 | 29aa: 71 09 sbc r23, r1 |
76 | 29ac: f1 cf rjmp .-30 ; 0x2990 <rcvr_datablock+0x3e> |
77 | 29ae: c8 0f add r28, r24 |
78 | 29b0: d9 1f adc r29, r25 |
79 | } |
80 | while(!(USARTE1.STATUS & USART_TXCIF_bm)); |
81 | 29b2: 80 91 b1 0a lds r24, 0x0AB1 |
82 | 29b6: 86 ff sbrs r24, 6 |
83 | 29b8: fc cf rjmp .-8 ; 0x29b2 <rcvr_datablock+0x60> |
84 | *p++=USARTE1.DATA; |
85 | 29ba: 80 91 b0 0a lds r24, 0x0AB0 |
86 | 29be: 88 83 st Y, r24 |
87 | token = xchg_spi(0xFF); |
88 | } while ((token == 0xFF) && Timer1); |
89 | if (token != 0xFE) return 0; /* If not valid data token, return with error */ |
90 | |
91 | rcvr_spi_multi(buff, btr); /* Receive the data block into buffer */ |
92 | xchg_spi(0xFF); /* Discard CRC */ |
93 | 29c0: 8f ef ldi r24, 0xFF ; 255 |
94 | 29c2: 43 df rcall .-378 ; 0x284a <xchg_spi> |
95 | xchg_spi(0xFF); |
96 | 29c4: 8f ef ldi r24, 0xFF ; 255 |
97 | 29c6: 41 df rcall .-382 ; 0x284a <xchg_spi> |
98 | 29c8: 81 e0 ldi r24, 0x01 ; 1 |
99 | 29ca: 90 e0 ldi r25, 0x00 ; 0 |
100 | 29cc: 02 c0 rjmp .+4 ; 0x29d2 <rcvr_datablock+0x80> |
101 | |
102 | Timer1 = 20; |
103 | do { /* Wait for data packet in timeout of 200ms */ |
104 | token = xchg_spi(0xFF); |
105 | } while ((token == 0xFF) && Timer1); |
106 | if (token != 0xFE) return 0; /* If not valid data token, return with error */ |
107 | 29ce: 80 e0 ldi r24, 0x00 ; 0 |
108 | 29d0: 90 e0 ldi r25, 0x00 ; 0 |
109 | rcvr_spi_multi(buff, btr); /* Receive the data block into buffer */ |
110 | xchg_spi(0xFF); /* Discard CRC */ |
111 | xchg_spi(0xFF); |
112 | |
113 | return 1; /* Return with success */ |
114 | } |
115 | 29d2: df 91 pop r29 |
116 | 29d4: cf 91 pop r28 |
117 | 29d6: 1f 91 pop r17 |
118 | 29d8: 0f 91 pop r16 |
119 | 29da: 08 95 ret |
:
Bearbeitet durch User
Falk Brunner schrieb: >>Der Sektor 0 einer SD-Karte enthält normalerweise keinen Bootloader, und >>die Partitionstabelle steht sehr weit hinten. Dass Du da 160 mal "00" >>bekommtst, ist also normal! > > Nein. Auch phne Bootloader kommt die Kennung FAT32 recvht weit am Anfang > an Offset 82 Quatsch. Das ist ein FAT-Bootsektor. So weit vorne kommt der nur, wenn die Karte als "Superfloppy" formatiert ist. Ab Werk sind die Dinger aber normalerweise als HD formatiert, vor der ersten Partition kommt also mindestens der MBR in der Größe eines Sektors. Typisch ist sogar, dass ein kompletter "Track" reserviert ist (hier natürlich nicht wirklich ein Track im Sinne einer Spur einer HD, sondern oft genau die Größe eines Löschblocks des verbauten Flash [oder Flashcontrollers???]). Was übrigens Wixdos macht, ist bei Wechselmedien eh' absolut grenzwertig. Obwohl darauf lt. aller jeweiligen Standards immer auch HD-Strukturen zumindest zulässig sind, ist Wixdos nicht in der Lage, damit korrekt umzugehen. Nur bei "Superfloppy"-Formatierung sieht es das, was wirklich dort ist. Ansonsten nur die erste Partition. Der NT-Kernel selber sieht aber natürlich alles korrekt. Deshalb muß man nicht nur Admin sein, sondern auch noch auf's richtige Devicefile zugreifen, um selber alles zu sehen... Lustige Effekte aus dieser schwachsinnigen Trennung in das, was Microsoft will, was der User sieht und das, was wirklich ist, kann man erzielen, wenn man in der sog. "Datenträgerverwaltung" mal ein wenig mit Datenträgern spielt, die eine HD-Struktur mit mehr als einer Partition aufweisen. Die dabei generierten Fehlermeldungen füllen ein komplettes Realsatire-Magazin... Noch extremer und wesentlich weniger lustig wird es, wenn man mit bootfähigen Windows-Installationen auf solchen Wechseldatenträgern gezwungenermaßen tatsächlich hantieren muß... Nö, der (richtig gute) NT-Kernel hat wirklich besseres als den völlig beschissenen Windows-Aufsatz verdient...
@ c-hater (Gast) >> Nein. Auch phne Bootloader kommt die Kennung FAT32 recvht weit am Anfang >> an Offset 82 >Quatsch. Das ist ein FAT-Bootsektor. So weit vorne kommt der nur, wenn >die Karte als "Superfloppy" formatiert ist. Ab Werk sind die Dinger aber >normalerweise als HD formatiert, vor der ersten Partition kommt also >mindestens der MBR in der Größe eines Sektors. Stimmt, da hatte ich mich wohl vertan. >aufweisen. Die dabei generierten Fehlermeldungen füllen ein komplettes >Realsatire-Magazin... Wenn das mal nicht die Männer mit der Kalaschnikov hören . . .
OK,, es geht voran! Es war noch ein Fehler in den IO-Funktionen. Der UART im SPI-Modus ist halt doch ein wenig anders als das normale SPI-Modul, vor allem die FIFOs machen da ein wenig Stress, wenn man nicht aufpasst.
1 | /*-----------------------------------------------------------------------*/
|
2 | /* Transmit/Receive data from/to MMC via SPI (Platform dependent) */
|
3 | /*-----------------------------------------------------------------------*/
|
4 | |
5 | /* Exchange a byte */
|
6 | static
|
7 | BYTE xchg_spi ( /* Returns received data */ |
8 | BYTE dat /* Data to be sent */ |
9 | )
|
10 | {
|
11 | USARTE1.DATA; // clear old data |
12 | USARTE1.DATA; |
13 | USARTE1.DATA; |
14 | |
15 | USARTE1.DATA = dat; |
16 | while(!(USARTE1.STATUS & USART_RXCIF_bm)); |
17 | return USARTE1.DATA; |
18 | }
|
19 | |
20 | /* Send a data block fast */
|
21 | static
|
22 | void xmit_spi_multi ( |
23 | const BYTE *p, /* Data block to be sent */ |
24 | UINT cnt /* Size of data block */ |
25 | )
|
26 | {
|
27 | BYTE tmp; |
28 | |
29 | USARTE1.STATUS = USART_TXCIF_bm; // clear TXC |
30 | USARTE1.DATA = *p++; |
31 | cnt--; |
32 | for (; cnt>0; cnt--) { |
33 | tmp = *p++; |
34 | while(!(USARTE1.STATUS & USART_DREIF_bm)); |
35 | USARTE1.DATA = tmp; |
36 | }
|
37 | while(!(USARTE1.STATUS & USART_TXCIF_bm)); |
38 | |
39 | USARTE1.DATA; // clear rx data buffer |
40 | USARTE1.DATA; |
41 | USARTE1.DATA; |
42 | }
|
43 | |
44 | |
45 | /* Receive a data block fast */
|
46 | static
|
47 | void rcvr_spi_multi ( |
48 | BYTE *p, /* Data buffer */ |
49 | UINT cnt /* Size of data block */ |
50 | )
|
51 | {
|
52 | BYTE tmp; |
53 | |
54 | USARTE1.DATA; // clear rx data buffer |
55 | USARTE1.DATA; |
56 | USARTE1.DATA; |
57 | |
58 | USARTE1.DATA = 0xFF; |
59 | cnt--; |
60 | for (; cnt != 0; cnt--) { |
61 | while(!(USARTE1.STATUS & USART_DREIF_bm)); |
62 | USARTE1.DATA = 0xFF; |
63 | while(!(USARTE1.STATUS & USART_RXCIF_bm)); |
64 | tmp = USARTE1.DATA; |
65 | *p++ = tmp; |
66 | }
|
67 | while(!(USARTE1.STATUS & USART_RXCIF_bm)); |
68 | *p++ = USARTE1.DATA; |
69 | }
|
Mit diesen Funktionen kann ich schon mal Dateien lesen!!! Aber beim Schreiben geht noch was schief!. Öffnen zum Schreibzugriff geht, aber bei f_write() kommt eine Rückgabewert von 1 (FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */) zurück, die Anzahl geschriebener Bytes ist auch Null. Dumm nur, dass dieser Fehler an ziemlich vielen Stellen der Funktion zurückgegeben werden kann. Einen In Circuit Debugger hab ich auch nicht, nur das gute, alte AVR ISP MK II 8-0
Ich habe eine defekte Micro-SD-Karte, die mich unter Linux und einen MP3-Player zur Verzweifelung gebracht hat. Lesen ist noch möglich. Beim Schreiben tut das Betriebssystem so als ob. Danach ist der alte Inhalt der Micro-SD-Karte wieder sichtbar. Nicht das es an einer defekten SD-Karte liegt,. ;-)
@ noreply@noreply.com (Gast)
>Nicht das es an einer defekten SD-Karte liegt,. ;-)
Nein, die ist OK, hab ich gerade probiert. Man kann neue Dateien anlegen
und lesen. Ausserdem habe ich es auch mit einer anderen SD-Karte
probiert, gleiches Ergebnis. Der Dateiname wird angelegt, der inhalt
aber nicht geschrieben :-(
Soweit ich es im Moment eingrenzen kann, scheint die Zuweisung des neuen
(ersten) Clusters für die Datei schief zu gehen! Wie kann das sein? Die
Karte ist nahezu leer!
Also, das Problem ist im Moment, dass bei f_open() KEIN Fehler zurück kommt, die Datei wird auch im Hauptverzeichnis angelegt (kann man am PC sehen), aber der Schreibvorgang f_write() bricht ab, weil scheinbar kein Cluster für die Datei verfügbar ist. Sehr merkwürdig. Ich hab mir mal das ATMELICE bestellt, ich hoffe der Debugger wirft deutlich schneller Licht auf die Sache als meine print_f Orgie.
So, mittels ATMELICE hab ich mich jetzt weiter zum Problem durchgewühlt. Wie es scheint, gibt es ein Problem beim Schreiben der FAT auf die SD-Karte. Wenn mittels CMD24 der FAT-Sektor 0 zurüchgeschieben werden soll, kommt als Anwort der Karte 0xFF, machmal auch 0,1F, wo aber 0x05 erwartet wird. Scheibenhonig! Merkwürdig ist, dass das Directory mit dem erstellten Eintrag der neuen Datei aber beschrieben wird! Häää?? Allerdings sind die Signale auf dem Logicanalyzer nicht ganz plausibel. Am Ende der Übertragung werden 2x 0xFF als Dummybytes für die CRC gesendet, danach nochmal 0xFF um die Antwort der SD-Karte zu bekommen. Aber diese Einzelsendungen müssten auch zeitlich etwas mit Abstand erkennbar sein. Sind sie aber nicht! Der SPI-Takt ist lückenlos und hört dann auf! Mysteriös!
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHHH Ich Depp! Ich hab den Fehler gefunden! Er lag natürlich mal wieder vor der Tastatur! "Also flink die Dateien kopiert, die Low Level Sachen angepasst, los gehts. Oder auch nicht :-(" Denkste! Bei der Schreibroutine hab ich mir, wie bereits bei der Empfangsroutione sauber ins Knie geschossen! Und warum? Wegen des FIFOs!! (Genitiv ins Wasser weil Dativ) Beitrag "Re: Problem mit Micro-SD-Karte" Ich dachte, lösch doch einfach das TXC Flag vor der Übertragung, die leiert dann schön durch und am Ende wird TXC gesetzt. FALSCH! TXC wird ZWISCHENDURCH gesetzt! Warum? Weil die Übertragung des Datenblocks durch Interrupts unterbrochen wird, dadurch läuft der FIFO zwischenzeitlich leer. Jaja, man hätte DMA nehmen können, die bringt hier aber wenig, weil die CPU sowieso warten muss. Ok, also muss man TXC am ENDE der Übertragung VOR dem Senden des letzten Bytes löschen und zwar ATOMAR! Warum? Wenn zwischen das Löschen von TXC und das Senden des letzten Bytes ein Interrupt dazwischenfunkt, wird TXC gelöscht (von vorherigen Sendepausen), die aktuelle Übertragung mit vollem FIFO läuft noch, die ISR blockiert das Laden des letzten Bytes, der FIFO läuft leer und setzt TXC wieder! Nach der Rückkehr der ISR wird das letzte Byte gesendet, die Warteschleife geht aber sofort weiter, weil TXC ja gesetzt ist! Damit holt man sich Probleme im weiteren Ablauf der FAT-Lib! Denn die macht danach noch Einzelübertragungen. Die funktionieren aber nur, wenn die vorherige Blockübertragung VOLLSTÄNDIG abgeschlossen ist! OMG! Das hat mich jetzt $("§&$%")!!! Tage gekostet!!! SCHEIIIIIIIIBENHONG!!! Damit sich die Nachwelt diesen Krampf erspart, hier die Routinen, die sollten jetzt WIRKLICH passen. Einzufügen in mmc.c
1 | // oben einfügen
|
2 | #include <util/atomic.h> |
3 | |
4 | /* Exchange a byte */
|
5 | static
|
6 | BYTE xchg_spi ( /* Returns received data */ |
7 | BYTE dat /* Data to be sent */ |
8 | )
|
9 | {
|
10 | USARTE1.DATA; // clear old data |
11 | USARTE1.DATA; |
12 | USARTE1.DATA; |
13 | |
14 | USARTE1.DATA = dat; |
15 | while(!(USARTE1.STATUS & USART_RXCIF_bm)); |
16 | return USARTE1.DATA; |
17 | }
|
18 | |
19 | /* Send a data block fast */
|
20 | static
|
21 | void xmit_spi_multi ( |
22 | const BYTE *p, /* Data block to be sent */ |
23 | UINT cnt /* Size of data block */ |
24 | )
|
25 | {
|
26 | BYTE tmp; |
27 | |
28 | cnt--; |
29 | for (; cnt>0; cnt--) { |
30 | tmp = *p++; |
31 | while(!(USARTE1.STATUS & USART_DREIF_bm)); |
32 | USARTE1.DATA = tmp; |
33 | }
|
34 | |
35 | // special handling of last byte due to FIFO
|
36 | // and interrupts, which can set TXCIF in between a transfer!
|
37 | tmp = *p++; |
38 | while(!(USARTE1.STATUS & USART_DREIF_bm)); |
39 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { |
40 | USARTE1.STATUS = USART_TXCIF_bm; // clear TXC |
41 | USARTE1.DATA = tmp; |
42 | }
|
43 | while(!(USARTE1.STATUS & USART_TXCIF_bm)); |
44 | |
45 | USARTE1.DATA; // clear rx data buffer |
46 | USARTE1.DATA; |
47 | USARTE1.DATA; |
48 | }
|
49 | |
50 | |
51 | /* Receive a data block fast */
|
52 | static
|
53 | void rcvr_spi_multi ( |
54 | BYTE *p, /* Data buffer */ |
55 | UINT cnt /* Size of data block */ |
56 | )
|
57 | {
|
58 | BYTE tmp; |
59 | |
60 | USARTE1.DATA; // clear rx data buffer |
61 | USARTE1.DATA; |
62 | USARTE1.DATA; |
63 | |
64 | USARTE1.DATA = 0xFF; |
65 | cnt--; |
66 | for (; cnt != 0; cnt--) { |
67 | while(!(USARTE1.STATUS & USART_DREIF_bm)); |
68 | USARTE1.DATA = 0xFF; |
69 | while(!(USARTE1.STATUS & USART_RXCIF_bm)); |
70 | tmp = USARTE1.DATA; |
71 | *p++ = tmp; |
72 | }
|
73 | while(!(USARTE1.STATUS & USART_RXCIF_bm)); |
74 | *p++ = USARTE1.DATA; |
75 | }
|
Kleine Ergänzung. So ist es besser in xmit_spi_multi.
1 | ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { |
2 | USARTE1.DATA = tmp; |
3 | USARTE1.STATUS = USART_TXCIF_bm; // clear TXC |
4 | }
|
Denn damit ist ABSOLUT sicher, dass TXC gelöscht wird. Denn theoretisch besteht die Möglichkeit, dass zwischen dem Schreibzugriff auf .STATUS und .DATA das TXC Flag schon wieder gesetzt ist, auch wenn dort nur wenige Takte dazwischen liegen.
Aber was passiert nun, wenn zwischen dem Daten schreiben und dem TXC-Flag löschen ein Interrupt auftritt, der länger als die Bytelaufzeit ist? Dann löschst Du ein frisch gesetztes TXC-Flag und das wird dann nie wieder gesetzt. Ich denke vorher war´s besser.
:
Bearbeitet durch User
@ Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite >Aber was passiert nun, wenn zwischen dem Daten schreiben und dem >TXC-Flag löschen ein Interrupt auftritt, der länger als die Bytelaufzeit >ist? ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { } > Dann löschst Du ein frisch gesetztes TXC-Flag und das wird dann nie >wieder gesetzt. Ich denke vorher war´s besser. Nö.
Ein kleiner Tip der sich bei mir bewaehrt hat: So frueh wie moeglich auch fuer den SPI-Modus die CRC-Datensicherung einschalten und danach dann alles mit Pruefsummen uebertragen und auswerten. Das macht den Coder erheblich robuster gegen Probleme aller Art. Olaf
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.