Forum: Mikrocontroller und Digitale Elektronik Schneller SD/USB-Datenlogger


von Tycho B. (asellus)


Lesenswert?

Liebe Gemeinde,

ich habe vor einen SD/USB Datenlogger zu bauen, bzw. schon einiges 
gebaut, allerdings gerade auf eine Grenze gestoßen, bei der ich nicht 
einschätzen kann, ob es an meinem Programm oder an der generellen Idee 
scheitert.

Zunächst zum System: ATmega1284P, 16 MHz. Ich habe einen 
kontinuierlichen Datenstrom bestehend aus 10 Bytes, die in 500 µs 
Zeitabstand kommen. Das sind ca. 20 kBytes/s, für eine SD-Karte oder 
USB-Stick also kein Problem.
SD-Kartenlesegerät ist über SPI mit voller Bandbreite von f/2, also 8 
MHz angeschlossen. Ich habe das FatFs-Modul implementiert und 
festgestellt, dass es anscheinend die Daten in der Funktion f_write 
puffert bis 512 Bytes voll sind, dann werden diese geschrieben. Das 
Schreiben ist in FATFS über Polling implementiert 
(loop_until_bit_is_set(SPSR,SPIF)), somit verbleibt das Hauptprogramm 
wenn ein Block geschrieben wird ca 50 ms in der Funktion f_write und ich 
verliere die Daten aus dem Datenstrom. Ich könnte diese zwar puffern, 
deren Verarbeitung benötigt aber auch eine gewisse Zeit, so dass 
insgesamt ich mir nicht sicher bin, ob der Puffer überhaupt geleert 
werden kann, wenn zur Datenverarbeitung zusätzlich das Schreiben auf die 
Karte dazukommt. Auch der Programmumbau wäre eine Heidenarbeit.
Deshalb bin ich hier und habe auch ein Paar Fragen zusammengestellt:

1) gibt es einen low level Unterbau von FATFS, der nicht mit Polling, 
sonder über SPI-Interrupte funktioniert? So dass die Daten unabhängig 
vom Hauptprogramm durch die SPI ISR rausgeschoben werden?

2) gibt es überhaupt eine Möglichkeit seriellen Datenstrom direkt vom µC 
in eine SD-Karte (FAT32-Datei) zu schreiben, so dass für das Schreiben 
einer Sequenz von 10 Bytes weniger als 250-500 µs benötigt wird? Beim 
Petit FAT File System Module, welches soweit ich es einschätzen kann 
wirklich einzelne Bytes schreibt, steht 0,38kBytes/s für ein Byte, also 
deutlich langsamer als von mir benötigt.

3) Nach Stöbern im Forum habe ich Verweise auf OpenLog und VDrive2 
gefunden. OpenLog ist etwas zu langsam, bei VDrive2 steht eine maximale 
Baudrate von 3.000.000. Wäre VDrive2 (Farnell 23,26) das Richtige für 
mein Vorhaben? Soweit ich es verstanden habe schreibt man nur 
Textbefehle über SPI (was sehr schnell geht und ohne weiteres über 
SPI-Interrupt implementiert werden kann), z.B. WRF·<dword> data, mit 
<dword>=Anzahl an data Bytes gefolgt von purem Datenstrom, und das 
war's. Natürlich davor Datei/Verzeichnis anlegen usw.

Grüße
Tycho

von Falk B. (falk)


Lesenswert?

@ Tycho B. (asellus)

>Zunächst zum System: ATmega1284P, 16 MHz. Ich habe einen
>kontinuierlichen Datenstrom bestehend aus 10 Bytes, die in 500 µs
>Zeitabstand kommen. Das sind ca. 20 kBytes/s, für eine SD-Karte oder
>USB-Stick also kein Problem.

Ja.

>SD-Kartenlesegerät ist über SPI mit voller Bandbreite von f/2, also 8
>MHz angeschlossen. Ich habe das FatFs-Modul implementiert und
>festgestellt, dass es anscheinend die Daten in der Funktion f_write
>puffert bis 512 Bytes voll sind, dann werden diese geschrieben.

Ja, siehe Doku.

> Das
>Schreiben ist in FATFS über Polling implementiert
>(loop_until_bit_is_set(SPSR,SPIF)), somit verbleibt das Hauptprogramm
>wenn ein Block geschrieben wird ca 50 ms in der Funktion f_write

Glaub ich nicht. Sooo lange dauert das nicht. Ausserdem sollte man 
beachten, wie man Schreibzugiffe verbessern kann.

http://elm-chan.org/fsw/ff/en/lseek.html

Das Zauberwort heißt Preallocation und CLMT.

> und ich
>verliere die Daten aus dem Datenstrom. Ich könnte diese zwar puffern,
>deren Verarbeitung benötigt aber auch eine gewisse Zeit, so dass
>insgesamt ich mir nicht sicher bin, ob der Puffer überhaupt geleert
>werden kann, wenn zur Datenverarbeitung zusätzlich das Schreiben auf die
>Karte dazukommt. Auch der Programmumbau wäre eine Heidenarbeit.

Muss aber sein. Wäre mit dem richtigen Design (tm) nicht passiert.
Dein Datenstrom muss per Interrupt verarbeitet und in einen FIFO 
geschrieben werden. Dann klappt das auch mit FATFS und der SD-Karte. 
Been there, done this.

>1) gibt es einen low level Unterbau von FATFS, der nicht mit Polling,
>sonder über SPI-Interrupte funktioniert?

Nein.

> So dass die Daten unabhängig
>vom Hauptprogramm durch die SPI ISR rausgeschoben werden?

Nein.

>2) gibt es überhaupt eine Möglichkeit seriellen Datenstrom direkt vom µC
>in eine SD-Karte (FAT32-Datei) zu schreiben, so dass für das Schreiben
>einer Sequenz von 10 Bytes weniger als 250-500 µs benötigt wird?

Nicht wirklich. Es gibt ein paar Stunts hier im Forum, wo es extrem 
verzahnt wird (Messung und SD-karte schreiben), das willst du aber nicht 
wirklich. Und nötig ist es auch nicht.

> Beim
>Petit FAT File System Module, welches soweit ich es einschätzen kann
>wirklich einzelne Bytes schreibt, steht 0,38kBytes/s für ein Byte, also
>deutlich langsamer als von mir benötigt.

Vergiss das, das ist deutlich schlechter, eben weil der Zwischenpuffer 
fehlt.

Ich hab vor einiger Zeit einen DMX-Rekorder gebaut, der sendet/empfängt 
250kBit/s per UART-Interrupt und schreibt die Daten in einen FIFO. In 
der Hauptschleife wird FATFS und die vorgelagerte Verarbeitung
(Statemachine) alle 10ms per Timer aufgerufen. Damit kann man 
problemlos die 22kB/s schreiben oder auch lesen, CPU-Last im Mittel bei 
30% (AVR @16MHz).

von Tycho B. (asellus)


Lesenswert?

Falk Brunner schrieb:
> Glaub ich nicht. Sooo lange dauert das nicht. Ausserdem sollte man
> beachten, wie man Schreibzugiffe verbessern kann.

Jetzt bekomme ich mit preallocation
1
res=disk_initialize(0);         
2
res = f_mount(&FatFs, "", 0);       
3
res = f_open(&Fil, "datei.txt",  FA_CREATE_ALWAYS | FA_WRITE );
4
res = f_lseek(&Fil, 10000);
5
res = f_lseek(&Fil, 0);
6
7
...
8
9
OSZILOSCOPE_LINE_HIGH();
10
res=f_write(&Fil, tempbuffer, 8192, &bw);
11
OSZILOSCOPE_LINE_LOW();
eine Dauer von ca. 280 ms. Das sind 29 kByte/s, ich komme also an deine 
31 kByte/s ran (du meintest doch kBit/s?) Scheint mir sehr langsam zu 
sein, allerdings kann es auch an der Karte liegen. Werde noch mit CLMT 
rumspielen, aber das ist eher um f_lseek zu beschleunigen?

Falk Brunner schrieb:
> CPU-Last im Mittel bei
> 30% (AVR @16MHz)

Ich muss ein von extern kommendes SENT-Protokoll dekodieren (Block aus 9 
Nibbles alle 300 µs kommend, darf keinen einzigen verlieren), habe auch 
eine statemachine, absoluten timer (16 MHz) mit 48 bit Länge, 
Tasteneingaben (entprellt), UART Datenbus (250k), der Befehle empfängt 
und Daten weitersendet (2 x FIFO) und zwei CRC-Auswertungen. Meine 
CPU-Last liegt ohne FATFS bei ca. 50%.
Die von mir benötigten 20kByte/s sind aber mehr als 50% von maximal 29 
kByte/s, ich glaube also, dass der Puffer überläuft.

von Frank K. (fchk)


Lesenswert?

Tycho B. schrieb:

> 1) gibt es einen low level Unterbau von FATFS, der nicht mit Polling,
> sonder über SPI-Interrupte funktioniert? So dass die Daten unabhängig
> vom Hauptprogramm durch die SPI ISR rausgeschoben werden?

Andere Controller können SPI oder MCI per DMA ansteuern. Hat ein AVR 
natürlich nicht, jedenfalls kein herkömmlicher. (Xmega schon)

> 2) gibt es überhaupt eine Möglichkeit seriellen Datenstrom direkt vom µC
> in eine SD-Karte (FAT32-Datei) zu schreiben, so dass für das Schreiben
> einer Sequenz von 10 Bytes weniger als 250-500 µs benötigt wird? Beim
> Petit FAT File System Module, welches soweit ich es einschätzen kann
> wirklich einzelne Bytes schreibt, steht 0,38kBytes/s für ein Byte, also
> deutlich langsamer als von mir benötigt.

SD_Karten erreichen ihre volle Geschwindigkeit erst per MCI, also dem 
nativen MMC-Interface, das mit 4 Bit Datenbreite betrieben werden kann.
Schade, das gibts bei AVR auch nicht.

Nimm mal einen geeigneteren Controller, dann erledigen sich viele 
Probleme quasi von alleine. So ein SAM3S wäre angemessen.

fchk

von Falk B. (falk)


Lesenswert?

@ Tycho B. (asellus)

>Jetzt bekomme ich mit preallocation

>res=f_write(&Fil, tempbuffer, 8192, &bw);
>OSZILOSCOPE_LINE_LOW();

>eine Dauer von ca. 280 ms. Das sind 29 kByte/s, ich komme also an deine
>31 kByte/s ran (du meintest doch kBit/s?)

280ms für 8kB? Eher nicht. Wie misst du das? Mit dem Oszi und einem 
IO-Pin?
Ich hab damals selbst unter ungünstigen Bedingungen 170kB/s 
(KiloBytes/s) gemessen. Die 22kB/s waren problemlos drin.

> Scheint mir sehr langsam zu
>sein, allerdings kann es auch an der Karte liegen. Werde noch mit CLMT
>rumspielen, aber das ist eher um f_lseek zu beschleunigen?

Beides.

>Die von mir benötigten 20kByte/s sind aber mehr als 50% von maximal 29
>kByte/s, ich glaube also, dass der Puffer überläuft.

Da klemmt es irgendwo anders.

von Pandur S. (jetztnicht)


Lesenswert?

Was soll ein seek() ? Da gibt es nichts zu seek()-en.

von Tycho B. (asellus)


Lesenswert?

Falk Brunner schrieb:
> Wie misst du das? Mit dem Oszi und einem
> IO-Pin?

ja

Falk Brunner schrieb:
> Da klemmt es irgendwo anders.

Mit einer an Sicherheit grenzender Wahrscheinlichkeit. :)
Habe mit einer anderen Karte probiert, 20 ms => 400 kByte/s, lag also an 
der Karte. Die langsame Karte: 2GB SD-C02G microSD, die schnelle: 
SanDisk 512 MB (AX0502YW)
Eventuell habe ich die Einstellungen in der ffconf.h vermurkst. Jedoch 
liefert auch die FATFS-Seite verschiedene Performancewerte für 
unterschiedliche Karten. Ich denke mal der Entwickler wusste schon was 
er macht, als er die Benchmarks aufgenommen hat.
Eine kartenabhängige Anwendung ist sehr ungünstig bis nicht akzeptabel. 
Jetzt ärgere ich mich, dass ich dem Punkt nicht mehr Beachtung geschenkt 
habe, dachte, dass die schlechten Performancewerte Ausnahmen sind.

Jetzt Nicht schrieb:
> Was soll ein seek() ?

steht in http://elm-chan.org/fsw/ff/en/lseek.html in den Kommentaren des 
mittleren Codeblocks. Der cluster allocation delay wird vermieden.

von Pandur S. (jetztnicht)


Lesenswert?

> Jetzt Nicht schrieb:
>> Was soll ein seek() ?

>steht in http://elm-chan.org/fsw/ff/en/lseek.html in
>den Kommentaren des mittleren Codeblocks. Der cluster
>allocation delay wird vermieden.

Sollte man sowieso vermeiden. Einfacher ist es auf dem PC ein (1) File 
zu schreiben. Und nachher dieses File zu ueberschreiben.

von Jim M. (turboj)


Lesenswert?

Tycho B. schrieb:
> Jetzt ärgere ich mich, dass ich dem Punkt nicht mehr Beachtung geschenkt
> habe, dachte, dass die schlechten Performancewerte Ausnahmen sind.

Ich sehe keine schlechten Performance Werte bei Deinen Karten.
Ich habe schon Karten gesehen, die beim Schreiben gefühlt 1 Sekunde 
abtauchen, das war aber eine Karte aus dem Supermarkt.

Übrigens werden die Wartezeiten länger je öfter auf die Karte 
geschrieben wurde, Stichwort Wear-leveling.

Wenn man richtig schnell auf SD-Karten schreiben muss, braucht man 
multi-Block Writes und einen großen (ich verwende 16kB) Puffer. Die 
dafür benötigte Infrastruktur ist aber nicht trivial, ich habe das als 
Cache  unterhalb des Dateisystems (also in disk_write) implementiert.

von Falk B. (falk)


Lesenswert?

@Jetzt Nicht (jetztnicht)

>>steht in http://elm-chan.org/fsw/ff/en/lseek.html in
>>den Kommentaren des mittleren Codeblocks. Der cluster
>>allocation delay wird vermieden.

>Sollte man sowieso vermeiden. Einfacher ist es auf dem PC ein (1) File
>zu schreiben. Und nachher dieses File zu ueberschreiben.

Unsinn. Wenn man mal die verlinkte Seite LESEN und so Gott will auch 
VERSTEHEN würde, dann KÄME man auf die Idee, dass mit den dort 
dargestellten Verfahren das Ganze deutlich flexibler handhabbar ist.

von Falk B. (falk)


Lesenswert?

@Jim Meba (turboj)

>Wenn man richtig schnell auf SD-Karten schreiben muss, braucht man
>multi-Block Writes und einen großen (ich verwende 16kB) Puffer. Die
>dafür benötigte Infrastruktur ist aber nicht trivial, ich habe das als
>Cache  unterhalb des Dateisystems (also in disk_write) implementiert.

FATFS kann das auch schon von Haus aus, allerdings muss man es dann mit 
großen Datenblöcken füttern, wofür natürlich wieder viel RAM benötigt 
wird. Also dicker ARM irgendwas oder ein AVR mit externem SRAM oder was 
ähnliches. Aber für die vom OP angepeilten 20kB/s reicht der kleine 512 
Byte Puffer im FATFS locker. Damit schafft man bei 8 Mbit SPI Speed 
~170kB/s beim Lesen wie Schreiben.

Beitrag "Re: SD-Karte Speichergeschwindigkeit"

Das waren aber reine Tests mit 32kB Blöcken beim Aufruf von f_write().

: Bearbeitet durch User
von Tycho B. (asellus)


Lesenswert?

Jim Meba schrieb:
> Ich sehe keine schlechten Performance Werte bei Deinen Karten.

Ist relativ. 40 kByte/s ist für die Anwendung einfach zu langsam. Auch 
der Speicher des µC ist begrenzt, 16k habe ich nicht. Deswegen habe ich 
auch nach Erfahrungen zu VDrive2 / Alternativen gefragt.

Jim Meba schrieb:
> Wenn man richtig schnell auf SD-Karten schreiben muss

Da muss man doch eh SPI verlassen, und parallel schreiben, deswegen 
VDrive2.

von Tycho B. (asellus)


Lesenswert?

Falk Brunner schrieb:
> Aber für die vom OP angepeilten 20kB/s reicht der kleine 512
> Byte Puffer im FATFS locker. Damit schafft man bei 8 Mbit SPI Speed
> ~170kB/s beim Lesen wie Schreiben.

Hast du es mit mehreren unterschiedlichen Karten versucht? Wie bereits 
geschrieben, ich kriege mit einer Karte 400 kB/s, mit der anderen 30 
kB/s.
(nicht am kontinuierlichen Datenstrom gemessen, sondern mit Oszi-Pin, 
und einmaliger Block von 8192 Bytes)

von Falk B. (falk)


Lesenswert?

@ Tycho B. (asellus)

>> Aber für die vom OP angepeilten 20kB/s reicht der kleine 512
>> Byte Puffer im FATFS locker. Damit schafft man bei 8 Mbit SPI Speed
>> ~170kB/s beim Lesen wie Schreiben.

>Hast du es mit mehreren unterschiedlichen Karten versucht?

Ja.

> Wie bereits
>geschrieben, ich kriege mit einer Karte 400 kB/s, mit der anderen 30
>kB/s.

Dann hat die eine Karte einen erheblichen Defekt.

von chris (Gast)


Lesenswert?

Ich habe die Lib von @Falk mal angepasst.
Was derzeit noch fehlt ist formatierung MIT nicht 512 bytes, Also karten 
MIT mehr als 4 GB und multi block Unterstützung sowie Transaktion safe 
fat. Implementiert ist fat32+
Also files mit>4gb sind kein Problem.
Wenn die Karte kein einzelnen block löschen
kann, wie bei schnellen karten üblich,
Dann können derzeit keine daten gelöscht werden. Achso, nur 8.3 Namen 
werden verwendet und für ein fat32 system formatiert
Mit fat16 oder fat12 braucht es eine besondere
Formatierung. Limit sind 2T.

Wenn du willst kann ich eine pre alpha Version hochladen. Auch wenn es 
mit interrupt funktionieren würde ist es derzeit ohne und es ist gedacht 
dass ein Scheduler die Datensammlung im Interrupt erledigt und in ein 
fifo rein schreibt.

Karten funktionieren alle, mbr ist implementiert,
Kein GPT und derzeit auch nur die erste partition.
Optionaler basic interpreter ist auch dabei,
Ist aber derzeit nur pre alpha.

von Tycho B. (asellus)


Lesenswert?

chris schrieb:
> Ist aber derzeit nur pre alpha.

Hallo chris,
danke für das Angebot. Verstehe ich das richtig, dass deine Anpassung zu 
keinem Zeitpunkt das Hauptprogramm für länger als 500µs unterbricht? 
Oder muss ich die kontinuierlich kommenden Daten puffern, um ein 
Zeitfenster für die Übertragung zu verschafen? Das war schon der 
Vorschlag von Falk.

von Olaf (Gast)


Lesenswert?

> Hast du es mit mehreren unterschiedlichen Karten versucht? Wie bereits
> geschrieben, ich kriege mit einer Karte 400 kB/s, mit der anderen 30
> kB/s.

Elms FatFS liegt bei mir so mit unterschiedlichen Karten bei 200kB/s. 
Aber man kann sich nicht drauf verlassen. Es kommt immer mal vor das 
eine Karte zwischendurch mal meint etwas anderes machen zu muessen und 
dann dauert es ploetzlich sehr viel laenger. Man braucht also einen 
Buffer wo man notfalls fuer 1s die Daten speichern.

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
Noch kein Account? Hier anmelden.