Hi, ich hab ein (kleines) Problem bei der Ansteuerung meiner SD Karte. Das Auslesen von Daten aus einer Datei usw. klappt wunderbar, aber es ist mir zu langsam. Ich steuere die Karte via SPI an, mein CPU Takt beträgt 16 MHz... Bei einem Prescaler von 8 (2 MHz) funktionierts noch, beim Prescaler 4 (4 MHz) nicht mehr, woran kann das liegen? Ich dachte die SD Karten kommen mit einem Takt von 20 MHz klar (laut Datenblatt)?? Danke schonmal im Voraus.
Falsches Timing, zu hochohmige Spannungsteiler (falls der µC mit 5V läuft) usw. Ich hatte mit 15MHz SPI Takt bisher noch nie Probleme.
Danke für die schnelle Antwort. Ich benutze ein Pegelwandler (74LVC245) mit einer "Propagation delay time" von maximal 7 ns, das dürfte doch locker für 8 MHz Takt reichen??
Andere Richtung? also du meinst SDO von der SD-Karte aus? Na die Leitung hängt an einem Eingang vom 245er chip, der Ausgang geht dann zum MISO pin am µC (dazwischen noch ein 4,7K Widerstand)..
Kommt der µC mit den 3,3V Pegel zurecht? Da die Pegel vermutlich recht knapp als high erkannt werden, kann es sein, dass dadurch nochmal ein wenig Verzögerung hinzukommt, vor allem mit dem 4,7k Widerstand. Lass den mal weg.
im Datenblatt vom ATmega128 steht nur die Output Spannung Output Low Voltage (Ports A,B,C,D, E, F, G) : 0,7 V Output High Voltage (Ports A,B,C,D, E, F, G) : 4.2 V Aber beim TWI Steht bei Input High: 0,7*Vcc das wären 3,5 V und 3,3 V wären dann schlecht... die Frage ist dann nur, warum es bei 2 MHz überhaupt funktioniert? Gibt es ne schnelle Möglichkeit den Pegel anzuheben ohne noch so ein IC zu verwenden und ohne die Spannung des µC zu verändern?
Die Ausgangsspannungen interessieren hier nicht, die Eingangsspannungen sind wichtig: Input High Voltage except XTAL1 and RESET pins: 0.6*VCC, also 3V bei 5V. Bei 3,3V Spannung sind das nur 0,3V mehr, was eben zusammen mit dem 4,7k Widerstand eine zusätzliche Verzögerung bewirkt. Versuch es mal ohne den Widerstand. Die beste Lösung wäre ein HCT245 oder irgendwas in der Art, denn dieser hat Schaltschwellen bei etwa 0,8V bzw. 2V. Am Ausgang liefert er 0V/5V.
naja aber ich kann den LVC245 nicht durch den HCT ersetzen sondern brauch wieder ne extra schaltung...mist, hätt ich mir vorher überlegen sollen.. Ohne den Widerstand gehts garnicht, nicht mal bei nem Takt von 125 KHz, mit dagegen einwandfrei, wieder bis 2 MHz...
Ich meinte den HCT125 zusätzlich zum LVC245 für die andere Richtung. Hast du den richtigen SPI Modus gewählt? Und häng mal einen Pullup (irgendwas im Bereich 10-100k) an den Ausgang des SD Karte.
So sieht mein SPI Init aus: SPI_DIR |= (1 << MOSI) | (1 << SCK) | (1 << SS); SPI_PORT |= (1 << MOSI) | (1 << SCK) | (1 << SS); SPI_DIR &= ~(1 << MISO); SPCR = (1 << MSTR) | (1 << SPE); SPCR |= (1 << SPR0) | (1 << SPR1); SPSR |= (1<<SPI2X); kann kein pullup mehr dazwischen klemmen ohne die schaltung zu zerstören, ist schon fertig geätzt :(
Hirbel wrote: > kann kein pullup mehr dazwischen klemmen ohne die schaltung zu > zerstören, ist schon fertig geätzt :( Schlecht, der ist aber notwendig, siehe hier: Beitrag "Re: Adressierung der Daten auf einer SD-Karte?" Ansonsten passt der SPI Modus.
also auf dem Board, das vom Thread-Teilnehmer benutz wird, ist auch nirgends ein Pullup widerstand dran: http://heldt-intern.dyndns.org/uploads/pdf/Experimentierboard-Schematic.pdf
Vermutlich hat er den internen Pullup aktiviert, was bei dir nicht geht, da du den LVC245 dazwischen hast.
Warum hab ich den eigentlich dazwischen?? ich versuch mal ne umleitung direkt zum µC pin zu bauen und aktiviere ebenfalls den internen pullup..
Okay, jetzt läufts mit 8 MHz....mehr ist ja nicht drin beim Hardware SPI (16 MHz CPU Takt) oder??
Ja es lag daran und an den LVC, keine ahnung warum ich die Outputdaten von der SD Karte noch dadurch jagen wollte.... ich habe jetzt eine Rate von 512 Bytes in 7 µs das sind doch knapp 70 MB/s, kann das stimmen?
dachte ich mir, bitte einmal vorrechnen was nun wirklich rauskommt :)
Die 512Byte pro 7µs zweifele ich hiermit öffentlich an.
meine messung habe ich wie folgt vorgenommen: Sd Karte initialisiert. Datei geladen. Timer wie folgt initialisiert: TCCR1A=0x00; TCCR1B=0x01; //Prescaler 1 -> 16 MHz TCNT1=0x10000 - 16; //---> 1 MHz -> jede µs ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; Timer gestartet (mit TIMSK=0x04) -> Timerinterrupt jede µs->zähler wird erhöht, TCNT1 wird zurückgesetzt Ein Block (512 Bytes) angefordert Timer gestoppt (mit TIMSK=0x04) Ausgabe der 512 Bytes (sind korrekt) und ausgabe des Zählers (7 µs) wo ist der Fehler?? Kann ja nur beim timer sein
Hirbel wrote: > Timer gestartet (mit TIMSK=0x04) > -> Timerinterrupt jede µs->zähler wird erhöht, TCNT1 wird zurückgesetzt Alle 16 Takte ein Interrupt? Vergiss es! > Ausgabe der 512 Bytes (sind korrekt) > und ausgabe des Zählers (7 µs) Mit ein wenig Nachdenken hättest du eigentlich selbst drauf kommen können, dass dies nicht sein kann: SPI hat 8MHz, also 8MBit/s. 512Byte sind 4kBit. Wenn du für 8bit 1µs brauchst, dann kannst du in 7µs maximal 56Bit übertragen, aber nie 4kBit.
na ich habe ja glaube geschrieben das es nicht sein kann... habe den fehler gefunden...beim zurücksetzen von TCNT1 stand ein alter wert drin.... so komme ich auf 7 ms und grad mal 71 KByte/s ...langsam....
Ahaaa. Rein theoretisch sind 512Bytes gut einer halben ms drin, wenn Dein Controller nichts anderes mehr machen muß. Also macht Dein Controller die anderen 6 1/2 ms noch irgendwelchen anderen Kram. Vielleicht kannst Du da noch optimieren. Oder aber der Controller wartet auf ein Busy von der Karte. Da könnte dann nur noch das Kommando "MultiBlockRead" etwas helfen. Ich erreiche bei meinen Karten bei 16Mhz SPI (XMega@32Mhz) etwas über 400kByte/s beim Single Block lesen. Du kannst natürlich auch Deinen Controller übertakten. 25Mhz machen die meisten ATMEGAs problemlos mit.
Travel Rec. wrote: > Ahaaa. Rein theoretisch sind 512Bytes gut einer halben ms drin, wenn > Dein Controller nichts anderes mehr machen muß. Also macht Dein > Controller die anderen 6 1/2 ms noch irgendwelchen anderen Kram. Ja, nämlich das hier: > TCCR1B=0x01; //Prescaler 1 -> 16 MHz > TCNT1=0x10000 - 16; //---> 1 MHz -> jede µs > ICR1H=0x00; > ICR1L=0x00; > OCR1AH=0x00; > OCR1AL=0x00; > OCR1BH=0x00; > OCR1BL=0x00; > > Timer gestartet (mit TIMSK=0x04) > -> Timerinterrupt jede µs->zähler wird erhöht, TCNT1 wird zurückgesetzt Wenn der AVR jede µs einen Interrupt ausführt, dann geht da fast die ganze Rechenleistung drauf. So eine Zeitmessung macht man anders: Den Timer auf 0 setzen und starten. Im Overflow Interrupt eine weitere 8/16bit Variable erhöhen. Nun hast du zusammen mit dem 16bit Timer einen 24/32bit Zähler mit 62,5ns Auflösung und einem Messbereich bis 1s/256s. Wenn du fertig bist, stoppst du den Timer mit TCCR1B=0; Nun kannst du das Timer Register und die Variable auslesen und ausgeben. Ich wette dann bist du mindestens doppelt so schnell. Beim Lesen sind die SD Karten in der Regel sehr schnell, so dass fast nur der SPI Takt + Overhead zwischen den Bytes eine Rolle spielen. Ich schreibe sogar mit rund 100kByte/s mit einem mega8 @10MHz...
@Benedikt: Kannst du das nochmal genau erklären mit dem timer und der Zeitmessung? Hab ich grad nich wirklich verstanden....
Du benutzt den Timer nicht als Timer zur Erzeugung eines Zähltaktes, sondern lässt den Timer direkt bis 65535 zählen. Bei 16MHz Takt gibt es so nur mit 244Hz einen Overflow Interrupt. Im Interrupt erhöhst du eine weitere Variable, falls ein Messbereich bis 4ms nicht reicht.
Also mit den Timereinstellungen komme ich auf folgendes: 16bit Zähler = 1 --> 4,096 ms TCNT1 = 41860 --> 2,61625 ms = 6,71225 ms Das ist keine wirkliche Verbesserung...was mache ich falsch??
Irgendwie kommt mir das etwas komisch vor: Wenn du vorher wirklich den Timer alle 1µs einen Interrupt hast ausführen lassen, dann wäre diese zu (4 Takte Interrupteintritt, 4 Takte um Register zu retten, und das ganze nochmal beim Verlassen, also 16 Takte insgesamt, dann nochmal 10 Takte um eine 16bit Variable zu erhöhen, macht also mindestens mal 26 Takte. Deine erste Messung war vermutlich also komplett falsch. Da deine zweite Messung fast dasselbe Ergebnis liefert, und bei der ersten Messung der µC eigentlich die ganze Zeit im Interrupt verbringen müsste, kann da irgendwas nicht passen.
meine interrupt routine sieht so aus: _timer1_overflow: ST -Y,R30 ST -Y,R31 IN R30,SREG ST -Y,R30 MOVW R30,R6 ADIW R30,1 MOVW R6,R30 LD R30,Y+ OUT SREG,R30 LD R31,Y+ LD R30,Y+ RETI Sind genau 22 Takte (Codevision compiler)... also ich weiß nich wo der fehler liegt :(
welchen rest denn? die ganzen sd-karten routinen für die ansteuerung? neee das ist zu viel... wenn bei beiden Messungen 7 ms rauskommt, warum sollte es da einen Fehler geben, ich versteh das nich so ganz...
Hirbel wrote: > meine interrupt routine sieht so aus: > > _timer1_overflow: > ST -Y,R30 > ST -Y,R31 > IN R30,SREG > ST -Y,R30 > MOVW R30,R6 > ADIW R30,1 > MOVW R6,R30 > LD R30,Y+ > OUT SREG,R30 > LD R31,Y+ > LD R30,Y+ > RETI > > Sind genau 22 Takte (Codevision compiler)... > also ich weiß nich wo der fehler liegt :( Wenn der Code (bzw. etwas ähnliches das du vorher hattest) 22 Takte braucht, er aber alle 16 Takte ausgeführt wurde, dann kann da was nicht passen. Wenn du es nun anders machst, und immer noch das selbe rauskommt, dann kann da was nicht passen.
na das mit den 22 Takten bekomme ich ja nun nicht kleiner hin... ich könnte den timer langsamer laufen lassen, so das ich garkeine Intterupt routine brauche, sonder TCNT1 ausreicht, also nie der overflow erreicht wird... aber ich wette da kommt dann das gleich raus
>wenn bei beiden Messungen 7 ms rauskommt, warum sollte es da einen >Fehler geben, ich versteh das nich so ganz... Weil 7ms das 7-fache davon ist, was der Controller eigentlich an Zeit braucht, um die Daten auf der Karte abzulegen. Wenn Kartenschreibzeit und andere Routinen im zeitlichen Verhältnis von etwa 1:1 vorliegen würden, würde ich ja gar nichts sagen. Aber so vertrödelst Du einfach irgendwo Zeit, die Du vielleicht andernorts brauchen könntest.
Hirbel wrote:
> na das mit den 22 Takten bekomme ich ja nun nicht kleiner hin...
Darum gehts ja auch nicht.
Ich machs mal an einem einfachen Beispiel:
Du liest ein Buch mit 512 Seiten.
Du liest nur 1h pro Tag, da du die restliche Zeit mit etwas anderem
zubringst.
Jetzt liest du das Buch nochmal, diesmal liest du aber 23h pro Tag.
Trotzdem brauchst du 512 Tage.
Wenn du beidesmal genausoschnell gelesen hast, dann muss irgendwo ein
Fehler sein, denn dann kann das nicht stimmen.
Wenn du alle 1µs, also alle 16 Takte den Timer Interrupt ausführst,
dieser aber 22 Takte braucht, dann
- passt die Zeitmessung nicht
- ist der Prozessor zu 22/23, also 96% mit dem Timer Interrupt
beschäftigt
Wenn dein Code hierbei genausolange braucht, als wenn er nur z.B. 1% im
Timerinterrupt verbringt, also 99% der Rechenleistung zum Lesen hat,
dann kann irgendwas nicht stimmen.
Zeig also mein deinen ganzen Code!
sooo der timer lief jetzt mit 2MHz. TCNT1 hatte den Wert 13423, das sind wieder 6,7115 ms die Messung ist also korrekt oder nich? es stimmt schon, das ich zeit vertrödele, in dem ich auf die SD karte warte (busy wait) aber das geht doch nun mal nich anders ??
Wie alt ist denn die SD Karte? 70kByte/s ist schnarchlahm. Die Zugriffszeit beim Lesen ist eigentlich vernachlässigbar klein (meist irgendwas im 2 stelligen µs Bereich). Zumindest hatte ich noch keine Karte, die länger gebraucht hat.
ja die ist schon entwas älter und sieht sehr mitgenommen aus... anbei mal die sd.c, fat32.c (nicht alles auf meinem mist gewachsen) und die main.c (steht auch anderes zeug drin -> nicht beachten). also ein wenig zeit geht auch drauf, weil er zu einer bestimmten stelle in einer datei springt...aber das ist nicht viel (hab ich schonmal auskommentiert)
hab mal ne neuere Karte genommen, da sinds jetzt immerhin "nur" noch 6,6555 ms ;) kann es evtl. sein, das es an der takt oder datenleitung liegt? hab dafür nur ein 0,2 mm kupferlackdraht genommen und alle leitungen zusammengedreht....???
Achso, du liest nicht nur die Daten, sondern suchst erst noch den Sektor aus der Cluster Chain usw. Das erklärt einiges. Les mal z.B. 16x 512Bytes und mess dabei mal die Zeit. Dann sollten deutlich >100kByte/s rauskommen. Meine Erfahrung war bisher, das die Datenrate bei bis zu rund der Hälte des der SPI Frequenz liegt, also bei dir bei rund 4MBit/s=500kByte/s. Hängt natürlich auch von der Geschwindigkeit des Prozessors usw. ab. In der sd.c könntest du bei der Lesefunktion noch *(buffer + i) = card_sendbyte(0xFF); durch *buffer++ = card_sendbyte(0xFF); ersetzen, das sollte der Compiler deutlich besser optimieren können. Und die card_sendbyte Funktion selbst, die solltest du als inline deklarieren, denn der Sprung + Rücksprung dauert fast so lange wie das Lesen selbst. Und die Timeoutabfrage in der Funktion ist eigentlich auch unnötigt. Nach 16 Takte ist der SPI Transfer fertig, wenn nicht dann ist irgendwo was gewaltig schief gelaufen, da hilft dann auch keine Abfrage mehr. Ansonsten sieht der Code gut aus. Wenn du mehrere Blöcke liest, und den Code wie angegeben etwas optimiert, dann sollten definitiv >100kByte/s rauskommen.
okay, ich hab das mit dem buffer abgeändert und 10 mal die gleichen 512 bytes gelesen (ohne Seek, also vom anfang der datei)... und man glaubt es kaum, aber ich komme auf 7,067 ms für 512 bytes :(
Versuch mal die Änderungen in die Software einzubauen, vor allem das mit dem inline sollte eigentlich rund 50% mehr Geschwindigkeit bewirken.
Am Besten liest du mal 10.000 Bloecke und stopst mit der Uhr ;-)
ach naja ich lass das jetzt erstmal so, alles in asm umzuschreiben, da hab ich jetzt keine lust zu 70KByte sind ja 560 kbit/s das dürfte für mp3 anwendungen ausreichen? Kannst mir aber auch deine routinen zur verfügen stellen, wenn du willst :) Vielen Dank aber erstmal für doe Hilfe.
Hirbel wrote: > ach naja ich lass das jetzt erstmal so, alles in asm umzuschreiben, da > hab ich jetzt keine lust zu Musst du auch nicht. Mit dem Code von ELM-Chan erreiche ich >200kByte/s (alles in C). http://elm-chan.org/fsw/ff/00index_e.html > 70KByte sind ja 560 kbit/s das dürfte für mp3 anwendungen ausreichen? Ja, sollten eigentlich. Mehr als 320kBit/s gibt es bei den normalen mp3s ja nicht.
okay, werd den code mal testen.. wie sieht es eigentlich mit SDHC karten aus?? funktionieren die auch (mit dem gleichen code für normale SD karten) oder funktionieren die anders oder garnicht?
Die Routinen von ELM Chan können glaube ich SDHC ausprobiert habe ich es noch nicht.
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.