Forum: Mikrocontroller und Digitale Elektronik Datenformatierung Flash Speicher


von Dominic A. (neo123)


Lesenswert?

Hallo zusammen,
Ich entwickle momentan als Hobbyprojekt ein Datenlogger. Geloggt werden 
sollte die Luftfeuchte, Temperatur, Helligkeit, Zeit und einen CRC-8.
Auf dem Gerät habe ich einen Flash Speicher vom Typ SST25VF032B.
Die Daten liegen in folgendem Format vor:

Zeit: 32Bit
Temperatur: 16Bit
Helligkeit: 16Bit
Luft feuchte: 16Bit
CRC-8: 8Bit
=88Bit=11Byte

Nun bin ich mir am überlegen wie ich die Daten auf dem Flashspeicher 
organisiere. Ich habe mir überlegt einfach alle Daten hintereinander in 
den Flash zu schreiben. Ich kenne ja die Startadresse sowie auch die 
Länge(11Byte) eines Datensatzes. Soweit so gut. Jedoch habe ich nun das 
Problem das ich nicht erkenne an welcher Adresse ich geschrieben habe 
sobald die Batterie abgehängt wurde. Leider besitzt mein uC kein EEPROM. 
Ich könnte zwar mittels dem Programm Speicher ein EEPROM emulieren 
jedoch sind die Schreibzyklen dabei ziemlich begrenzt und der Programm 
Speicher wäre nach ein paar Messungen kaputt.

Im Artikel 
http://www.mikrocontroller.net/articles/Speicher#EEPROM_Schreibzugriffe_minimieren 
wird eine Methode beschrieben um zu erkennen ob die Betriebsspannung weg 
fällt. Ist dies die einzig sinnvolle Möglichkeit? Oder gibt es auch eine 
reine Software Lösung? Ich würde letzteres bevorzugen da die Hardware 
schon steht.

Grüsse
Dominic

von g457 (Gast)


Lesenswert?

> Jedoch habe ich nun das Problem das ich nicht erkenne an welcher Adresse
> ich geschrieben habe sobald die Batterie abgehängt wurde.

Klar weisst Du das, denn nur da stehen gültige Pakete.

von holger (Gast)


Lesenswert?

>=88Bit=11Byte

Mach 16 draus. Sonst hast du viel Spass
beim überschreiten der Pagegrenzen.

von Hott (Gast)


Lesenswert?

Ich wuerd auch die 11Bit als 16 bit abspeichern. Das Andere etwas 
ausprobieren. Allenfalls eine Simulation laufen lassen.

von Dominic A. (neo123)


Lesenswert?

Wie erkenne ich den ein ungültiges Paket? Es kann ja sein, dass nachdem 
ich die 2Byte Temperatur geschrieben habe die Betriebsspannung wegfällt. 
Nun gehe ich beim nächsten Start durch eine FOR Schleife zähle die 
Adresse solange hoch bis die Daten 0xFF kommen(gelöschter Flashbereich). 
Dann stoppe ich bei einer Adresse mitten in einem halben Datensatz.

Weiterhin habe ich bei der For Schleife das Problem das auch ein 
Datensatz ein 0xFF Byte enthalten kann. Wie kann ich soetwas erkennen?

holger schrieb:
> Mach 16 draus. Sonst hast du viel Spass
> beim überschreiten der Pagegrenzen

Wie meinst du das? Ich kann dem Flash einfach eine 24 Bit Adresse und 
ein 8 Bit Datenwort übergeben und er speichert das von selber an der 
"richtigen Stelle". Sorry falls ich das falsch verstehe. Es ist das 
erste mal das ich etwas mit einem externen Flash mache.

von Falk B. (falk)


Lesenswert?

@ Dominic A. (neo123)

>Adresse solange hoch bis die Daten 0xFF kommen(gelöschter Flashbereich).
>Dann stoppe ich bei einer Adresse mitten in einem halben Datensatz.

Und dann rechnest du die CRC nach und siehst, welcher Datensatz zuletzt 
gültig ist.

von holger (Gast)


Lesenswert?

>Nun gehe ich beim nächsten Start durch eine FOR Schleife zähle die
>Adresse solange hoch bis die Daten 0xFF kommen(gelöschter Flashbereich).
>Dann stoppe ich bei einer Adresse mitten in einem halben Datensatz.

Nö, das tust du nicht. Du zählst in ganzen Datensätzen hoch.
Wie lange willst du denn in einem 4MB Flash rumsuchen wenn
du jedes Byte einzeln liest?

>Weiterhin habe ich bei der For Schleife das Problem das auch ein
>Datensatz ein 0xFF Byte enthalten kann. Wie kann ich soetwas erkennen?

Ein kompletter Datensatz mit 0xFF ist leer.

Kleiner Tip: Denk dir einen passenden Suchalgorithmus aus
damit du nicht das komplette Flash byteweise lesen musst.
Das könnte sonst sehr lange dauern.

von g457 (Gast)


Lesenswert?

> Wie erkenne ich den ein ungültiges Paket?

..indem Du die Prüfsumme prüfst?

Zum Thema 'schnell durchsuchen': Binärsuche regelt.

von Dominic A. (neo123)


Lesenswert?

Erstmal vielen Dank für eure Hilfe hat mich auf jeden Fall schon 
ziemlich weiter gebracht.

Falk Brunner schrieb:
> Und dann rechnest du die CRC nach und siehst, welcher Datensatz zuletzt
> gültig ist.

Achso ja klar dafür habe ich ja unteranderem den CRC.

holger schrieb:
> Kleiner Tip: Denk dir einen passenden Suchalgorithmus aus
> damit du nicht das komplette Flash byteweise lesen musst.
> Das könnte sonst sehr lange dauern.

Wie wärs den wenn ich noch ein 12Byte nehme mit einem kleinem Schlüssel. 
Also ich denke mir das so: Ich springe von CRC zu CRC der Datensätze. 
Falls nun der CRC 0xFF ist also entweder gelöscht oder im Sonderfall 
tatsächlich 0xFF entspricht kann ich das Schlüsselbyte dieses 
Datensatzes auslesen. Falls dieser Schlüssel nun der Richtige ist z.B. 
0xAA weiss ich das der Datensatz komplett ist und kann weiter suchen. 
Falls der Schlüssel aber 0xFF ist weiss ich das da das Ende ist und habe 
die richtige Adresse.

g457 schrieb:
> Zum Thema 'schnell durchsuchen': Binärsuche regelt.

Habe soeben nur ganz kurz im Wiki Artikel der Binär Suche gestöbert. 
Verstehe ich das richtig das sozusagen der Bereich immer wie mehr 
eingegrenzt wird in welchem ein gültiges Datenwort sein kann? Also ich 
beginne nicht bei 0 zu suchen sondern beginne schon in der Hälfte.
Falls das stimmt könnte ich das ja mit meiner Methode welche ich oben 
beschrieben habe kombinieren oder?

von Wolfgang (Gast)


Lesenswert?

Dominic A. schrieb:
> Zeit: 32Bit
> Temperatur: 16Bit
> Helligkeit: 16Bit
> Luft feuchte: 16Bit
> CRC-8: 8Bit

Ich bewundere deine Sensoren.
 - Deinem Temperatursensor traust du 16 Bit zu, obwohl deine 
Messumgebung (Homogenität/Rauschen durch Turbulenz) wohl eher höchstens 
12 Bit rechtfertigt
 - Ein Luftfeuchtesensor mit einer Genauigkeit von 16Bit erst noch 
erfunden werden muss
 - Die Helligkeit mit 16 bit auch schon einen ausgefeilten Sensor voraus 
setzt
 - Ein 32Bit Zeitstempel über gut 100 Jahre eine Auflösung von einer 
Sekunde erlaubt

Da sind Ansätze zur Reduzierung der Datenrate. Um auf eine runde 
Byteanzahl von 8 zu kommen (falls dein Speicherplatz wirklich so knapp 
ist), kannst du guten Gewissens 8Bit bei der Feuchte, 4 Bit bei der 
Temperatur und 12 Bit bei der Zeit streichen.
Insbesondere 1äßt sich der Datenumfang der Zeitstempel noch kleiner 
halten, indem auf jeder Page des Speichers nur einmal den volle 
Zeitstempel ablegt und bei den Datensäten nur die "Nachkommastellen"

Dominic A. schrieb:
> Es kann ja sein, dass nachdem ich die 2Byte Temperatur geschrieben
> habe die Betriebsspannung wegfällt.

Das Problem entfällt, wenn du feste Datenblockgrößen hast, weil du immer 
weißt bzw. ausrechnen kannst, wo ein Block anfängt und dadurch immer 
prüfen kannst, ob ein Block komplett ist.

von (prx) A. K. (prx)


Lesenswert?

Dominic A. schrieb:
> wird eine Methode beschrieben um zu erkennen ob die Betriebsspannung weg
> fällt. Ist dies die einzig sinnvolle Möglichkeit? Oder gibt es auch eine
> reine Software Lösung?

Irgendwie musst du mitkriegen, dass es bei der Spannung eng wird. Und 
dann genug Puffer bei der Stromversorgung einplanen, dass ein 
Löschvorgang noch sauber abgeschlossen werden kann. Ohne etwas 
Überlegung vor dem Bau dem Hardware wird das schwierig. Der 
Funktionsumfang von Microcontrollern wird zwar immer grösser, aber ein 
Präkognitionsmodul ist leider noch nicht dabei.

von Werner (Gast)


Lesenswert?

Dominic A. schrieb:
> Verstehe ich das richtig das sozusagen der Bereich immer wie mehr
> eingegrenzt wird in welchem ein gültiges Datenwort sein kann?

Ja, um z.B. mit der binären Suche einen Datensatz aus einer Million 
heraus zu fischen bzw. das Ende der Aufzeichnung zu finden, kommst du 
mit 20 Datensatzzugriffen und vergleichen aus.

von (prx) A. K. (prx)


Lesenswert?

holger schrieb:
> Mach 16 draus. Sonst hast du viel Spass
> beim überschreiten der Pagegrenzen.

Niemand zwingt einen dazu, die letzten N-1 Bytes einer Page zu 
verwenden. Eine Zweierpotenz als Grösse eines Records ist also unnötig.

: Bearbeitet durch User
von Dominic A. (neo123)


Lesenswert?

Wolfgang schrieb:
> Um auf eine runde
> Byteanzahl von 8 zu kommen (falls dein Speicherplatz wirklich so knapp
> ist), kannst du guten Gewissens 8Bit bei der Feuchte, 4 Bit bei der
> Temperatur und 12 Bit bei der Zeit streichen.

Der Speicherplatz reicht mir eigentlich bei weitem. Ich habe es soeben 
kurz durch gerechnet. Wenn 1 Datensatz 16Byte gross wäre und ich alle 
30Min eine Messung machen würde könnte ich fast 15 Jahre lang Werte 
speichern. Falls ich alle 10 Minuten speichern würde (Was mir bei weitem 
reicht), könnte ich immer noch 5 Jahre loggen.

Natürlich haben die Sensoren nicht diese Auflösung und schon gar nicht 
Genauigkeit. Da ich aber sowieso genug Speicherplatz habe dachte ich mir 
ich speichere die Daten alle in kompletten Bytes ab.
Die Zeit speichere ich ganz einfach im UNIX-Format.

A. K. schrieb:
> Ohne etwas
> Überlegung vor dem Bau dem Hardware wird das schwierig.

Das habe ich mir schon fast gedacht. Da werde ich wohl noch etwas an die 
bestehende Schaltung ran basteln.

> Der
> Funktionsumfang von Microcontrollern wird zwar immer grösser, aber ein
> Präkognitionsmodul ist leider noch nicht dabei.

Schön wärs aber =).

Werner schrieb:
> Ja, um z.B. mit der binären Suche einen Datensatz aus einer Million
> heraus zu fischen bzw. das Ende der Aufzeichnung zu finden, kommst du
> mit 20 Datensatzzugriffen und vergleichen aus.

Aber nach welchem Datensatz suche ich dann? Wenn ich nach 0xFF suche 
finde ich den ja schon in der Mitte und die Suche ist beendet.

von holger (Gast)


Lesenswert?

>Es ist in dieser Grössenordnung wenig relevant, wie gross ein Datensatz
>wirklich ist. Denn niemand zwingt einen dazu, die letzten N-1 Bytes
>einer Page zu verwenden.

Darüber denkt er aber nicht nach. Diese Ausnahme müsste er
berücksichtigen. Sonst läuft er zwangsläufig in die Falle.
Wenn man Datensätze mit der Grösse von Zweierpotenzen benutzt
erledigt sich das Problem quasi von selbst.

von (prx) A. K. (prx)


Lesenswert?

Dominic A. schrieb:
> Wie erkenne ich den ein ungültiges Paket? Es kann ja sein, dass nachdem
> ich die 2Byte Temperatur geschrieben habe die Betriebsspannung wegfällt.

Der Löschvorgang ist der interessantere Fall. Weil der ein paar 
Grössenordnungen langsamer ist. Wenn dir da zur falschen Zeit der Strom 
absemmelt, dann kann der Sektor/Block später bereits gelöscht 
erscheinen, ohne es aber vollständig zu sein.

von (prx) A. K. (prx)


Lesenswert?

Dominic A. schrieb:
> Aber nach welchem Datensatz suche ich dann? Wenn ich nach 0xFF suche
> finde ich den ja schon in der Mitte und die Suche ist beendet.

Ist binäre Suche derart schwer zu verstehen?

Dieses Flash ist in 4KB Sektoren aufgeteilt. Nutze diese. Musst du beim 
Löschen ohnehin.

Wenn der Sektor in der Mitte vom Flash mit einem gültigen Record 
anfängt, und das ist jünger als das vom ersten Sektor, dann gehts 
dahinter weiter. Sonst davor. In der nächsten Iteration betrachtest du 
auf die gleiche Weise die nun ermittelte Hälfte.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

A. K. schrieb:
> Der Löschvorgang ist der interessantere Fall. Weil der ein paar
> Grössenordnungen langsamer ist.

Warum sollte man während des Loggens löschen wollen? Das Flash wird 
einmal im Ganzen gelöscht und dann während eines Einsatzes so weit 
beschrieben, wie eben nötig.

Ich würde nach einem Abbruch (Absturz, Power loss, etc) einfach einen 
neuen Sektor anfangen und das mit dieser Idee kombinieren:

Wolfgang schrieb:
> Insbesondere 1äßt sich der Datenumfang der Zeitstempel noch kleiner
> halten, indem auf jeder Page des Speichers nur einmal den volle
> Zeitstempel ablegt und bei den Datensäten nur die "Nachkommastellen"

Man könnte z.B. am Anfang jedes Sektors einen langen Zeitstempel 
abspeichern. Falls nicht mehr als 1 Sekunde Auflösung gebraucht wird, 
z.B. als 32 Bit UNIX Timestamp.

In den einzelnen Datensätzen speichern man jetzt keinen absoluten 
Timestamp mehr, sondern immer den Abstand zu vorherigen Datensatz. Wenn 
1s - 255s dafür reichen, dann braucht man da nur 1 Byte. Ein Datensatz 
wird damit 8 Byte lang.

Immer wenn der Logger einen Sektor (4K bei diesem Flash) anfängt, 
schreibt er die aktuelle Zeit an den Anfang, gefolgt vom 1. Datensatz. 
Da bei diesem das "Zeitstempel-Abstand" Feld definitiv 0 ist, eignet 
sich das prima als Markierung ob der Sektor schon benutzt ist. Die 4 
extra Bytes nach dem Timestamp würde ich dann einfach unbenutzt lassen 
(alle Records fangen an einer durch 8 teilbaren Adresse an).

Wenn der Controller (re)started, sucht er einfach den ersten Sektor, der 
auf Adresse 8 ein 0xFF stehen hat und fängt mit diesem an.


XL

von Hott (Gast)


Lesenswert?

Der Powerdown ist kein Problem. Je nach Flash ist es in Seiten 
organisiert. Mit RAM dazu. Beim 45dB321 oder so ist das so gross wie 
eine Seite. Da schreibt man eine Seite voll, und setzt dann das Schreib 
Command ab. Das dauert dann vielleicht 4ms. Solange sollte man schon 
Strom haben, Ein dickerer Elko ist gerechtfertigt. Und eine 
Netzausfallerkennung.

von (prx) A. K. (prx)


Lesenswert?

Axel Schwenke schrieb:
> Warum sollte man während des Loggens löschen wollen?

Beispielsweise weil dann die letzten <n> Events gespeichert werden 
können. Wenn man alles löscht wenn es voll wird, dann ist die Historie 
weg.

> Das Flash wird einmal im Ganzen gelöscht und dann während eines
> Einsatzes so weit beschrieben, wie eben nötig.

Wenn das der Anforderung entspricht, klar. Da wo ich das bisher gemacht 
hatte war die Historie wichtiger.

von (prx) A. K. (prx)


Lesenswert?

Hott schrieb:
> Da schreibt man eine Seite voll, und setzt dann das Schreib
> Command ab.

Hast du mal ins Datasheet von diesem Flash geschaut? Das scheibt 
byteweise. Nicht seitenweise.

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

A. K. schrieb:
> Axel Schwenke schrieb:

>> Warum sollte man während des Loggens löschen wollen?
>
> Beispielsweise weil dann die letzten <n> Events gespeichert werden
> können. Wenn man alles löscht wenn es voll wird, dann ist die Historie
> weg.
...
> Da wo ich das bisher gemacht hatte war die Historie wichtiger.

Das hast du irgendwie falsch verstanden. Ich will nie im Logger löschen. 
Wenn das Flash voll ist, dann bleibt der Logger stehen. Notgedrungen. 
Woher soll der denn auch wissen, welche Daten im Flash du noch für 
aufhebenswert hältst und welche nicht?

Wenn man das Flash ausliest, dann kann man sich entscheiden, ob man es 
vor dem nächsten Einsatz löscht. Oder ob noch genug Platz frei ist für 
den nächsten Job.


XL

von (prx) A. K. (prx)


Lesenswert?

Axel Schwenke schrieb:
> Woher soll der denn auch wissen, welche Daten im Flash du noch für
> aufhebenswert hältst und welche nicht?

Bei mir: Die letzten Daten. Deshalb round robin.

von Dominic A. (neo123)


Lesenswert?

Axel Schwenke schrieb:
> Wenn man das Flash ausliest, dann kann man sich entscheiden, ob man es
> vor dem nächsten Einsatz löscht. Oder ob noch genug Platz frei ist für
> den nächsten Job.

Genau so habe ich es mir auch vorgestellt. Es ist ja sowieso genug Platz 
im Flash vorhanden.

Axel Schwenke schrieb:
> Man könnte z.B. am Anfang jedes Sektors einen langen Zeitstempel
> abspeichern. Falls nicht mehr als 1 Sekunde Auflösung gebraucht wird,
> z.B. als 32 Bit UNIX Timestamp.
>
> In den einzelnen Datensätzen speichern man jetzt keinen absoluten
> Timestamp mehr, sondern immer den Abstand zu vorherigen Datensatz. Wenn
> 1s - 255s dafür reichen, dann braucht man da nur 1 Byte. Ein Datensatz
> wird damit 8 Byte lang.

Das wäre möglich. Die Auflösung meiner Zeit beträgt eine Sekunde. Und 
die Zeit liegt ja bei mir auch schon als Unix Zeit vor. Angenommen ich 
speichere nun nach deinem Ansatz am Anfang jeder Page die Unix Zeit und 
in jedem Datensatz nur den Abstand in Sekunden. Wenn ich nun alle 30 
Minuten eine Messung machen will, und ein Datensatz 9Byte(2Byte Zeit 
Abstand) gross ist, kann eine Page einen Zeitraum von 800000 Sekunden 
enthalten.
Das heisst ich bräuchte 3Byte für den Zeitabstand. Die Ersparnis von 
1Byte pro Datensatz lohnt sich also aus meiner Sicht nicht wirklich.
Ein anderes Problem welches ich bei dieser Methode sehe ist folgendes: 
Was passiert wenn ich mit dem Logger ein paar Daten aufnehme dann die 
Batterie raus nehme und nach irgendwie 3-4 Wochen wieder rein tue? Dann 
überläuft wieder die Abstands variable.


holger schrieb:
>>Es ist in dieser Grössenordnung wenig relevant, wie gross ein Datensatz
>>wirklich ist. Denn niemand zwingt einen dazu, die letzten N-1 Bytes
>>einer Page zu verwenden.
>
> Darüber denkt er aber nicht nach. Diese Ausnahme müsste er
> berücksichtigen. Sonst läuft er zwangsläufig in die Falle.
> Wenn man Datensätze mit der Grösse von Zweierpotenzen benutzt
> erledigt sich das Problem quasi von selbst.

Ist der Speicherverbrauch nicht grösser wenn ich einen Datensatz von 11 
auf 16 Byte künstlich vergrössere als wenn ich mit einem 11 Byte 
Datensatz arbeite und dann einfach die letzten paar Bytes des Flash 
nicht benutzen kann weil es nicht schön aufgeht?

Eine Frage habe ich noch. Muss ich erkennen ob die Versorgungsspannung 
plötzlich wegfallt? Ich denke die Chance ist sehr gering das man genau 
den Moment trifft in dem Daten gespeichert werden. Obwohl bekanntlich 
schlägt ja Murphy immer wieder gerne zu.

von Axel S. (a-za-z0-9)


Lesenswert?

Dominic A. schrieb:
> Axel Schwenke schrieb:

>> Man könnte z.B. am Anfang jedes Sektors einen langen Zeitstempel
>> abspeichern.
...
>> In den einzelnen Datensätzen speichern man jetzt keinen absoluten
>> Timestamp mehr, sondern immer den Abstand zu vorherigen Datensatz.

> Das wäre möglich. Die Auflösung meiner Zeit beträgt eine Sekunde. Und
> die Zeit liegt ja bei mir auch schon als Unix Zeit vor. Angenommen ich
> speichere nun nach deinem Ansatz am Anfang jeder Page die Unix Zeit und
> in jedem Datensatz nur den Abstand in Sekunden. Wenn ich nun alle 30
> Minuten eine Messung machen will, und ein Datensatz 9Byte(2Byte Zeit
> Abstand) gross ist, kann eine Page einen Zeitraum von 800000 Sekunden
> enthalten.
> Das heisst ich bräuchte 3Byte für den Zeitabstand.

Nein. Ich zitiere mich selbst:

>> In den einzelnen Datensätzen speichern man jetzt keinen absoluten
>> Timestamp mehr, sondern immer den Abstand zu vorherigen Datensatz.

Nicht: den Abstand zum Anfang des Sektors.

Aber 30 Minuten sind wirklich verdammt lang.

> Ein anderes Problem welches ich bei dieser Methode sehe ist folgendes:
> Was passiert wenn ich mit dem Logger ein paar Daten aufnehme dann die
> Batterie raus nehme und nach irgendwie 3-4 Wochen wieder rein tue? Dann
> überläuft wieder die Abstands variable.

Nein. Du fängst dann einen neuen Sektor an und läßt den Rest des letzten 
Sektors leer. Deswegen wird der Abstand nie länger als dein 
eingestelltes Meßintervall + \epsilon.

Bei einem Meßintervall von 30 Minuten würde ich gar keinen Timestamp im 
Record speichern. Einfach in einem festen Raster Timestamps einstreuen. 
Für die Records dazwischen ergibt sich die Zeit aus ihrer Position. 
Komplett ohne Timestamps geht nicht, weil du dann nach einem z.B. 
Batteriewechsel nicht neu aufsetzen könntest.

>> Darüber denkt er aber nicht nach. Diese Ausnahme müsste er
>> berücksichtigen. Sonst läuft er zwangsläufig in die Falle.
>> Wenn man Datensätze mit der Grösse von Zweierpotenzen benutzt
>> erledigt sich das Problem quasi von selbst.
>
> Ist der Speicherverbrauch nicht grösser wenn ich einen Datensatz von 11
> auf 16 Byte künstlich vergrössere als wenn ich mit einem 11 Byte
> Datensatz arbeite und dann einfach die letzten paar Bytes des *Flash*

Die letzten paar Bytes des Sektors

> nicht benutzen kann weil es nicht schön aufgeht?

Ja, das ist sicher weniger Verschnitt als wenn du jeden Datensatz 
einzeln aufrundest. Wenn du das obige Verfahren implementierst, dann 
mußt du ja sowieso auf Sektorgrenzen aufpassen. Dann kannst du die 
Records auch dicht packen.

> Eine Frage habe ich noch. Muss ich erkennen ob die Versorgungsspannung
> plötzlich wegfallt? Ich denke die Chance ist sehr gering das man genau
> den Moment trifft in dem Daten gespeichert werden. Obwohl bekanntlich
> schlägt ja Murphy immer wieder gerne zu.

Wenn du eine robuste Methode zum Finden der nächsten freien Adresse 
hast, dann geht jedes Mal höchstens ein Datensatz kaputt. Und den 
erkennst du später beim Auslesen am inkorrekten CRC.


XL

von Wolfgang (Gast)


Lesenswert?

Dominic A. schrieb:
> Aber nach welchem Datensatz suche ich dann? Wenn ich nach 0xFF suche
> finde ich den ja schon in der Mitte und die Suche ist beendet.

Nein, du suchst natürlich den letzten, der nicht 0xFF hat. Suchstrategie 
ist die selbe, wie bei einem DAC mit sukzessive Approximation, d.h. du 
mußt dich immer bis zum letzen Suchschritt im Baum der Möglichkeiten 
runterhangeln. Die Zahl der Suchschritte ist der auf ganze Zahl 
aufgerundete Zweierlogarithmus der möglichen Datensätze im Speicher, 
freier Random-Zugriff vorausgesetzt.

von Dominic A. (neo123)


Lesenswert?

Axel Schwenke schrieb:
> Nein. Du fängst dann einen neuen Sektor an und läßt den Rest des letzten
> Sektors leer. Deswegen wird der Abstand nie länger als dein
> eingestelltes Meßintervall + \epsilon.
>
> Bei einem Meßintervall von 30 Minuten würde ich gar keinen Timestamp im
> Record speichern. Einfach in einem festen Raster Timestamps einstreuen.
> Für die Records dazwischen ergibt sich die Zeit aus ihrer Position.
> Komplett ohne Timestamps geht nicht, weil du dann nach einem z.B.
> Batteriewechsel nicht neu aufsetzen könntest.

Achso ja klar, habs vorhin falsch verstanden. Ja so wäre es auf jeden 
Fall möglich. Einfach nur Timestamps einstreuen gefällt mir nicht so 
weil ich eventuell vorhabe später im PC-Programm den Intervall 
einzustellen. Dann würde es ziemlich mühsam werden falls verschiedene 
Intervalle gespeichert werden.

Axel Schwenke schrieb:
> Die letzten paar Bytes des Sektors

Scheinbar stehe ich da vollkommen auf dem Schlauch. Wieso den pro 
Sektor? Ich kann von dem MCU aus den Flash von 0-0x3FFFFFH komplett 
durch adressieren. Das Paging übernimmt der Flashcontroller selber. Das 
heisst selber auf dem MCU bemerke ich von den Pages eigentlich nichts. 
Das mit den Pages kommt doch erst zum Zuge wenn ich Löschen will?

Wolfgang schrieb:
> Nein, du suchst natürlich den letzten, der nicht 0xFF hat. Suchstrategie
> ist die selbe, wie bei einem DAC mit sukzessive Approximation, d.h. du
> mußt dich immer bis zum letzen Suchschritt im Baum der Möglichkeiten
> runterhangeln. Die Zahl der Suchschritte ist der auf ganze Zahl
> aufgerundete Zweierlogarithmus der möglichen Datensätze im Speicher,
> freier Random-Zugriff vorausgesetzt.

Alles klar, ich denke die Binär Suche sollte ich hinbekommen. Ein 
Problem weniger =).

von Nosnibor (Gast)


Lesenswert?

Da man die Bytes einzeln schreiben kann und im Betrieb nicht gelöscht 
werden muß, sind Pages und Sektoren egal. Die Datensätze können also so 
groß oder klein sein, wie es sich eben aus den Daten ergibt.
Der Flash ist wohl auch groß genug, also braucht man die Daten nicht bis 
aufs letzte Bit komprimieren, wenn dadurch die Software zu komplex wird 
(Zeit manchmal absolut und manchmal als Differenz). 2x12bit in drei byte 
packen oder so würde ich aber noch machen.

Interessant ist das Problem, wenn während des Schreibens eines 
Datensatzes der Strom ausfällt. Dann liegt ein unvollständiger Datensatz 
im Flash. Damit muß man also auch rechnen, wenn man beim Einschalten den 
ersten freien Platz sucht: der Platz ist nur frei, wenn alle Bytes FF 
sind, nicht nur das high-byte der Temperatur, oder die Prüfsumme oder 
so.

Dann gibt es noch das Risiko, daß ein unvollständiger Datensatz frei 
oder vollständig aussieht, weil der Strom ausgefallen ist, während das 
erste oder letzte Byte geschrieben wurde. Da könnte es sein, daß ein 
Byte noch als FF gelesen wird, aber einige Bits schon etwas 
"angefressen" sind und dann beim späteren Schreiben zu 0 werden. Oder 
daß zu schwach geschriebene Bits irgendwann wieder nach 1 zurückfallen 
(oder je nach Temperatur und Mondphase als 1 oder 0 gelesen werden).
Dagegen hilft ein Statusbyte pro Datensatz, in dem man einzelne Bits 
"abhakt", um anzuzeigen, wie weit man mit dem Datensatz ist. In diesem 
Fall kommt man mit zwei Bits aus:
Statusbyte FF: der Datensatz ist frei. Wenn man ihn benutzen will, 
löscht man als erstes das oberste Bit im Statusbyte, schreibt also 7F 
rein.
Statusbyte 7F: der Datensatz ist unvollständig / in Arbeit. Erst wenn 
alle Daten (und die Prüfsumme) geschrieben sind, löscht man auch das 
nächste Bit im Statusbyte, schreibt also 3F.
Statusbyte 3F: der Datensatz ist gültig.

Falls der Strom beim ersten Schreibvorgang ausfällt, richtet ein 
"angefressenes" Bit keinen Schaden an, weil das ja ohnehin beim nächsten 
Schreibvorgang als erstes gelöscht wird. Falls der Strom beim letzten 
Schreibvorgang ausfällt, wird der Datensatz eben mal als unvollständig 
und mal als gültig bewertet, aber ein Schaden (falsche Information) 
entsteht nicht, weil ja korrekte Daten drinstehen. Wenn der Strom 
irgendwann dazwischen ausfällt, steht im Statusbyte eindeutig drin, daß 
der Datensatz ungültig ist.

Ein Warnsignal von der Hardware, daß demnächst der Strom ausfällt, ist 
also nicht nötig.

von Dominic A. (neo123)


Lesenswert?

Vielen Dank für deine ausführliche Erklärung. Die Idee mit dem Statusbit 
finde ich gut. Jedoch benötige ich doch 2 Bytes dafür oder? Ich kann ja 
nur einmal von 0xFF auf den ersten Status also 0x7F schreiben. Dann 
müsst ich es ja löschen und ich kann nur ganze Pages löschen. Würde ich 
den die angeknabberten Bits nicht auch mit dem CRC erkennen?

von Nosnibor (Gast)


Lesenswert?

Wenn nichts gegenteiliges im Datenblatt steht, kann man dasselbe Byte 
mehrmals beschreiben ohne zwischendurch zu löschen. Man muß nur 
beachten, daß das Schreiben immer nur Bits von 1 nach 0 verändern kann, 
niemals umgekehrt.

Mit den "angeknabberten" Bits meinte ich solche, die nicht mehr 
hundertprozentig 1 sind, aber auch noch nicht ganz 0. Ein Bit im Flash 
besteht ja letztendlich aus einem Analogwert, nämlich der Ladungsmenge, 
die irgendwo gespeichert ist. Es ist also möglich, daß da nicht 0 oder 1 
drinsteht sondern z.B. 0,6. Die Leseelektronik auf dem Flash-Chip rundet 
das natürlich zu einem sinnvollen Wert (also 0 oder 1), aber das ist 
analoge Signalverarbeitung und kann durch Temperatur, 
Versorgungsspannung oder sonstwasalles beeinflußt werden.
Wenn das Bit vollständig gelöscht oder geschrieben wurde, ist das kein 
Problem, aber wenn man mitten beim Schreiben unterbricht, ist eben 
irgendeine mittlere Ladung gespeichert, die nicht bei jedem Lesevorgang 
zum gleichen Ergebnis gerundet wird. Man liest also z.B. eine 1, und 
später mit ein paar mV mehr Versorgungsspannung liest man an derselben 
Stelle eine 0. Mit der CRC würde man zwar erkennen, daß die Daten gerade 
nicht stimmen, aber für die Erkennung, ob ein Datensatz frei ist, geht 
das nicht.

Wenn der Stromausfall beim Schreiben des ersten Bytes (z.B. 1F) 
passiert, liest man später vielleicht FF und denkt, der Platz ist frei. 
Wenn man jetzt z.B. 21 drüberschreibt, kann es später passieren, daß die 
zuerst "halb" geschriebenen 0-Bits gelegentlich zum Vorschein kommen, 
und dann liest man eben mal 21 und mal 01. OK, die CRC verhindert dann 
wieder das Schlimmste, da stimmt. Aber ein Speicher, der sich nicht 
entscheiden kann, wieviel denn nun drin steht, ist zumindest ungewohnt; 
da kann man mit allerlei Software drüber stolpern.

Letztendlich ist die Wahrscheinlichkeit gering; es ging mir 
hauptsächlich darum, zu zeigen, daß man auch mit reinen 
Softwaremaßnahmen wieder Zuverlässigkeit herstellen kann.

Eine elegante Hardwaremaßnahme wäre übrigens ein brown-out-Reset, der 
den Prozessor anhält, wenn die Versorgungsspannung wegbricht, aber bevor 
die Spannung so niedrig ist, daß das Flash nicht mehr zuverlässig 
Schreiben kann. Da hätte man das Problem mit den "halben" Bits auch 
erledigt, ohne daß im Schaltplan oder in der Software eine Extramaßnahme 
erkennbar wäre.

von Dominic A. (neo123)


Lesenswert?

Alles klar das mit dem mehrmals beschreiben funktioniert einwandfrei. 
Ich dachte immer sobald einmal irgendetwas geschrieben wurde geht gar 
nichts mehr.
Somit sind vorerst eigentlich alle Fragen geklärt. Ich werde mal 
versuchen das ganze in der Software zu implementieren.

Vielen Dank an alle die mir geholfen haben. Sehr Nett!

von Wolfgang (Gast)


Lesenswert?

Nosnibor schrieb:
> Ein Bit im Flash besteht ja letztendlich aus einem Analogwert
Du meinst die Ladung einer Speicherzelle. Die Zeiten, wo ein Bit pro 
Speicherzelle enthalten ist, sind zumindest bei NAND-Flash-Speichern 
vorbei. Das sind inzwischen meist Multi-Level Zellen (MLC).

von (prx) A. K. (prx)


Lesenswert?

Hier geht es um NOR-Flash mit 32 MBits, nicht um NAND-Flash mit 32 
GBits.

von Dominic A. (neo123)


Lesenswert?

Ich bin es nochmal.
Es geht um die Binäre Suche. Irgendwie komme ich damit doch nicht so 
richtig zurecht.

Eine kurze Zusammenfassung von hier damit sich nicht jeder noch einmal 
alles durchlesen muss:
Ich habe ein Flash Speicher in welchem ich 12Byte grosse Datensätze 
abspeichere. Das erste Byte des Datensatz ist ein Statusbyte. Sobald ich 
anfange den Datensatz zu beschreiben setze ich dieses Byte auf 0x7F. 
Sobald das schreiben eines Datensatzes fertig ist schreibe ich in dieses 
Byte 0x1F. Somit kann ich bei jedem Datensatz überprüfen ob er komplett 
geschrieben wurde und somit als gültig gilt.

Nun zu meinem Problem:
Es geht nun darum den letzten gültigen Datensatz im Flash zu suchen. Im 
Flash selber haben 349525 Datensätze Platz. Um dies zu erreichen wurde 
die binär Suche vorgeschlagen. Ich habe versucht diese mit Hilfe des 
Codes von Wikipedia zu implementieren. Nun funktioniert dies aber noch 
nicht richtig. Das Problem ist, das nur die Hälfte der Datensätze 
erkannt wird.

Ist der Flash zum Beispiel noch komplett leer und ich die Suche starte 
kommt entsprechend auch eine 0 zurück. Nun speichere ich einen Satz ab. 
Kommt immer noch eine 0 zurück. Nach einem weiteren Datensatz kommt eine 
2 zurück. Dann kommt eine 3. Dann wieder 3,dann eine 5.
Die Reihenfolge ist also:
0
0
2
3
3
5
5
7

Der Suche Algorithmus ist folgender:
1
uint16_t find_last_measurmentblock(void)
2
{
3
    int mitte;
4
    int links = 0; /* man beginne beim kleinsten Index */
5
    int rechts = 349525 - 1; /* Arrays-Index beginnt bei 0 */
6
7
    /* Solange die zu durchsuchende Menge nicht leer ist */
8
    while (links <= rechts)
9
    {
10
        mitte = links + ((rechts - links) / 2); /* Bereich halbieren */
11
12
        if (checkblock(mitte) == 0)
13
            rechts = mitte - 1; /* im linken Abschnitt weitersuchen */
14
        else /* (M[mitte] < suchwert) */
15
            links = mitte + 1; /* im rechten Abschnitt weitersuchen */
16
    }
17
    return mitte;
18
}
Die Funktion checkblock() liefert eine 1 zurück wenn der Block gültig 
ist und eine 0 wenn er ungültig ist.

Sieht jemand was am Such Code falsch ist?

von Nosnibor (Gast)


Lesenswert?

Die Abbruchbedingung der Suchschleife ist, daß rechts und links 
"über Kreuz" sind. Dann gibt sie mitte als Ergebnis zurück.

In der Runde bevor rechts und links über Kreuz geraten, sind sie 
erstmal gleich. mitte hat dann logischerweise denselben Wert. Dann 
wird checkblock() darauf angewendet, aber das Ergebnis ignoriert: egal 
ob der Block gültig oder ungültig ist, seine Position ist das Ergebnis.

Ich würde die Schleifenbedingung ändern in links<rechts, dann bricht die 
Schleife ab, wenn beide Grenzen gleich sind. checkblock(links) verrät 
dann, ob links oder links+1 das gesuchte Ergebnis ist.

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.