Hallo,
ich möchte mit einem Atmega32 (2kB SRAM) Daten auf eine µSD Karte
speichern.
Der µC läuft mit 14,7456MHz, SPI läuft mit einer Endgeschwindigkeit von
fosc/2 und zum Beschreiben der Karte benutze ich Elm Chan's FatFs
(R0.13).
Die 8 Analogeingänge (mit 10 bit) des Atmega möchte ich mit je 1kHz
auslesen und die Werte abspeichern, es fallen also 8000 Samples/Sekunde
an.
Als Karte benutze ich eine Medion 4GB SDHC Class 10 die auf Fat32
formatiert ist. Alternativ habe ich noch eine 8GB Sandisk SDHC Class 10,
die aber nochmal rund 50% langsamer.
Ich habe den FatFs Beispielcode so weit lauffähig bekommen und testweise
in einer Schleife mit f_write ein char-Array mit unterschiedlichen
Größen weggeschrieben, ohne selber f_sync zu benutzen. Geschrieben wird
in ein einziges Dokument.
Dabei habe ich zum Beispiel 2048*32 Byte in ca. 1640ms geschrieben, was
ca. 78 kB/s ergibt. Bei 512*256 Byte in ca. 1530ms sind das ca. 84,8
kB/s.
Also scheinen größere zusammenhängende Datenmengen schneller in den
Puffer geschrieben zu werden. Flushen müsste er ja in beiden Fällen nach
je 512 Byte automatisch.
Einen großen Unterschied zwischen den Konfigurationen FF_FS_TINY 0 bzw.
1 konnte ich nicht feststellen.
Leider ist das vom Datendurchsatz nicht so hoch wie erhofft. Ideal wären
Geschwindigkeiten von rund 250 kB/s, die erreiche ich aber aktuell bei
weitem nicht. (Eigentlich wollte ich jeden Messwert mittels f_printf mit
Datum, Uhrzeit, Namen und Trennzeichen auf die SD Karte schreiben, damit
die am PC direkt in Excel eingelesen werden können, dafür würden 32 Byte
pro Sample anfallen.)
Die ffconf.h sieht bei mir zurzeit so aus: (Vielleicht habe ich da ja
schon etwas wichtiges übersehen.)
Die SPI Geschwindigkeit müsste also nach dem Initialisieren bei fosc/2
liegen. Nachmessen kann ich es leider nicht.
Das Vormerken von Speicher (Pre-Allocation) mit f_lseek oder f_expand
habe ich bisher noch nicht ausprobiert.
Merkt er sich dabei eigentlich immer die gleichen Speicherbereiche auf
der Karte vor, sprich erhöht das die Abnutzung der Karte? Das soll
soweit ich es gelesen habe die Schreibgeschwindigkeit erhöhen, was für
Nachteile entstehen dadurch?
Und wie viel schneller ist man damit unterm Strich?
Allgemein würde ich gerne wissen:
* Was für Schreibraten kann man mit FatFs bei einem Atmega über SPI im
Schnitt erreichen? Vielleicht kann ja der Eine oder Andere
Erfahrungswerte mit seiner Konfiguration (MCU, Karte, Takt- und
SPI-Frequenz) teilen.
* Mit welchen Maßnahmen man mit FatFs die besten
Schreibgeschwindigkeiten erreichen kann.
Seien es FatFs Optionen (z.B. FF_FS_TINY 0/1), die Art und Weise, wie
man die FatFs Funktionen benutzt (f_write oder f_printf einfach irgendwo
im Programmcode aufrufen o.Ä.) oder wie man die zu schreibenden Daten
bereitstellt/zuführt (was bringt z.B. ein FiFo Puffer, aus dem man
f_write speist oder wie groß sollten die einzelnen Datenpakete je
f_write sein).
Also was die wichtigsten Stellschrauben / Fallstricke sind, um gute
Schreibgeschwindigkeiten mit FatFs zu erreichen.
Wäre großartig, wenn man hier etwas zusammentragen könnte. Denn langsam
habe ich Zweifel, ob ich die von mir angepeilten
Schreibgeschwindigkeiten mit der Hardware überhaupt erreichen kann.
Schöne Grüße
Mit 80kB/s hast du bereits mehr erreicht, als die meisten anderen. Ich
schätze, dass du im SPI Modus nicht viel mehr erreichen kannst.
Ärgerlicher ist hingegen, dass diese Karten sich spontan mal mit etwas
anderem beschäftigen und plötzlich einige 100ms lang nicht mehr
antworten. Dafür brauchst du einen ausreichend großen Puffer.
Stefan U. schrieb:> Mit 80kB/s hast du bereits mehr erreicht, als die meisten anderen. Ich> schätze, dass du im SPI Modus nicht viel mehr erreichen kannst.
Doch, das kann man. Der begrenzende Faktor ist nicht die
SPI-Geschwindigkeit, wie man sehr leicht ausrechnen kann. Schließlich
bedeutet ca. 7MHz SPI-Takt einen Bruttodurchsatz von nicht weniger als
875kB/s, also mehr als das Zehnfache des erreichten Nettodurchsatzes.
> Ärgerlicher ist hingegen, dass diese Karten sich spontan mal mit etwas> anderem beschäftigen und plötzlich einige 100ms lang nicht mehr> antworten. Dafür brauchst du einen ausreichend großen Puffer.
Das ist nur ein Aspekt der Sache. Aber dieser Aspekt führt genau wie
alle anderen nur zu einer Lösung: man braucht viel mehr RAM im µC.
ElmChan's Werk kann zumindest bei einigen der Aspekte von zusätzlichem
RAM profitieren (mit entsprechender Konfiguration), deswegen ist die
einfachste Lösung, den Mega32 schlicht durch einen Mega1284P zu
ersetzen, der immerhin 16k RAM bereitstellt, ansonsten aber relativ
weitgehend Pin- und Softwarekompatibel zum Mega32 ist. Damit kann man
dann schon mit FatFS irgendwas um die 300kB/s (bei dem gegebenen
SPI-Takt) erreichen.
Schneller geht's nur, wenn man sich von dieser eierlegenden Wollmilchsau
trennt und etwas von vorherein auf "relativ viel Buffer verfügbar"
optimiertes programmiert. Damit kann man etwa 85..90% des durch die
SPI-Anbindung vorgegebenen theoretischen Maximums als Dauerleistung beim
Schreiben erreichen.
Alternativ kann man auch FatFS weiter verwenden, aber eine puffernde
Schicht zwischen dem eigentlichen FatFS und dem physischen Zugriff auf
die Karte einfügen. Das ist performancemäßig sehr nahe an der optimalen
Lösung, allerdings nur dann, wenn wirklich viel Puffer-RAM verfügbar
ist. Leider deutlich zu viel auch für einen Mega1284P. Sprich: diese
Variante ist zwar programmiertechnisch deutlich einfacher zu
realisieren, aber auch sehr viel ineffizienter, denn selbst mit dem real
auf einem Mega1284P verfügbaren RAM bringt sie nur sehr wenig
zusätzlichen Gewinn. Den Aufwand nicht wert. Das wäre allenfalls eine
Option für Megas mit externem RAM.
c-hater schrieb:> Damit kann man> dann schon mit FatFS irgendwas um die 300kB/s (bei dem gegebenen> SPI-Takt) erreichen.
Zeig mal bitte :-)
Ich schaffe ähnliches - aber nur, weil ich den DMA-Modus des ATXMega in
Verbindung mit RAW-Schreiben auf Sektor-Ebene (ohne FAT..) nutze.
Bei meinen Datensampler schreibe ich immer binär weg.
Datum, Uhrzeit das passt auch in einem 32 Bit time_t. Trennzeichen
braucht man nicht. Immer gleiche Record-Längen und dann rein ins Flash.
Zum Auswerten später braucht man ja eh ein extra Auswerteprogramm. Das
kann dann die Zeiten menschenlesbar machen, die Rohwerte filtern und in
Einheiten umrechnen. Ein PC hat genug Rechenleistung dafür.
PittyJ schrieb:> Zum Auswerten später braucht man ja eh ein extra Auswerteprogramm. Das> kann dann die Zeiten menschenlesbar machen,
Ich mache es umgekehrt und nutze Python :-)
Ich hatte mal einen Atmega mit 16MHz, SD Karte und einem Ethernet Chip
als mp3 Player gebaut.
Über FTP hat der 120kB/s lesend und 80kB/s schreibend erreicht. Das sind
so ungefähr deine Werte. Wobei davon natürlich signifikant viel Zeit
fürs Netzwerk drauf ging. Ich meine die Schreibwerte hatte ich auch erst
erreicht, nachdem ein paar Sektoren immer gebuffert wurden. Sonst muss
der beim Schreiben jedes mal noch die FAT Tabelle holen, ändern,
zurückschreiben. Eventuell ist da also noch was bei dir (auf Kosten von
RAM) zu holen. Ansonsten 8000Samples/Sekunde, jeweils 16Bit binär
kodiert -> 16KB/s -> reicht doch?
Wenn du aber alles in Dezimal umrechnest sind das ne menge Divisionen,
und die Kosten auf nem AVR wirklich Zeit:
https://www.mikrocontroller.net/articles/ArithmetikBenchmark
Rechne dann mal mit einer Division pro Dezimalstelle. 10Bit->5 Stellen
-> 245Takte pro Division -> 1225 Takte pro Wert * 8000 -> ~10MHz nur
fürs dividieren.
Also hab nicht letztens mit dem SPI des Atmega beschäftigt. Auf der
Seite SPI geht's zu diesem Link. Da geht's um die Optimierung des
Quelltexts. Bzw um ein schnelleres schreiben von SPI Busses.
http://www.matuschek.net/atmega-spi/
>Da geht's um die Optimierung des>Quelltexts. Bzw um ein schnelleres schreiben von SPI Busses.
Richtig schnell geht es mit dem USART als
SPI Master. Der ist in Senderichtung doppelt gepuffert beim Atmega.
Ich befürchte, dass Du ohne grosse RAM-Puffer keine zuverlässige
Datenrate hinbekommst. Sobald ein Sektor auf der SD Karte voll ist, muss
ja der Block Lookup neu geschrieben werden und der nächste Sektor zum
Schreiben gefunden werden, etc. .
Ein echter Zeitfresser ist auch printf in all seinen varianten, weil der
Controller den Formatierstring erst byte für byte interpretieren muss.
Ausserdem ist ASCII natürlich immer auch extrem verschwenderisch, da ja
im Prinzip nur 5bit von 8bit überhaupt signifikant sind.
Schau doch mal so genau wie möglich, wo der Flaschenhals ist. Ist das
wirklich der SPI? Oder eher der FatFs? Oder warten alle auf prinf()?
Gefühlsmässig wäre mein Ansatz, die Daten stark zu komprimieren. Der
Timestamp ist fast komplett überflüussig, wenn du mit einer festen Rate
samplest. Oder schreib halt nur den Delta-Wert in 1000tel Sekunden zum
vorherigen Sample. Ändern sich die Analogwerte wirklich alle 1000 mal
pro Sekunde, oder muss man nur die wegschreiben, die sich wirklich
ändern? Dann noch alles binär wegschreiben mit ner simplem Runlength
Encoding Kompression, und Du kommst plötzlich mit der Datenrate hin -
und Deine SD Karte lebt auch viel länger.
holger schrieb:> Richtig schnell geht es mit dem USART als> SPI Master. Der ist in Senderichtung doppelt gepuffert beim Atmega.
wirklich schneller wirds damit aber nicht. Hab das mit einem spi-tft
ausprobiert.
Es gibt die Möglichkeit ohne fat direkt auf die Karte zu schreiben:
Beitrag "Re: Geschwindigkeitsfrage AVR auf SD"
Wenn es auf Geschwindigkeit ankommt, sollte man auf stm32/sdio
umsteigen.
grundschüler schrieb:> Wenn es auf Geschwindigkeit ankommt, sollte man auf stm32/sdio> umsteigen.
Zeig mal :-) (analog C-Hater, der sich ja nicht zurück gemeldet hat)
>> Mit 80kB/s hast du bereits mehr erreicht, als die meisten anderen. Ich>> schätze, dass du im SPI Modus nicht viel mehr erreichen kannst.> Der begrenzende Faktor ist nicht die SPI-Geschwindigkeit
Das wollte ich damit auch nicht sagen. Dass die SPI Schnittstelle viel
höhere Datenraten unterstützt, ist ja offensichtlich. Ich denke eher,
dass der Knackpunkt die "Denkpausen" der SD Karte sind, und dass sie im
SPI Modus eher nicht auf Performance optimiert arbeiten.
Stefan U. schrieb:> Ärgerlicher ist hingegen, dass diese Karten sich spontan mal mit etwas> anderem beschäftigen und plötzlich einige 100ms lang nicht mehr> antworten. Dafür brauchst du einen ausreichend großen Puffer.
Mit dem Problem beschäftige ich mich auch im Moment.
(PIC18F27J53, FatFS, verschiedene Sensoren mit 5kHz-100Hz-33Hz
Abtastrate und 16bit Daten)
Dafür zwei Buffer mit 352Bytes, die in wechselweise in 30ms gefüllt und
an FatFS weitergereicht werden.
Bei den ersten Versuchen mit einer älteren microSD Karte kam die große
Ernüchterung. Regelmäßig 250ms und mehr in denen kein Schreiben auf die
Karte möglich ist.
Ich habe inzwischen verschiedene microSDHC Karten ausprobiert, von denen
bisher nur eine, auch bei stundenlangen Aufzeichnungen, nie eine größere
Auszeit nahm als 25ms. Die kann ich dann leicht mit einem größeren
Buffer oder mehr Buffern überbrücken.
Die "gute" Karte war eine Intenso microSDHC 8GB Class 10 (3413460)
Durchgefallen (mit großen Ausfallzeiten) sind:
- PLATINUM microSDHC 4GB Class 4 (177315)
- PHILIPS microSDHC 4GB Class 6 (FM04MD35B)
- Samsung Evo 16GB Class 10 / U1
- 2GB Standard microSD Karten
Hat jemand vielleicht schon weitere gute oder auch schlechte Erfahrungen
mit anderen Karten gesammelt? z.B.:
- KINGSTON 32GB microSDHC/SDXC UHS-I Class U3 (SDCA3/32GBSP)
- KINGSTON 16GB microSDHC UHS-I Class U3 (SDCG/16GB)
Stefan U. schrieb:> Ich denke eher,> dass der Knackpunkt die "Denkpausen" der SD Karte sind, und dass sie im> SPI Modus eher nicht auf Performance optimiert arbeiten.
Das denke ich nicht. Auch der SPI-Modus kann recht flott sein.
Ich beschreibe SD-Karten im SPI-Modus mit bis zu 5-600 KB/s. Allerdings
mit einem ColdFire (22 MHz SPI-CLK).
Markus F. schrieb:> Ich beschreibe SD-Karten im SPI-Modus mit bis zu 5-600 KB/s.
Bisher keine "Denkpausen" aufgefallen, oder einfach nur genügend
Zwischenspeicher vorgesehen?
Welche Karte, wäre auch noch interessant...
Volker S. schrieb:> Markus F. schrieb:>> Ich beschreibe SD-Karten im SPI-Modus mit bis zu 5-600 KB/s.>> Bisher keine "Denkpausen" aufgefallen, oder einfach nur genügend> Zwischenspeicher vorgesehen?> Welche Karte, wäre auch noch interessant...
Keine, die mich stören würden. Die Karte spielt dabei eher eine
untergeordnete Rolle. In meinem Fundus habe ich nur eine (eine der
ersten Micro-SD's mit Adapter) die merklich lahmt und nur etwas mehr als
die Hälfte schafft. Der Rest ist (100 KB/s hin oder her) fast
vergleichbar.
Wenn Du mit einem geringen SPI-Takt drangehst, werden die Denkpausen
naturgemäß auch länger, denke ich. Wie hoch kannst Du gehen?
Markus F. schrieb:> Wenn Du mit einem geringen SPI-Takt drangehst, werden die Denkpausen> naturgemäß auch länger, denke ich. Wie hoch kannst Du gehen?
Ich habe bisher nicht getestet, wie sich der SPI Takt auf die Pausen
auswirkt. Bisher habe ich wenig Erfahrung mit SD Karten. Ich kann mir im
Moment nicht so recht vorstellen, wie sich der SPI Takt auf etwas
auswirken soll das in der Karte vorgeht (zwischengespeicherten Sektor
ins Flasch schreiben oder was auch immer...), wäre aber für jeden
Hinweis dankbar!
Die Hardware stammt aus einer Bachelor-Aschluss-Arbeit und wegen eines
kleinen Designfehlers wird momentan Software-SPI verwendet.
Der SPI-Clock ist ~2MHz. Das Schreiben von 512 Bytes dauert ~4,3ms.
Wenn ich kontinuierlich schreiben könnte/würde, dann sollten das etwas
über 100kByte/s sein. Daten zum Schreiben habe ich im Moment ~12kByte/s.
Das ist also im Zeitlichen Mittel kein Problem.
Blöd sind nur die langen Pausen, in denen kein Schreiben möglich zu sein
scheint und dass auf so einem (mickrigen ;-) 8Bitter nicht eben viel RAM
zum Zwischenspeichern verfügbar ist.
Jetzt stellt sich die Frage nach "besseren Karten", oder eben einem
anderen Controller. Andere Karte einstecken wird natürlich erst mal
bevorzugt ;-)
Volker S. schrieb:> Ich habe inzwischen verschiedene microSDHC Karten ausprobiert, von denen> bisher nur eine, auch bei stundenlangen Aufzeichnungen, nie eine größere> Auszeit nahm als 25ms. Die kann ich dann leicht mit einem größeren> Buffer oder mehr Buffern überbrücken.>> Die "gute" Karte war eine Intenso microSDHC 8GB Class 10 (3413460)
Korrektur - die Freude war leider nur von beschränkter Dauer. Nach
einigen Stunden/einigen 100MB zeigt die Karte ähnliches Verhalten wie
die anderen. (>100ms kein Schreibzugriff)
Volker S. schrieb:> Stefan U. schrieb:>> Ärgerlicher ist hingegen, dass diese Karten sich spontan mal mit etwas>> anderem beschäftigen und plötzlich einige 100ms lang nicht mehr>> antworten. Dafür brauchst du einen ausreichend großen Puffer.>> Mit dem Problem beschäftige ich mich auch im Moment.> (PIC18F27J53, FatFS, verschiedene Sensoren mit 5kHz-100Hz-33Hz> Abtastrate und 16bit Daten)
Das Problem ist, dass SD-Karten ebenso wie beispielsweise SSDs keine
transparenten Schreibzugriffe ermöglichen, weil da eben noch ein kleiner
Controller zwischen deinem uC und dem Flash sitzt, der sich
beispielsweise um Wear-Leveling kümmert. Die SD-Spec sieht
Schreiblatenzen von bis zu 500ms(!) vor. D.h. dein Buffer muss
mindestens so groß sein, dass du diese Zeit überbrücken kannst, also für
deine Anwendung in etwa 5kB, womit der PIC18F27J53 prinzipiell nicht
dienen kann.
Christopher J. schrieb:> Die SD-Spec sieht> Schreiblatenzen von bis zu 500ms(!) vor. D.h. dein Buffer muss> mindestens so groß sein, dass du diese Zeit überbrücken kannst...
Sieht im Allgemeinen wohl ganz so aus.
Für unsere spezielle Anwendung kann es eventuell erst mal tolerierbar
sein, kurze Aussetzer in der Aufzeichnung zu haben.
Das darf dann aber "relativ" selten passieren und wir müssen die
Information mit abspeichern wie lange die Pause war.
@Michael K. (natulo)
>Die 8 Analogeingänge (mit 10 bit) des Atmega möchte ich mit je 1kHz>auslesen und die Werte abspeichern, es fallen also 8000 Samples/Sekunde>an.
Macht 16kB/s. Schafft man locker.
>Als Karte benutze ich eine Medion 4GB SDHC Class 10 die auf Fat32>formatiert ist. Alternativ habe ich noch eine 8GB Sandisk SDHC Class 10,>die aber nochmal rund 50% langsamer.
Interessiert hier nicht, mit SPI und AVR kriegst du die nicht mal
ansatzweise ausgelastet.
>Dabei habe ich zum Beispiel 2048*32 Byte in ca. 1640ms geschrieben, was>ca. 78 kB/s ergibt. Bei 512*256 Byte in ca. 1530ms sind das ca. 84,8>kB/s.
Lahm.
Beitrag "Re: Geschwindigkeitsfrage AVR auf SD"
Ich hab mal einen DMX-Rekorder programmiert, dort wurden 22kB/s von
SD-Karte gelesen/schreiben und per UART empfangen/gesendet. Die mittlere
CPU-Last lag bei ~30% @16MHz.
Beitrag "Re: Atemega328p - schaffst du das?"
Volker S. schrieb:> Für unsere spezielle Anwendung kann es eventuell erst mal tolerierbar> sein, kurze Aussetzer in der Aufzeichnung zu haben.
Wenn du 500ms für "kurz" hältst, dann sollte es eigentlich niemals
irgendwelche Probleme geben.
> Das darf dann aber "relativ" selten passieren.
Das kann (im Grenzfall) bei jedem verschissenen write passieren. Hint:
die Specs haben de facto allein die Hersteller der Karten geschrieben,
nicht die Käufer/Benutzer. Dementsprechend schwammig ist die
Beschreibung dessen, was so eine Karte tatsächlich leisten können
muss....
Der Trick ist: mache es der Karte (bzw. dem ziemlich dummen
Flashcontroller darin) so leicht, wie irgend möglich. Dann (und leider
nur dann) wird sie die versprochenen Schreibraten auch dann noch
erreichen, wenn sie z.B. bereits mehrfach vollgeschrieben war. Alle dazu
nötigen Informationen lassen sich in den Daten finden, die der
Controller der Karte liefert. Um sie sinnvoll zu nutzen, braucht man:
1) Viel Buffer (leider sehr viel mehr als auf kleinen µC typischerweise
verfügbar ist)
2) Das Verständnis, wie man diesen Buffer unter Berücksichtigung der vom
Controller gelieferten Informationen sinnvoll einsetzt, um den
Controller die Arbeit maximal zu erleichtern.
De facto also alles Scheiß, der durch den Flashcontroller für die
Anwendung eigentlich irrelevant gemacht werden sollte. Genau das ist die
große Lüge des SD-Card-Konsortiums. Tatsache ist: er macht das eben
leider nicht überflüssig.
Damit das nicht so auffällt, spielt er eine Weile gut mit (so lange der
Spare reicht), dann schwächelt er performancemäßig, dann stirbt er ganz.
Der Unterschied der Mafiosi aus der einen oder anderen Konzernzentrale
besteht dann nur noch darin, ob sie dir erlauben, wenigstens noch
erlauben, ein Image zu ziehen oder ob sie dich stumpf komplett von
deinen Daten trennen...
> und wir müssen die> Information mit abspeichern wie lange die Pause war.
Das ist simpel: Du speicherst einfach Zeitstempel, die auf die Gewinnung
der Werte bezogen sind, nicht auf das Wegschreiben selbiger.
Das sollte aber sowieso der Grundansatz sein, völlig unabhängig vom
Speichermedium. Alles andere wäre schlechtes Softwaredesign. Und zwar
deiner eigenen Software. Das zumindest könntest du also nicht der
SD-Card-Mafia anhängen, so finster die auch ist...
Eigentlich ist es mir vollkommen Wurscht, was hier abgeht - aber
ich weiß, das die SD-Karten einen eigenen Prozessor haben, der sich
entsprechend durchsetzt.
Dagegen kann sich auch niemand wehren. Die Spezifikationen kann man sich
im Netz herunterladen. Natürlich braucht der SD-Karten-Prozessor Zeit um
seine Verwaltung der Daten zur organisieren. Diese stört halt ab und an
die Kommunikation.
SD Karten verwenden einen NAND Flash. Auf den NAND Flash kann man leider
nicht so einfach zugreiffen wie auf die SD Karte selbst, der Controller
in der Karte muss sich darum kümmern die Zugriffe des Hosts auf den
Flash abzulegen und ihn entsprechend anzusteuern. Je nachdem wie die
Daten vom Host kommen kann dies mehr oder weniger Effizient passieren.
Ein NAND Flash kann beispielsweise nur in Einheiten sogenannter Pages
Programmiert werden, bevor eine Page Programmiert werden kann muss sie
gelöscht sein. Das Löschen passiert in Einheiten von Flash Blöcken. Eine
Page ist bei MLC Flashes 4, 8, 16kiB gross, ein Block kann 64, 128 256
Pages beinhalten. Die Werte sind als Grössenordnungen zu verstehen und
hängen von der konkreten Architektur und Flash Type ab.
Wenn der Host nun nur einen Sektor (512 Bytes) oder sogar noch weniger
(nur bei SDSC möglich) auf die Karte schreibt, muss die Karte intern
trotzdem mindestens eine ganze Flash Page programmieren. Je nach dem ist
intern ein Read-Modify-Write notwendig, weil vielleicht ein Block
gelöscht werden muss der teilweise noch gültige Daten beinhaltet. Das
ganze ist recht komplex.
Der Datendurchsatz der Karte selbst wird umso schneller sein, desto mehr
Daten der Host auf einmal schreibt. Mikrocontroller benutzen oft
ausschliesslich Sektorzugriffe, die sehr langsam sind.
Das SD Protokoll hat zwei Schreibkommandos: WRITE_BLOCK für das
Schreiben von einzelnen Sektoren und das WRITE_MULTIPLE_BLOCK um mehrere
Sektoren zu schreiben. Der Host sollte wenn möglich WRITE_MULTIPLE_BLOCK
benutzen und möglichst viele Sektoren auf einmal schreiben.
Gruss
brue
Schonmal Danke für all die Antworten!
Um die Datenmenge zu reduzieren habe ich überlegt, die einzelnen
Teildaten eines Messpunktes per Bitshifting in eine 64 Bit Variable
abzulegen und die dann hinterher am PC wieder aufzudröseln.
Bei den Zeitstempeln einen Offset zu benutzen wäre auch noch eine Idee,
z.B. sich langsam ändernde Werte wie das Datum nur ab und zu in größeren
Intervallen zu schreiben. Allerdings wüsste ich spontan nicht, wie ich
Daten mit dynamischer Länge (z.B. mal 64 Bit, dann nur 32 Bit oder etwas
dawischen, wenn etwa das Datum wegfällt) in einem FIFO zwischenspeichern
könnte.
Ich werde auch mal einen pinkompatiblen AVR mit mehr SRAM raussuchen,
wobei es da ja eh nur den 644PA mit 4kB oder den 1284P mit 16kB gibt.
Falk B. schrieb:> Lahm.>> Beitrag "Re: Geschwindigkeitsfrage AVR auf SD">> Ich hab mal einen DMX-Rekorder programmiert, dort wurden 22kB/s von> SD-Karte gelesen/schreiben und per UART empfangen/gesendet. Die mittlere> CPU-Last lag bei ~30% @16MHz.>> Beitrag "Re: Atemega328p - schaffst du das?"
Dass das "lahm" ist, sehe ich. Daher war ja auch der Sinn des Threads in
Erfahrung zu bringen, wie man das schneller machen kann.
Die von dir im ersten verlinkten Beitrag angehängte Datei hatte ich auch
schon gesehen. Bei 100 Byte Blöcken (also 100 Byte an f_write
übergeben?) schon Schreibwerte von 250kB/s zu erreichen finde ich
beachtlich.
Wenn ich das richtig rauslese, benutzt du da generell Pre-Allocation mit
f_lseek und hast bei den "mit CLMT" Werten zusätzlich FF_USE_FASTSEEK 1
benutzt? (http://elm-chan.org/fsw/ff/doc/lseek.html letztes Beispiel)
Der Unterschied zwischen Fastseek 1 und 0 ist in deinem Beispiel ja
nicht so groß.
Ich habe das mit der Preallocation (ohne Fastseek und die CLMT) mal
ausprobiert, sofern ich es richtig verstanden habe:
xprintf(PSTR("6. f_size nach truncate %lu\n"),f_size(&file1));
53
xprintf(PSTR("6. f_tell nach truncate %lu\n"),f_tell(&file1));
54
55
xprintf(PSTR("Timer ende%d\n"),Timer*10);
56
57
xprintf(PSTR("f_sync2 rc=%d\n"),f_sync(&file1));
58
f_close(&file1);
59
xprintf(PSTR("Unmount rc=%d\n"),f_mount(0,"",0));
Für den Test habe ich die zu schreibenden Daten gleich gelassen und nur
die Größe der Zuweisung geändert. Die Datei auf der Speicherkarte wurde
vor dem Ändern der Zuweisungsgröße gelöscht.
Nach dem ersten Durchlauf wurde der µC aus- und wieder eingeschaltet.
Vor Trunc: 256010 256010 | Vor Trunc: 256010 256010 | Vor Trunc: 256010 256010
18
Nach Trunc: 256010 256010 | Nach Trunc: 256010 256010 | Nach Trunc: 256010 256010
19
Zeit: ca. 900ms | Zeit: ca. 1500ms | Zeit: ca. 900ms
Beobachtung:
*Selbst mit dem Erweitern über f_lseek komme ich nur auf ca. 139kB/s,
verglichen mit deinen 250kB/s ist das nach wie vor langsam.
*Obwohl die zugewiesene Größe eigentlich ausreichen müsste
(128100/128010 beim ersten Durchlauf), schreibt die Karte in diesen
Fällen langsam. Wenn sie aber augenscheinlich zu klein ist, wird der
Schreibvorgang schneller.
Hat jemand eine Idee, wieso sich die Karte so verhält?
Benutze ich die f_lseek Funktion falsch? Falls ja, könnte jemand ein
Beispiel geben wie man sie richtig nutzt?
@Falk Brunner (falk)
Könntest du bitte näher ausführen, eventuell mit einem kleinen Beispiel
zum Ablauf/groben Programmaufbau, wie du deine Schreibraten erreicht
hast? Wäre nett, danke.
@Michael K. (natulo)
>Ich werde auch mal einen pinkompatiblen AVR mit mehr SRAM raussuchen,>wobei es da ja eh nur den 644PA mit 4kB oder den 1284P mit 16kB gibt.
Tu das. 16kb sind in diesem Kontext RIESIG!
>Wenn ich das richtig rauslese, benutzt du da generell Pre-Allocation mit>f_lseek und hast bei den "mit CLMT" Werten zusätzlich FF_USE_FASTSEEK 1>benutzt? (http://elm-chan.org/fsw/ff/doc/lseek.html letztes Beispiel)
Ja.
>Der Unterschied zwischen Fastseek 1 und 0 ist in deinem Beispiel ja>nicht so groß.
Was wohl daran lag, daß die Karte neu und leer war ;-) Erstell mal
einfach so eine fragmentierte SD-Karte 8-0
>*Selbst mit dem Erweitern über f_lseek komme ich nur auf ca. 139kB/s,>verglichen mit deinen 250kB/s ist das nach wie vor langsam.
Läuft dein SPI WIRKLICH mit F_CPU/2? Hast du das mal gemessen? Nicht daß
du aus Versehen den falschen Takt konfiguriert hast.
>Hat jemand eine Idee, wieso sich die Karte so verhält?>Benutze ich die f_lseek Funktion falsch? Falls ja, könnte jemand ein>Beispiel geben wie man sie richtig nutzt?
Hmm, ehrlich gesagt verstehe ich dein Testprogramm nicht so ganz.
>f_lseek(&file1,f_size(&file1)); // Pointer zum Ende der Datei
Das kann nicht stimmen, denn f_size(&file1) ist zu dem Zeitpunkt NULL,
denn es wurde ja bisher noch nichts reingeschrieben und nach dem Öffnen
ist die Dateigröße Null.
>Könntest du bitte näher ausführen, eventuell mit einem kleinen Beispiel>zum Ablauf/groben Programmaufbau, wie du deine Schreibraten erreicht>hast? Wäre nett, danke.
Hmm, eigentlich nicht viel, ich hab mich ganz simpel am Beispiel vom
Meister Chan orientiert.
http://elm-chan.org/fsw/ff/doc/lseek.html
Man muss natürlich beachten, daß PRE_SIZE ein #define ist, welches die
Größe der Datei definiert
#define PRE_SIZE 128100
>xprintf(PSTR("lseek expand %d\n"),f_lseek(&file1,1000) ); // Verschiebe >Filepointer und erweiter die Datei, Wert wird im Test verändert
Hier legst du nur 1000 Byte in der Datei an, schreibst dann aber 128k.
Das wird so nix. Man muss vorher die GESAMTE Dateilänge reservieren.
Falk B. schrieb:> Das wird so nix. Man muss vorher die GESAMTE Dateilänge reservieren.
Ist schon etwas angestaubt und trägt auch nicht unbedingt was zur Lösung
des zu-wenig-RAM-Speicher-Problems bei, aber wenn ich die zu füllende
Datei mit f_lseek() oder f_expand() erweitere, dann wird das Schreiben
bei mir sogar langsamer. Ich hänge mal zwei entsprechende Screenshots
an. Das obere (hellblaue) Signal zeigt den /CS des SPI, darunter kommt
SDO und ganz unten SDI des µC.
Das Schreiben selbst, scheint bei Preallocation schneller einzusetzen,
aber danach kommt irgendwie noch was anderes.
Das (zusätzliche) geht so lange, bis die voreingestellte Dateilänge
erreicht ist. Dann läuft es wieder so, wie wenn die Datei nicht
künstlich erweitert wurde.
Irgendjemand eine Idee was da passiert? (wie schon erwähnt, bin SDcard
Anfänger ;-)
(((FatFS ist nicht die neueste Version, sondern R0.12c)))
Code ist eine einfache Schleife:
@Volker SK (vloki)
>Datei mit f_lseek() oder f_expand() erweitere, dann wird das Schreiben>bei mir sogar langsamer.
Sehr merkwürdig. Hast du vielleicht eine komische Konfiguration beim
FatFS eingestellt? Oder ist die SD-Karte "exotisch"? Fragmentiert? Hast
du mal einen neue, frisch formatierte probiert?
> #define BUFFER_SIZE 352
GANZ BLÖDE IDEE.
Wenn man kein Vielfaches von 512 Byte schreibt, muss er den Block vorher
einlesen.
Bei Vielfachen von 512 fällt das Lesen weg, das ist viel schneller.
Wer richtig schnell schreiben will nimmt das Multi-Block-Write Kommando.
Dann muss man aber bei FatFS auf Innereien (Blockaddresse) zurück
greifen, und mehrstufiges Schreiben (z.B. jeweils 1 Block pro
Funktionsaufruf) braucht auch etwas Hinschmalz, weil nicht
out-of-the-box vorhanden.
Out-of-the-box gibt es nur das Multi-Block-write mit großem Puffer, das
kann man als Vorlage verwenden.
Jim M. schrieb:>> #define BUFFER_SIZE 352>> GANZ BLÖDE IDEE.>> Wenn man kein Vielfaches von 512 Byte schreibt, muss er den Block vorher> einlesen.
Das habe ich bisher nicht beobachten können. Mir schien , ohne f_sync()
wird einfach erst auf die Karte geschrieben, wenn 512 Bytes zum
Schreiben da sind.
(oder wenn das File geschlossen wird)
Wo kann man das in meinen Screenshots erkennen, dass da viel gelesen
würde?
Falk B. schrieb:> Sehr merkwürdig. Hast du vielleicht eine komische Konfiguration beim> FatFS eingestellt? Oder ist die SD-Karte "exotisch"? Fragmentiert? Hast> du mal einen neue, frisch formatierte probiert?
Mehrere neue Karten, verschiedener Hersteller, oder auch frisch
formatiert. Ich sehe da keinen großen Unterschied.
(Intenso, Kingston, Samsung, Platinum, Philips, und Transcend, von
2..32GB)
Ich hatte ja anfangs die Hoffnung eine Karte,mit möglichst kurzen
"Denkpausen" zu finden, damit ich mit meinem "kleinen" RAM auskomme.
(keine gefunden ;-)
Wenn ich wieder etwas mehr Zeit finde, werde ich mir mal ein hier noch
rum liegendes PIC32 Board mit Kartenslot und das MCHP "Harmony" Zeugs
anschauen. Ausreichend RAM, zum Überbrücken der Denkpausen, sollte dann
jedenfalls nicht mehr das Problem sein...
<edit> Auch die neuere FatFS v0.13 könnte/sollte ich noch testen. Habe
allerdings noch nicht genauer nachgeschaut, ob man die einfach so
austauschen kann.
Falk B. schrieb:> @Volker SK (vloki)>>>Datei mit f_lseek() oder f_expand() erweitere, dann wird das Schreiben>>bei mir sogar langsamer.>> Sehr merkwürdig. Hast du vielleicht eine komische Konfiguration beim> FatFS eingestellt?
Ach ja Konfiguration hatte ich vergessen. Kurzform:
@Jim Meba (turboj)
>> #define BUFFER_SIZE 352>GANZ BLÖDE IDEE.
Nö. Nur ungewöhnlich.
>Wenn man kein Vielfaches von 512 Byte schreibt, muss er den Block vorher>einlesen.
Nö, nur wenn man FatFs auf die Minimalkonfiguration eingestellt hat. Im
Normalfall hat FatFS einen 512 Byte Sektorpuffer. Da muss rein gar
nichts doppelt gelesen werden.
>Wer richtig schnell schreiben will nimmt das Multi-Block-Write Kommando.
Das macht FatFS schon selber, wenn möglich.
>Dann muss man aber bei FatFS auf Innereien (Blockaddresse) zurück>greifen, und mehrstufiges Schreiben (z.B. jeweils 1 Block pro>Funktionsaufruf) braucht auch etwas Hinschmalz, weil nicht>out-of-the-box vorhanden.
Wirklich? Hab ich anders in Erinnerung.
Falk B. schrieb:> Ich würde mal>> #define FF_FS_MINIMIZE 0>> nutzen.
Kein Unterschied. Nicht mal im Speicherverbrauch.
Unbenutzte Funktionen scheint der Linker selber weg zu lassen.
>Code ist eine einfache Schleife:>#define BUFFER_SIZE 352>...> for(unsigned long i = 0; i<1000000; i++){> fileResult = f_write(&file, &buffer[0][0], BUFFER_SIZE,
&bytesWritten);
> if(mGET_BTN()){> while(mGET_BTN()){;}> break;> }> }
Was soll dieses mGET_BTN() dort drin?
Zeig mal deinen VOLLSTÄNDIGEN Code.