PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : String auf SD-Karte mit Drivewritesector()



Fabian1995
06.05.2012, 19:23
Hallo,

ich sitze jetzt schon einige Stunden vor dem PC und komme nicht weiter.
Habe auch schon lange im Internet gesucht aber keine wirkliche Erklärung gefunden.
Und zwar habe ich mehrere Messdaten in einem String zusammengefasst und würde diese gerne in einem
Sektor auf der SD-Karte speichern.
Doch wenn ich es richtig verstanden habe besteht der angelegte Buffer aus Bytes und lässt sich somit auch nur in dieser Form übertragen.
Könnte mir diesbezüglich jemand einen Tipp geben wie ich mit dem Drivewritesector()-Befehl am besten einen String speichern kann?

MfG Fabian

Kampi
06.05.2012, 20:01
Hi,

du könntest den String Byteweise auf die Karte schreiben. Sprich du machst nen Zähler der für die Position im String ist. Dann schreibst du das Zeichen worausf der Zähler zeigt auf die Karte und erjöhst den Zähler um eins. Und dann machste das nochmal. Den ganzen Spaß wiederholst du solange bis du am Ende vom String bist.

Fabian1995
06.05.2012, 20:30
Ok aber ich glaube ich habe noch nicht so ganz die Funktionsweise von dem Befehl Drivewritesector verstanden.
Kann man Byteweise die Karte beschreiben weil es wird doch immer gesagt, dass man nur vollständige Sektoren Schreiben kann?
Codeausschnitt:
......
Dim Berror As Byte
Dim Buffer(512) As Byte 'SRAM-Bereich für Transfer
Dim Wsrampoint As Word 'Adress-Pointer für die Drive.. Routinen
Dim Lselectornumber As Long 'Variable für Sektor-Nummer
Wsrampointer = Varptr(buffer(1))
Lselectornumber =1
.....
Druck1 = Getadc(4)
Druck2 = Getadc(5)
Temperatur = Getadc(6)

Messwerte_string = Gpgga + ";" + Str(druck1) + ";" + Str(druck2) + ";" + Str(temperatur) + "*"
......

Ich glaube ich stehe gerade auf dem Schlauch.. Wie kann ich dann deine Idee mit ' Berror = Drivewritesector(wsrampoint , Lsectornumber)' umsetzen?

Danke für die schnelle antwort :)

Kampi
06.05.2012, 20:42
Laut der Hilfe schreibst du mit dem Befehl bis zu 512 Bytes in einen Sektor:

Write a Sector (512 Bytes) to the (Compact Flashcard) Drive

Fabian1995
06.05.2012, 20:51
Okay hab ich anscheinend überlesen....
Aber wo wird bei dem Befehl definiert was ich jetzt eigentlich speichere?
in meinem Fall gibt doch Berror einen Wert zurück, ob das Schreiben funktioniert hat, wsrampoint die Adresse von wo und Lsectornumber in welchen Sektor ich es schrieben will.
oder wird mit wsrampoint automatisch das byte an dieser Stelle übertragen?

for_ro
06.05.2012, 21:19
Hallo Fabian,
ich habe das einfach so gemacht:

Dim Berror As Byte
Dim Buffer(512) As Byte 'SRAM-Bereich für Transfer
Dim Messwerte_string * 512 as string at Buffer(1) overlay
Dim Wsrampoint As Word 'Adress-Pointer für die Drive.. Routinen
Dim Lselectornumber As Long 'Variable für Sektor-Nummer
Wsrampointer = Varptr(buffer(1))
Lselectornumber =1
.....
Druck1 = Getadc(4)
Druck2 = Getadc(5)
Temperatur = Getadc(6)
Messwerte_string = Gpgga + ";" + Str(druck1) + ";" + Str(druck2) + ";" + Str(temperatur) + "*"
Berror = DriveWriteSector(Wsrampointer,Lselectornumber)

Du schreibst in den String, durch das Overlay aber gleichzeitig auch in das Byte-Array Buffer.
Der DriveWriteSector Befehl schreibt immer die nächsten 512 Byte ab der angegebenen Adresse auf die SD Karte.
Beachte, dass du die Karte mit Windows nicht mehr lesen kannst, wenn du auf den Sektor 1 schreibst.

trekko
06.05.2012, 21:49
Der DriveWriteSector Befehl schreibt immer die nächsten 512 Byte ab der angegebenen Adresse auf die SD Karte.
Beachte, dass du die Karte mit Windows nicht mehr lesen kannst, wenn du auf den Sektor 1 schreibst.

Hallo!
Grundsätzlich ist es bei SD-Karten möglich, innerhalb eines Sektors Schritt für Schritt zu schreiben - jedes Byte immer dann, wenn es vom Messgerät eingelesen wird. Wahrscheinlich geht das aber nicht mit den üblichen Prozeduren.
Ich wollt nur auf die Möglichkeit hinweisen, weil ist so etwas schon einmal gemacht habe. Dadurch kann man auch mit Mikrocontrollern mit wenig Speicher (z.B. ATtiny25) auf SD-Karten schreiben.

Fabian1995
06.05.2012, 22:19
Danke for_ro,
Genau das habe ich gesucht :)
Hatte auch noch dummer Weis eine Variable falsch geschrieben... aber jetzt funktioniert es :)
Hatte gedacht in Sektor 0 stehen die wichtigen Daten die man nicht verändern darf aber in Sektor 1 darf man doch schon etwas schreiben oder?

Fabian

for_ro
06.05.2012, 22:35
Hatte gedacht in Sektor 0 stehen die wichtigen Daten die man nicht verändern darf aber in Sektor 1 darf man doch schon etwas schreiben oder?
Wenn du die Karte mit Windows lesen willst, dann kannst du sehr viele Sektoren am Beginn der Karte nicht benutzen.
Wieviele hängt wohl auch von der Größe der Karte und der Art der FAT ab.
Ich hatte damals eine Karte frisch formatiert und dann einen File mit bekanntem Inhalt (1234567890123456...) draufgeschrieben. Der steht dann auf dem ersten verwendbaren Sektor. Mit dem µC habe ich dann über DriveReadSector diesen Sektor gesucht.
Bei meiner 1GB Karte war es der Sektor 768.

MagicWSmoke
06.05.2012, 22:38
Dim Buffer(512) As Byte 'SRAM-Bereich für Transfer
Dim Messwerte_string * 512 as string at Buffer(1) overlay
Man kann keinen String mit einer Länge von 512 Zeichen über ein 512 Byte Array legen, denn der String benötigt tatsächlich 512 Zeichen + 1 Endbyte. Wenn der String tatsächlich mal 512 Byte lang ist, wird die dem Array folgende Variable zerstört, hier Wsrampoint, mit unbestimmten Folgen. Auch fehlt dem String, sollte er überhaupt korrekt geschrieben werden, auf der SD-Karte das Endzeichen. Das kann dann bei der Weiterverarbeitung zu Problemen führen. Also den String nur 511 Zeichen lang dimensionieren.

for_ro
06.05.2012, 22:42
Ich wollt nur auf die Möglichkeit hinweisen, weil ist so etwas schon einmal gemacht habe. Dadurch kann man auch mit Mikrocontrollern mit wenig Speicher (z.B. ATtiny25) auf SD-Karten schreiben.
Hallo trekko,
würde mich auch mal interessieren, wie das geht. Müsste man wahrscheinlich die DriveWriteSektor Funktion so ändern, dass über einen zusätzlichen Parameter die Anzahl bytes übergeben wird. Und nur die werden dann geschrieben.
Irgendwo habe ich mal gelesen, dass die Daten erst in einen Buffer geschrieben werden. Wenn dann ein Sektor komplett ist, wird er auf die Karte übertragen. Dies geschieht im Controller der Karte.

Fabian1995
06.05.2012, 22:48
Stimmt das mit dem endbyte hatte ich garnicht beachtet. Wegen der Auswertung: ich wollte in jeden Sektor nur einen datenstring schreiben und zur Auswertung dann die Sektoren durchgehen, dann brauche ich doch keine Endzeichen?
Wegen der Anfangssektoren werde ich das mal bei meiner 1 gb Karte herausfinden und dann den Startsektor dementsprechend anpassen.

MagicWSmoke
06.05.2012, 23:01
ich wollte in jeden Sektor nur einen datenstring schreiben und zur Auswertung dann die Sektoren durchgehen, dann brauche ich doch keine Endzeichen?
Wenn der Datenstring immer eine bestimmte Länge hat, könnte man auf das Endzeichen verzichten, ansonsten braucht man's um das Ende des Strings erkennen zu können. Bascom wird das Endzeichen aber auf jeden Fall schreiben, wenn also der String tatsächlich max 512 Bytes enthalten kann, dann unmittelbar auf die Buffervariable folgend ein einzelnes Byte dimensionieren, damit dieses das Endzeichen aufnimmt und nix überschrieben wird.

for_ro
07.05.2012, 14:16
Vielleicht solltest du nicht solche hintenrum Lösungen implementieren, die du nachher nicht mehr verstehen kannst.
Tatsächlich habe ich es bei mir genau anders herum gemacht:

Dim Messwerte_string * 512 as string
Dim Buffer(512) As Byte at Messwerte_string overlay

Dabei wird auch Platz für das Endezeichen bei 512 Byte langen Strings erzeugt.
Die Bufferlänge von 512 reicht, weil die hier nur zur Verdeutlichung angegeben wird.

Die DriveWriteSector() Funktion schreibt nicht bis zum Endezeichen des Strings sondern 512 Byte, egal was da drin steht.
Das musst du dann nur beim Einlesen bedenken, wenn du die DriveReadSector() Funktion benutzt, um den Sektor wieder in den Buffer und damit in den String zu bekommen. Steht weder in den 512 Byte noch im zusätzlichen Byte von Messwerte_string kein 0-Byte, dann geht der String einfach weiter, solange bis er im SRAM auf ein 0-Byte trifft. Evtl. kommen damit aber die Stringfunktionen nicht mehr zurecht.

Mit den Stringfunktionen solltest du bei solch langen Strings ohnehin sehr vorsichtig umgehen. Besonders Dinge wie

Messwerte_string = "12345678901234567890" + Messwerte_string

können zu recht hohen Anforderungen an deinen Frame Bereich führen, weil hierzu eine Kopie von Messwerte_string erzeugt werden muss.
Damit werden dann evtl. die Stacks überschrieben, was zu recht garstigen Fehlern führen wird.

MagicWSmoke
07.05.2012, 15:17
for_ro,

Vielleicht solltest du nicht solche hintenrum Lösungen implementieren,
Die Hintenrum-Lösung war eine Korrektur Deines fehlerhaften Vorschlags:

Hallo Fabian,
ich habe das einfach so gemacht:

Dim Berror As Byte
Dim Buffer(512) As Byte 'SRAM-Bereich für Transfer
Dim Messwerte_string * 512 as string at Buffer(1) overlay
Dim Wsrampoint As Word 'Adress-Pointer für die Drive.. Routinen

Und hat Dich immerhin dazu bewegt drüber nachzudenken und zu korrigieren.

trekko
07.05.2012, 19:55
würde mich auch mal interessieren, wie das geht. Müsste man wahrscheinlich die DriveWriteSektor Funktion so ändern, dass über einen zusätzlichen Parameter die Anzahl bytes übergeben wird. Und nur die werden dann geschrieben.
Irgendwo habe ich mal gelesen, dass die Daten erst in einen Buffer geschrieben werden. Wenn dann ein Sektor komplett ist, wird er auf die Karte übertragen. Dies geschieht im Controller der Karte.

Hi for_ro, ich kenn ja die DriveWriteSektor-Funktion nicht, ich hab die SD-Karte "zu Fuß" beschrieben, das heißt, ich hab die Schreibbefehle für die SD-Karte direkt über die serielle Leitung geschickt. Hier findest du ein paar Infos zu dem Thema: http://elm-chan.org/docs/mmc/mmc_e.html

Natürlich ist das aufwändiger, als so komfortable Funktionen wie DriveWriteSektor zu benutzen, es hat aber den Vorteil, dass man den Schreibvorgang so beeinflussen kann, wie man will. Das Schreibprotokoll für die SD-Karten erlaubt es nämlich, während des Schreiben eines Blocks den Clock-Takt vorübergehend anzuhalten und dann ein paar Sekunden (oder Minuten) später weiterzuschreiben, als wäre nichts gewesen.

for_ro
11.05.2012, 11:56
... ich kenn ja die DriveWriteSektor-Funktion nicht, ich hab die SD-Karte "zu Fuß" beschrieben, das heißt, ich hab die Schreibbefehle für die SD-Karte direkt über die serielle Leitung geschickt.
Hatte ich mir auch so gedacht. Cool wäre es allerdings, wenn man das auch über einen modifizierten DriveWrite Befehl machen könnte.

Hier findest du ein paar Infos zu dem Thema: http://elm-chan.org/docs/mmc/mmc_e.html
Natürlich ist das aufwändiger, als so komfortable Funktionen wie DriveWriteSektor zu benutzen, es hat aber den Vorteil, dass man den Schreibvorgang so beeinflussen kann, wie man will. Das Schreibprotokoll für die SD-Karten erlaubt es nämlich, während des Schreiben eines Blocks den Clock-Takt vorübergehend anzuhalten und dann ein paar Sekunden (oder Minuten) später weiterzuschreiben, als wäre nichts gewesen.
Aber diese Sache mit dem Clock anhalten ist dort nicht beschrieben, oder habe ich das übersehen?
Hast du dieses unterbrechen schon mal implementiert? Das wäre genau das, wie ich es auch gerne machen würde. Zur Zeit warte ich 8 Minuten, bis ich 512 Byte zusammen habe und diese dann en Block auf die Karte schreibe.