Hallo Community Ich suche Hilfe bei der erstellung eines effizienten Algorithmus zur Dauerspeicherung auf einem EEPROM. Zuerst das Setup: Verwendet wird ein externer EEPROM Speicher mit 2MB Speicher. Angesteuert wird er mit SPI. Der Adressbereich des EEPROM's ist von 0x000000 bis 0x03FFFF Die kleinstmögliche "Löscheinheit" ist ein 4KB-Sektor-Erase. Eine Bibliothek zum Schreiben und Lesen ist vollständig vorhanden. Das Programm ist ein kleines Messgerät, welches die Daten dauerhaft auf den EEPROM ablegt. Sobald der Speicher voll ist, soll das Program den ersten 4KB Sektor wieder Löschen und dort weiterschreiben. Ist auch dieser Sektor wieder voll soll der nächste Sektor gelöscht werden, usw.. Ich brauche also einen Algorithmus, welcher folgende zwei Dinge kann: - Beim Aufstarten den letzten belegten Speicherplatz suchen, um dort dann weiterschreiben zu können. - Vorzu Prüfen ob bald die grenze eines 4KB-Sektors erreicht ist und den darauffolgenden Sektor dann löschen. Meine Ansätze: Für das erste Problem kann ich solange den Speicher lesen, bis ich nur noch lauter Einsen zurückbekomme. (Bei diesem EEPROM bedeutet 0xFF dass er leer ist). Von der Art der Daten die ich auf meinen Speicher schreibe weiss ich, dass ich nie eine Einserfolge haben kann, die länger als 3 Byte ist. Sollte ich beim Auslesen also auf eine längere Einserfolge treffen, dann weiss ich, dass dort der zuletzt genutzte Speicherplatz ist. Für das zweite Problem könnte ich die Adressen vergleichen. Wan immer die ersten 12 Bit der Adresse Null sind, ist ein neuer 4kB Sektor erreicht. Dementsprechend muss der darauffolgende Sektor gelöscht werden. Ohne zu Wissen ob diese Ansätze funktionieren (sind noch nicht umgesetzt), glaube ich, dass sie sehr ineffizient sind und suche deshalb nach besseren Lösungen. Für Ratschläge und Optimierungen wäre ich sehr Dankbar. mfg
hi gleiche frage stellte sich mir auch irgendwann ich habe dann einfach das SPIFFS filesystem genommen https://github.com/pellepl/spiffs klingt evtl alles zu oversized ... aber es ist am ende sehr praktisch wenn man alles als datei sieht. zumal man nur ein paar kleine funktionen anpassen muss und das ganze läuft dann und über das handling musst du dir keinen kopf machen. schreibe eine datei .. hänge notfalls daten an .. wie du möchtest. ggf eine verbindung zum PC um diese dateien einfach hoch/runterladen zu können
Die größten (verfügbaren bzw. bezahlbaren) SPI-EEPROMs liegen im Moment bei 256 kByte. 2 MByte ist noch Zukunftsmusik. Außerdem muss/kann man EEPROMs nicht sektorweise löschen (der Witz von EEPROMs ist doch gerade, dass man sie byteweise überschreiben kann, und dass das vorherige Löschen solcher einzelnen Bytes bzw. 4-Byte Blöcken automatisch erfolgt). Bei NOR- oder NAND-Flash (um die es wohl geht?!) muss man beachten, dass das Löschen eines Sektors "lange" dauert, und der Flash in dem Zeitraum "blockiert" ist. Also muss man einen ausreichend großen Puffer einplanen. Oder zwei Chips, die abwechselnd (sektorweise oder komplett) beschreiben werden. Ein "Leertest" allein anhand "FF..." ist nicht ausreichend, denn bei Unterbrechung der Stromversorgung, Reset, ... kann "Müll" im Flash zurück bleiben. Also Datensätze anhand CRC oder so auf Gültigkeit überprüfen. Übrigens, was hat das mit avr-gcc zu tun???
Du könntest die ersten 2 bis 4 Byte von jedem Sektor für den Sektor-Zustand reservieren. Dann musst du bei der Suche nach dem Kaltstart nur ein Byte pro Sektor lesen. Ich glaube, das braucht man sowieso, weil ein Sektor nicht nur frei oder belegt sein kann: * frisch aus der Fabrik * enthält Daten * ist voll (mit Daten) * wird gerade gelöscht * ist gelöscht Die letzten beiden Zustände sind wichtig falls der Strom ausfällt während gerade gelöscht wird. Erst wenn die Flash-Hardware sagt "ist gelöscht" wird der Status "ist gelöscht" geschrieben. Nach einem Stromausfall wird ein Sektor ggf. ein zweites Mal gelöscht. Ich schreibe noch einen Lösch-Zyklus-Zähler hinter die Status-Bytes. Damit müsste man eigentlich eine binäre Sektor-Suche machen können.
1 | ich habe dann einfach das SPIFFS filesystem genommen |
Danke für den Tip. Für mich leider nicht die richtige lösung, da der Controller berets jetzt schon am Anschlag läuft, deshalb such ich auch nach Optimierungen.
1 | Bei NOR- oder NAND-Flash (um die es wohl geht?!) muss man beachten, dass |
2 | das Löschen eines Sektors "lange" dauert, und der Flash in dem Zeitraum |
3 | "blockiert" ist. |
Ja ich befürchte ich habe da wieder einmal was falsch verstanden. Ich entschuldige mich für die verwirrung. Auf jedenfall kann ich bei meinem Speicher nicht Byteweise löschen. Gut dass du das mit der Löschzeit ansprichts, das hatte ich bisher gar nicht beachtet. Gemäss Datenblatt liegt die bei 18ms. Ich denke dass ich den Datenverlust in dieser Zeit verkraften muss, sprich das Programm in dieser Zeit warten lasse.
1 | Also Datensätze anhand CRC oder so auf Gültigkeit |
2 | überprüfen. |
Paritybits sind bei den Daten vorhanden. Eine überprüfung auf Korrektheit kann ich also durchführen. Aber zur Erkennung des letzten Speicherortes ist dies doch irrelevant? In erster Linie will ich erkennen wo ich stehengeblieben bin, ob der letzte Datensatz dann korrekt ist ist eine andere Frage
1 | Übrigens, was hat das mit avr-gcc zu tun??? |
Irgendwie müssen die Leute doch wissen welche Mikrocontroller Architektur ich verwende und welche Toolchain. Nochmals vielen Dank für alle Antworten. mfg
:
Bearbeitet durch User
1 | Du könntest die ersten 2 bis 4 Byte von jedem Sektor für den |
2 | Sektor-Zustand reservieren. |
Ich habe gerade versucht deinen Ansatz zu implementieren. Ich scheitere allerdings daran, dass ich den Status des Sektors ja nicht überschreiben kann ohne den gesamten Sektor zu löschen.
Beitrag #5253878 wurde von einem Moderator gelöscht.
Hans F. schrieb: > Du könntest die ersten 2 bis 4 Byte von jedem Sektor für den > Sektor-Zustand reservieren. > > Ich habe gerade versucht deinen Ansatz zu implementieren. Ich scheitere > allerdings daran, dass ich den Status des Sektors ja nicht überschreiben > kann ohne den gesamten Sektor zu löschen. deswegen brauchst du mehr als ein Byte; jede Statusänderung (es sind ja sehr wenige) ändert ein weiteres Byte von FF auf etwas mit Wiedererkennungswert.
A. B. schrieb: > Die größten (verfügbaren bzw. bezahlbaren) SPI-EEPROMs liegen im Moment > bei 256 kByte. 2 MByte ist noch Zukunftsmusik. > Aha.... http://uk.farnell.com/amic/a25l016m-f/ic-sm-flash-16mb-spi-top-boot/dp/1697529 http://www.ebay.de/itm/WINDBOND-W25Q16BVSIG-25Q16B-16M-BIT-FLASH-8-SPI-BUS-SERIAL-EEPROM-BIOS-CHIP/121715258475?hash=item1c56cb746b:g:744AAOSwDNdVuQof
eagle user schrieb: > deswegen brauchst du mehr als ein Byte; jede Statusänderung (es sind ja > sehr wenige) ändert ein weiteres Byte von FF auf etwas mit > Wiedererkennungswert. Achso jetzt hab ich das Konzept verstanden! Klingt eigentlich ganz plausibel, ich denke das sollte sich umsetzen lassen. Nochmals Kurz wegen der EEPROM und FLASH geschichte. Ich glaube die Onlineshops verwenden den Begriff mehrdeutig. Ich habe bei meinem Chip nochmals nachgesehen. Auf dem Ettiket der Verpackung ist dieser unverfälschbar mit "Serial EEPROM" betittelt, das Datenblatt nennt den Chip allerdings "Serisl Flash".
Hans F. schrieb: > Nochmals Kurz wegen der EEPROM und FLASH geschichte. Ich glaube die > Onlineshops verwenden den Begriff mehrdeutig. Ich habe bei meinem Chip > nochmals nachgesehen. Auf dem Ettiket der Verpackung ist dieser > unverfälschbar mit "Serial EEPROM" betittelt, das Datenblatt nennt den > Chip allerdings "Serisl Flash". Du hast einen Flash Baustein! Und natürlich ist das ein EEPROM (electrically erasable programmable read-only memory) Merksatz: §1: Jeder Flash Baustein ist ein EEPROM. §2: Nicht jedes EEPROM ist ein Flash Baustein. Siehe: https://de.wikipedia.org/wiki/Flash-Speicher
eagle user schrieb: > deswegen brauchst du mehr als ein Byte; jede Statusänderung (es sind ja > sehr wenige) ändert ein weiteres Byte von FF auf etwas mit > Wiedererkennungswert. Man braucht nicht unbedingt mehrere Bytes. Man kann ja das selbe Byte "überschreiben", sofern sich die Bits nur von 1 auf 0 ändern. Ein einzelnes reicht also auch schon für 8 Änderungen.
OMG .. lesen will gerlernt sein ... ich verwende natürlich einen SPI Flash!! EEPROM habe ich total überlesen. sorry
4444444444444444444444 schrieb: > OMG .. > > lesen will gerlernt sein ... > ich verwende natürlich einen SPI Flash!! > > EEPROM habe ich total überlesen. > > > sorry Und das ist also kein EEPROM?
Stefan E. schrieb: > Man braucht nicht unbedingt mehrere Bytes. Man kann ja das selbe Byte > "überschreiben", sofern sich die Bits nur von 1 auf 0 ändern. Ein > einzelnes reicht also auch schon für 8 Änderungen. Gut zu wissen, war mir nämlich nicht bewusst dass das geht. Werde ich auch versuchen zu implementieren. Daanke und liebe Grüsse
Ich hätte noch eine ergänzende Frage. Die hat jetzt mit dem eigentlichen Problem nichts zu tun. jedoch denke ich dass es überflüssig ist extra einen neuen Thread zu eröffnen. Und zwar hab ich Probleme mit der Auto Address Increase Funktion des Speichers. Das Schreiben und Lesen von 8Bit Registern klappt problemlos. Nun möchte ich aber meinem Program je 56Bit an Daten aufsmal schreiben. Die entsprechende Sequenz im Datenblatt habe ich als Anhang hinzugefügt. Wenn ich das Richtig verstanden habe, dann wird für die Zeit des Schreibvorgangs die Funktion des MISO Pins (im Datenblatt nur "SO" genannt) während dieser Zeit umgeschaltet, so dass man an ihm erkennen kann, ob der Speicherbaustein gerade beschäftigt ist. Gemäss Datenblatt gilt dann: MISO = 0 : Device is busy MISO = 1 : Device is ready for next operation Ich habe hier exemplarisch mein Code für eine Schreibsequenz von 4* 8Bit. Ich hoffe die Namensgebung ist einigermassen eindeutig.
1 | void SPI_Write(uint32_t address, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4){ |
2 | uint8_t address_HIGH = (address >> 16)&0xFF; |
3 | uint8_t address_MED = (address >> 8)&0xFF; |
4 | uint8_t address_LOW = (address & 0xFF); |
5 | SPI_EnableCS(); // Chip Select low (ist aktiv low) |
6 | SPI_Transmit(EBSY); |
7 | SPI_DisableCS(); // Chip Select High |
8 | ;
|
9 | SPI_EnableCS(); |
10 | SPI_Transmit(WREN); |
11 | SPI_DisableCS(); |
12 | ;
|
13 | SPI_EnableCS(); |
14 | SPI_Transmit(AAIW);// AAIW entspricht dem befehl "AD" im datenblatt |
15 | SPI_Transmit(address_HIGH); |
16 | SPI_Transmit(address_MED); |
17 | SPI_Transmit(address_LOW); |
18 | SPI_Transmit(d1); |
19 | SPI_Transmit(d2); |
20 | SPI_DisableCS(); |
21 | ;
|
22 | SPI_EnableCS(); |
23 | while(!SPDR){ |
24 | ;
|
25 | }
|
26 | SPI_DisableCS(); |
27 | ;
|
28 | SPI_EnableCS(); |
29 | SPI_Transmit(AAIW); |
30 | SPI_Transmit(d1); |
31 | SPI_Transmit(d2); |
32 | SPI_DisableCS(); |
33 | ;
|
34 | SPI_EnableCS(); |
35 | while(!SPDR){ |
36 | ;
|
37 | }
|
38 | SPI_DisableCS(); |
39 | ;
|
40 | SPI_EnableCS(); |
41 | SPI_Transmit(WRDI); |
42 | SPI_DisableCS(); |
43 | ;
|
44 | SPI_EnableCS(); |
45 | SPI_Transmit(DBSY); |
46 | SPI_DisableCS(); |
47 | ;
|
48 | SPI_EnableCS(); |
49 | SPI_Transmit(RDSR); |
50 | SPI_DisableCS(); |
51 | }
|
Ob die Busy-Abfrage mit dieser While-Schlaufe so korrekt ist weiss ich nicht. Müsste man eventuell noch Dummy-Bytes senden in dieser Zeit? Und wenn wir schon beim Thema sind: Welche Bitfolge ist als Dummy zulässig? Im Datenblatt wird nirgends genannt wie ein Dummy auszusehen hat. Ich habe mich einfach an existierenden SPI Bibliotheken orientiert. Dort sind Dummys entweder eine Einserfolge oder eine Nullerfolge. Danke für die Hilfe! mfg
Der "Zukunftssicherheit" wegen ist es sinnvoll, nur die gängigen, bei NOR-Flash herstellerübergreifend identischen Kommandos zu verwenden. 0x03 (Read), 0x02 (Page Program), 0x05 (Read Status Reg.), 0x06 (Write Enable), 0x20 (Sector Erase), 0x9F (Read ID) sind weitgehend Konsens, ebenso BUSY- und WEL-Bit im Statusregister. (Und 0x13 bzw. 0x12 statt 0x03 bzw. 0x13 bei 4-Byte-Adressen). Auch die Page Size ist bei fast allen 256 Bytes. Jede nette Spezialität, die auf den ersten Blick schön aussieht, fällt einem früher oder später doch auf die Füße.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.