Guten Abend...
Projekte zu GPS-Loggern gibt es hier mittlerweile ja zu genüge, aber
irgendwie will es bei mir nicht so funktionieren und ich kann auch in
den anderen Threads nichts finden, was mein Problem lösen könnte.
Also die Daten kommen an der UART-Schnittstelle an und sollen dann
einfach ohne Verarbeitung per SPI auf die SD-Karte (FAT-16, Blockgröße
16kB, wenn man Windows trauen kann) geschrieben werden.
Den Quellcode dazu habe ich mir bei einem der anderen Projekte
rausgesucht und im Prinzip funktioniert auch alles, doch es scheint ein
Problem mit der Schreibgeschwindigkeit zu geben.
Die Eingangsdaten werden per UART-Interrupt abgefangen und dann erst
einmal in einem Array (128 Byte) zwischengespeichert. Immer wenn dort
Daten verfügbar sind, macht sich das Hauptprogramm an die Arbeit, die
Daten dann aus dem Buffer auf die SD-Karte zu schreiben. Das Problem
ist, dass irgendwann immer der Buffer komplett voll ist und dann das
Programm einen Fehler meldet und abbricht, was ja auch sinnvoll, aber
nicht erwünscht ist.
Der Mirkocontroller läuft per externem Quarz auf 7,3728 MHz, das SPI ist
auf Master und die Hälfte (ein Viertel) der Taktfrequenz eingestellt.
Das GPS-Modul liefert im Moment etwa 70 Bytes an Daten pro Sekunde und
der Fehler tritt aber nicht immer an der gleichen Stelle auf, sondern
manchmal sehr schnell, manchmal aber auch erst nach mehreren Minuten.
Sind das alle wichtigen Informationen?
Woran kann das liegen? Eigentlich müsste es doch möglich sein 70 Bytes/s
zu schreiben und bei den anderen scheint es ja auch zu funktionieren.
Zum Schluss noch die (hoffentlich) relevanten Codestellen:
Hallo,
deine Beschreibung ist äusserst spärlich und am Code sieht man auch
nicht wirklich wie du die Daten auf die SD-Karte schreibst.
Nichts zu sehen von einem File-System und den entsprechenden
Zugriffs-Methoden !!!
Ich kann nur hoffen das dein
> mmc_write_byte(rx_buf[rx_rdp++]);
nicht wegen jedem Byte immer wieder einen ganzen Sektor schreiben muss
???
bezeichnet "Ringpuffer leer" und nicht "Ringpuffer voll". Das mit dem
"uartrx" solltest Du ganz weglassen, das erzeugt ein fieses Race
zwischen Interrupt und Hauptschleife.
Aber auch der Test mit "rx_rdp" im Interrupt kann in die Hose gehen,
denn der Zugriff könnte - je nachdem was der Compiler für Code aufsetzt
- nicht atomar sein: Du inkrementierst zuerst und maskierst im 2.
Schritt. Ich würde auch diesen Test weglassen und einfach den Ringpuffer
überlaufen lassen. Daten wegschmeissen musst Du ja sowieso.
> Eigentlich müsste es doch möglich sein 70 Bytes/s> zu schreiben
Die Daten kommen bei GPS "am Stück". Wie hoch ist Deine Baudrate, 4800
Baud?
Das sollte eine SD eigentlich spielend schaffen, aber die brauchen
gelegentlich mal 300ms für das Wegschreiben eines Blocks. Dann würde es
mit Deinem 128 Byte Puffer u.U. eng werden, wenn z.B. noch ein FAT
Sektor dazu kommt.
Mh...ja, vergessen.
Also Dateisystem ist eben FAT-16, die Methoden zum schreiben sind nicht
von mir, sondern aus einem der anderen Projekte, bzw. wohl ursprünglich
mal von Mr. Data.
Im Anhang ist jetzt die Datei, die die Methoden für die SD-Karte und das
Dateisystem beinhaltet.
Und nein, es wird nicht immer ein ganzer Sektor für jedes Byte
geschrieben, sondern immer erst, wenn 512 Bytes zusammen sind.
Achja, die Speicherkarte hat 1GB Speicher und ist auch nicht voll.
Baudrate liegt bei 9600.
Jim Meba schrieb:> Das sollte eine SD eigentlich spielend schaffen, aber die brauchen> gelegentlich mal 300ms für das Wegschreiben eines Blocks. Dann würde es> mit Deinem 128 Byte Puffer u.U. eng werden, wenn z.B. noch ein FAT> Sektor dazu kommt.
Ich tipp ebenfalls auf einen Puffer-Überlauf bzw. eine Überholung, es
ist ja ein Ringpuffer. Erhöhe doch mal versuchsweise auf 512 Bytes. Wenn
der Speicher knapp wird, steig um auf den ATmega328, der hat 2 KB SRAM.
>> bezeichnet "Ringpuffer leer" und nicht "Ringpuffer voll".
Aber der Fall würde doch dann eintreten, wenn der Schreibpointer den
Readpointer im Prinzip überrunden würde - wie es Markus auch geschrieben
hat - und somit der ganze Puffer vollgeschrieben ist. Nennt man es dann
trotzdem "der Ringpuffer ist leer"?
Jim Meba schrieb:> Das mit dem> "uartrx" solltest Du ganz weglassen, das erzeugt ein fieses Race> zwischen Interrupt und Hauptschleife.
Ohne das gibt es keine Möglichkeit zu prüfen, ob der Puffer irgendwann
mal übergelaufen ist, oder? Naja, könnte ich mit leben. Dann muss man
später eben die ungültigen Stelle rausfiltern.
Jim Meba schrieb:> Aber auch der Test mit "rx_rdp" im Interrupt kann in die Hose gehen,> denn der Zugriff könnte - je nachdem was der Compiler für Code aufsetzt> - nicht atomar sein: Du inkrementierst zuerst und maskierst im 2.> Schritt. Ich würde auch diesen Test weglassen und einfach den Ringpuffer> überlaufen lassen. Daten wegschmeissen musst Du ja sowieso.
Das Inkrementieren und maskieren bezieht sich dann auf den Teil im
Hauptprogramm bzw. dann letztendlich auch auf den Writepointer im
Interrupt, oder?
Ohne jegliche Maske/Überprüfung ist man auf Puffergrößen beschränkt, die
einer Zweierpotenz entsprechen, oder? Ansonsten könnte man theoretisch
ja auch mit Modulo eine beliebige Größe angeben.
Markus W. schrieb:> Erhöhe doch mal versuchsweise auf 512 Bytes. Wenn> der Speicher knapp wird, steig um auf den ATmega328, der hat 2 KB SRAM.
512 Bytes passen nicht rein. Und dann bleibt als nächst kleineres ja nur
noch 256 Bytes. Werde ich mal probieren.
Der ATmega328 ist ein wenig schwer zu bekommen, aber da finde ich sicher
auch noch eine andere Alternative, auch wenn ich dann die Platine
vielleicht noch mal neu machen muss.
Moritz P. schrieb:> Der ATmega328 ist ein wenig schwer zu bekommen, aber da finde ich sicher> auch noch eine andere Alternative, auch wenn ich dann die Platine> vielleicht noch mal neu machen muss.
Das könnte ich jetzt nicht behaupten. Der ATmega328 ist oft sogar
billiger als der ATmega8 (bzw. ATmega88):
https://guloshop.de/shop/Mikrocontroller:::3.html
Bin mir jetzt nicht zu 100 Prozent sicher, aber die Pinbelegung müsste
doch die gleiche bleiben, du brauchst also keine neue Platine zu bauen.
Den ATmega8 kann ich aber bei Reichelt persönlich abholen, da spare ich
mir die Versandkosten. ;) Und den 328 hat es da nicht.
Von der Pinbelegung ist der 328 wirklich gleich, aber um genau zu sein
habe ich den ATmega8L verbaut, da dann alles mit 3,3V laufen kann. Das
würde mit dem ATmega328 nicht gehen.
edit:// Ich muss mich wohl korrigieren. Der ATmega328 scheint laut
Datenblatt auch mit 3,3V zu laufen...
Aber bisher scheint es mit dem etwas größeren Puffer (256 Bytes) auch so
zu gehen. Nächstes mal kommt dann aber auf jeden Fall ein größerer µC
zum Einsatz.
Moritz P. schrieb:> Den ATmega8 kann ich aber bei Reichelt persönlich abholen, da spare ich> mir die Versandkosten. ;) Und den 328 hat es da nicht.
Das ist natürlich praktisch, wenn Reichelt gleich nebenan hat. Wollen
wir Wohnort tauschen? :-)
Aber wenn ich jetzt richtig gerechnet habe, kämst du im Versand ab zwei
ATmega328 trotz Versandkosten schon billiger als bei zwei im Laden
gekauften ATmega168.
> edit:// Ich muss mich wohl korrigieren. Der ATmega328 scheint laut> Datenblatt auch mit 3,3V zu laufen...
Ja, der läuft sogar ab 1,8 Volt! Die Typen mit der 8 hinten (88, 168,
328) haben eine modernere Architektur, sind aber trotzdem pinkompatibel
zu Urgesteinen wie dem ATmega8. Echt praktisch.
> Aber bisher scheint es mit dem etwas größeren Puffer (256 Bytes) auch so> zu gehen. Nächstes mal kommt dann aber auf jeden Fall ein größerer µC> zum Einsatz.
Freut mich, dass es nun geht! Was den Ringpuffer-Überlauf betrifft,
vielleicht kannst du ihn trotzdem abfragen, wenn du den Indexvergleich
so machst, dass die Fehlermeldung schon dann kommt, wenn nur noch ein
Byte frei ist.
Zum Thema Puffergröße: Du hast Recht, am einfachsten ist es, wenn du
Zweierpotenzen verwendest. Falls nicht, dann besser nicht Modulo
verwenden, das schluckt wahrscheinlich arg viel Rechenzeit. Besser, man
fragt aufs Pufferende ab und setzt den Zeiger immer dann zurück, wenn er
am Ende angelangt ist.
Och nö, ich bleibe lieber hier wohnen. Oder hast du etwas anderes als
Reichelt zu bieten, was mich überzeugen könnte? ;)
Solange es jetzt ohne Fehler läuft, bleibe ich erst einmal beim ATmega8.
Wenn es aber dann doch immer wieder Probleme gibt, werde ich mal
schauen, ob ich dann nicht doch die 328'er bestelle. Der ATmega168 hätte
ja sowieso auch nur 1kB RAM.
Das Modulo recht langsam ist, habe ich mir schon fast gedacht. Naja,
vielleicht klappt es ja auch auf Dauer mit den 256 Bytes, dann muss ich
mir darüber keine weiteren Gedanken machen. :)
Nochmal viel Dank für die Tipps! :)