Hi, Ich möchte eine Look Up Table (4kByte) im virtuellen EEPROM eines STM32F3F303K8T6 speichern, jedoch klappt das irgendwie nicht mehr ab dieser Größe. 256xuint16_t=512Byte klappt noch, 512xuint16_t=1kByte nicht mehr. Die Library die ich verwende habe ich oben angehängt und ist von STM32 und ich habe bereits einige Einstellungen versucht anzupassen, jedoch leider ohne Erfolg. Eine Page hat die Grösse von 2kByte, daher sollte ja eigentlich zumindest die 512xuint16_t ohne Probleme reinpassen. Ich habe auch versucht bereits bei der Flash Addresse ADDR_FLASH_PAGE_16 zu starten, jedoch läuft mir das in einen Hardfault. Mit dem Speicher kenne ich mich einfach zu wenig aus und frage daher hier im Forum um Rat, wie ich den Speicher vergrößern kann, bzw. ob das überhaupt so klappen kann? Hier gibt es ja von STM32 ein Application Note dazu: https://www.st.com/content/ccc/resource/technical/document/application_note/ee/ef/d7/87/cb/b7/48/52/CD00165693.pdf/files/CD00165693.pdf/jcr:content/translations/en.CD00165693.pdf Und es wird beschrieben, dass in ihrem Beispiel nur 2 Pages à je 2kByte verwendet werden und eine Page immer in die andere kopiert wird. Daher kann ich in diesem Beispiel ja nur 2kByte speichern, jedoch klappt bei mir nicht einmal 1kByte. Gruss Bert
Ok, ich sehe zumindest jetzt, warum es nicht geht. Es wird ja immer die Addresse und die Daten gespeichert, also immer 32Byte für eine uint16_t. Daher kann ich in einer 2kByte Page nur 512xuint16_t speichern. Nun werden ja bei einer vollen Page einfach die alten Daten in eine neue Page übertragen. Kann ich aber die Page auch grösser als die 2kByte wählen, also z.B 16kByte? Oder klappt das mit dem Flash dann nicht mehr, da FLASH_PAGE_SIZE standardmäßig auf 2kByte ist. Edit: Ok habe es hinbekommen, einfach die FLASH_PAGE_SIZE erhöht und nun kann ich alles speicher wie gewollt.
:
Bearbeitet durch User
Leider klappt es irgendwie immer noch nicht, zumindest der Page Wechsel. Nachdem Page 0 voll ist und Page 1 beschrieben wird (mit HAL_OK), gibt es beim Neustart des Controllers bei EE_Init() immer den Flash Status 128 (PAGE_FULL) zurück, somit einen Fehler. Ich verstehe nicht, warum ich nicht einfach von Page 1 nach Page 0 kopieren kann. Im Anhang sind die aktuellen EEPROM files.
:
Bearbeitet durch User
Irgendwie kann Page 0 nicht transferiert werden. Sobald Page 0 voll ist, dann geht mit jedem Write Cycle der EEPROM Manager in die Routine EE_PageTransfer(), aber der Status bleibt immer PAGE_FULL.
1 | uint16_t EE_WriteVariable(uint16_t VirtAddress, uint16_t Data) |
2 | {
|
3 | uint16_t Status = 0; |
4 | |
5 | /* Write the variable virtual address and value in the EEPROM */
|
6 | Status = EE_VerifyPageFullWriteVariable(VirtAddress, Data); |
7 | |
8 | /* In case the EEPROM active page is full */
|
9 | if (Status == PAGE_FULL) |
10 | {
|
11 | /* Perform Page transfer */
|
12 | Status = EE_PageTransfer(VirtAddress, Data); |
13 | }
|
14 | |
15 | /* Return last operation status */
|
16 | return Status; |
17 | }
|
Nun kommt der also in EE_PageTransfer() und dort in folgendes:
1 | validpage = EE_FindValidPage(READ_FROM_VALID_PAGE); |
2 | |
3 | if (validpage == PAGE1) /* Page1 valid */ |
4 | {
|
5 | /* New page address where variable will be moved to */
|
6 | newpageaddress = PAGE0_BASE_ADDRESS; |
7 | |
8 | /* Old page ID where variable will be taken from */
|
9 | oldpageid = PAGE1_BASE_ADDRESS; |
10 | }
|
11 | else if (validpage == PAGE0) /* Page0 valid */ |
12 | {
|
13 | /* New page address where variable will be moved to */
|
14 | newpageaddress = PAGE1_BASE_ADDRESS; |
15 | |
16 | /* Old page ID where variable will be taken from */
|
17 | oldpageid = PAGE0_BASE_ADDRESS; |
18 | }
|
wobei er nun Page 1 als die Valid Page ansieht und nicht Page 0 und somit geht er in die erste if() rein. Ist das ein Fehler in der Library von STM32?
:
Bearbeitet durch User
Also wenn Du nur eine Lookup-Table schreiben willst, dann brauchst Du die "EEPROM-Emulation" eigentlich nicht, denn die ist dafür gemacht, dass Du einzelne Werte immer wieder ändern kannst, ohne dass jeweils immer eine ganze Page gelöscht/beschrieben werden muss. Aber Du musst ja nur die ganze Page löschen und kannst dann einmalig, Byte für Byte Deine Lookuptable reinschreiben und gut ist. Lesen kannst Du dann direkt mittels einem Pointer und brauchst den ganzen Kram von der EEPROM-Emulation auch nicht.
Johnny B. schrieb: > Also wenn Du nur eine Lookup-Table schreiben willst, dann brauchst Du > die "EEPROM-Emulation" eigentlich nicht, denn die ist dafür gemacht, > dass Du einzelne Werte immer wieder ändern kannst, ohne dass jeweils > immer eine ganze Page gelöscht/beschrieben werden muss. Die Look Up wird eben über eine Software angepasst, aber nur sehr selten. Daher wäre der virtuelle EEPROM ideal mit den wenigen Write Cycles. Johnny B. schrieb: > Aber Du musst ja nur die ganze Page löschen und kannst dann einmalig, > Byte für Byte Deine Lookuptable reinschreiben und gut ist. Lesen kannst > Du dann direkt mittels einem Pointer und brauchst den ganzen Kram von > der EEPROM-Emulation auch nicht. Im Speicher befinden sich noch etwa 64Byte andere Parameter, daher ist das nicht mehr so praktisch. Ich verstehe aber nicht, wieso das nicht hinhaut mit den Bibliotheken von STM32.
> Kann ich aber die Page auch grösser als die 2kByte wählen, > also z.B 16kByte? Nein, dafür sind die Routinen nicht ausgelegt. Darf ich frage, warum du eine Lookup-Tabelle in diese verquerte EEPROM-Nachbildung packen willst? So ne Tabelle ist doch normalerweise statisch und braucht den Pipapo gar nicht. Und falls sie doch mal alle Jubeljahre angepasst werden muß, schreib direkt ins Flash, ohne den Emulationslayer.
foobar schrieb: > Und falls sie doch mal alle > Jubeljahre angepasst werden muß, schreib direkt ins Flash, ohne den > Emulationslayer. Das könnte man schon, aber die Emulationslayer erlaubt natürlich wesentlich mehr Schreibzyklen bevor der EEPROM den Geist aufgibt. Mich hat aber auch der Ehrgeiz gepackt das Problem zu lösen :D. foobar schrieb: > Nein, dafür sind die Routinen nicht ausgelegt. Das wird wohl schon so sein, denn sobald Page 1 1kByte (2kByte mit Addressen inklusive) ist, wird erneut versucht die ganze Page zu transferieren. Ich schaue mal noch wo genau die Routinen angepasst werden müssen, dass werden ja wohl nur ein paar Defines sein.
:
Bearbeitet durch User
> die Emulationslayer erlaubt natürlich wesentlich mehr Schreibzyklen > bevor der EEPROM den Geist aufgibt. Nicht, wenn jedesmal die gesamte Tabelle überschrieben wird. Im Gegenteil, da die doppelte Menge an Daten geschrieben wird, geht die Lebensdauer runter. Dazu kommt, dass das Lesen über die Routinen schnarchlangsam ist - nicht gerade das, was man bei ner Lookup-Tabelle haben möchte. > Ich schaue mal noch wo genau die Routinen angepasst werden müssen, Ob sich das wirklich lohnt? Ich fand die Routinen qualitativ nicht gerade berauschend ...
foobar schrieb: > Nicht, wenn jedesmal die gesamte Tabelle überschrieben wird. Im > Gegenteil, da die doppelte Menge an Daten geschrieben wird, geht die > Lebensdauer runter. Dazu kommt, dass das Lesen über die Routinen > schnarchlangsam ist - nicht gerade das, was man bei ner Lookup-Tabelle > haben möchte. Du meinst wegen der Addresse für jede Variabel, die auch geschrieben wird? Das vielleicht schon, aber dafür werden immer andere Addressen beschrieben bis die Page voll ist und nicht immer die gleiche, denn die Lebensdauer ist ja direkt abhängig von der am meisten beschriebenen Addresse. Die LookUp wird sowiso am Anfang in den SRAM geladen, daher kein Problem bezüglich Speed. Mit 2kByte Page size klappt es übrigens prima mit dem Übertragen von einer Page in die nächste. Was ich nicht ganz verstehe ist folgende Funktion:
1 | static uint16_t EE_VerifyPageFullWriteVariable(uint16_t VirtAddress, uint16_t Data) |
2 | {
|
3 | HAL_StatusTypeDef flashstatus = HAL_OK; |
4 | uint16_t validpage = PAGE0; |
5 | uint32_t address = EEPROM_START_ADDRESS, pageendaddress = EEPROM_START_ADDRESS+PAGE_SIZE; |
6 | |
7 | /* Get valid Page for write operation */
|
8 | validpage = EE_FindValidPage(WRITE_IN_VALID_PAGE); |
9 | |
10 | /* Check if there is no valid page */
|
11 | if (validpage == NO_VALID_PAGE) |
12 | {
|
13 | return NO_VALID_PAGE; |
14 | }
|
15 | |
16 | /* Get the valid Page start address */
|
17 | address = (uint32_t)(EEPROM_START_ADDRESS + (uint32_t)(validpage * PAGE_SIZE)); |
18 | |
19 | /* Get the valid Page end address */
|
20 | pageendaddress = (uint32_t)((EEPROM_START_ADDRESS - 1) + (uint32_t)((validpage + 1) * PAGE_SIZE)); |
21 | |
22 | /* Check each active page address starting from begining */
|
23 | while (address < pageendaddress) |
24 | {
|
25 | /* Verify if address and address+2 contents are 0xFFFFFFFF */
|
26 | if ((*(__IO uint32_t*)address) == 0xFFFFFFFF) |
27 | {
|
28 | /* Set variable data */
|
29 | flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address, Data); |
30 | /* If program operation was failed, a Flash error code is returned */
|
31 | if (flashstatus != HAL_OK) |
32 | {
|
33 | return flashstatus; |
34 | }
|
35 | /* Set variable virtual address */
|
36 | flashstatus = HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address + 2, VirtAddress); |
37 | /* Return program operation status */
|
38 | return flashstatus; |
39 | }
|
40 | else
|
41 | {
|
42 | /* Next address location */
|
43 | address = address + 4; |
44 | }
|
45 | }
|
46 | |
47 | /* Return PAGE_FULL in case the valid page is full */
|
48 | return PAGE_FULL; |
49 | }
|
Was genau wird damit gemacht: (*(__IO uint32_t*)address) == 0xFFFFFFFF ? Die Adresse der Adresse verglichen? Dort scheint irgendwie der Fehler verborgen, denn nach 2kByte Page 1 ist die Voll und der Vergleich trifft nie mehr zu.
:
Bearbeitet durch User
> Was genau wird damit gemacht: (*(__IO uint32_t*)address) == 0xFFFFFFFF?
Die Routine sucht nen leeren Slot und schreibt da das neue
Adress/Daten-Tupel rein - wenn sie keinen freien Slot findet, gibt sie
PAGE_FULL zurück.
Der obige Ausdruck liest nen 32-Bit-Wert ab "address" und schaut, ob
alle Bits gesetzt sind (das Kennzeichen, dass dieser "Slot"
unbenutzt/frei ist).
foobar schrieb: > Die Routine sucht nen leeren Slot und schreibt da das neue > Adress/Daten-Tupel rein - wenn sie keinen freien Slot findet, gibt sie > PAGE_FULL zurück. Hmm ok, danke. Dann muss ich nur noch rausfinden, warum kein Slot mehr frei ist.
Bert S. schrieb: > Du meinst wegen der Addresse für jede Variabel, die auch geschrieben > wird? Das vielleicht schon, aber dafür werden immer andere Addressen > beschrieben bis die Page voll ist und nicht immer die gleiche, denn die > Lebensdauer ist ja direkt abhängig von der am meisten beschriebenen > Addresse. Nein, das ist falsch. Dein Feind ist der Löschvorgang und der kann nur komplette Pages löschen und nicht Werte an einzelnen Adressen. Das Gute an den STM32 ist, dass diese Pages relativ klein sind; also je nach Derivat meistens 1k oder 2k. Sprich, Du kannst nur eine komplette Page löschen (alle Bytes auf 0xff setzen), aber dann problemlos jederzeit (nach dem unlock) einzelne Bytes beschreiben. Wobei beim Beschreiben lediglich Bits von 1 auf 0 gesetzt werden können. Willst Du Bits von 0 auf 1 ändern, dann muss erst wieder die komplette Page gelöscht werden, womit alle Bits und Bytes in der Page auf 1 gesetzt werden.
Johnny B. schrieb: > Nein, das ist falsch. > Dein Feind ist der Löschvorgang und der kann nur komplette Pages löschen > und nicht Werte an einzelnen Adressen. Das Gute an den STM32 ist, dass > diese Pages relativ klein sind; also je nach Derivat meistens 1k oder > 2k. > Sprich, Du kannst nur eine komplette Page löschen (alle Bytes auf 0xff > setzen), aber dann problemlos jederzeit (nach dem unlock) einzelne Bytes > beschreiben. Wobei beim Beschreiben lediglich Bits von 1 auf 0 gesetzt > werden können. > Willst Du Bits von 0 auf 1 ändern, dann muss erst wieder die komplette > Page gelöscht werden, womit alle Bits und Bytes in der Page auf 1 > gesetzt werden. Ah ok, ja dann mach das auch sinn mit dem (*(__IO uint32_t*)address) == 0xFFFFFFFF
Bert S. schrieb: > Edit: Ok habe es hinbekommen, einfach die FLASH_PAGE_SIZE erhöht und nun > kann ich alles speicher wie gewollt. Ich würde mal annehmen, daß FLASH_PAGE_SIZE die per Hardware vorgegebene Pagegröße des Controllers ist. Die darfst Du sicher nicht einfach auf einen anderen Wert setzen! Du solltest wohl eher Deine logische PAGE_SIZE in eeprom.h als mehrfaches der FLASH_PAGE_SIZE definieren. Und dann muss natürlich z.B. beim Löschen der logischen Page berücksichtigt werden, daß diese aus mehreren Flash-Pages besteht.
:
Bearbeitet durch User
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.