Hallo! Ich suche ein einfaches Beispiel, wo Daten ins Flash gespeichert werden!? Ich arbeite mit dem STM32F103VDT6 und dem uVision von Keil. Unser Motor EC45 Flat 36V / 50W fährt einfach von A nach B mit einer Last von 180Kg an einem Schneckengetriebe. Bei der Ersten Fahrt wird der Weg gemessen. Dies soll bei Stromausfall erhalten bleiben. Leider habe ich noch nie mit dem Flash gearbeitet. Bin die Datenblätter am Durchlesen. Aber ein kleines Beispiel würde mir sicher sehr helfen. Auf der ST Site gibts eins, aber nicht zu diesem uP! Danke und Gruss! M.B.
Gast
#2748109
Erstmal musst du im Linker File eine neue Section anlegen, die du für die Nutzdaten verwendest ( ich denke eine Memory Page wird dafür locker reichen ). Die Variable wird in diese Section gepackt und kann auch schon problemlos gelesen werden. Um sie zu beschreiben, musst du 1) Flash unlocken 2) Die ganze Page löschen 3) Die Variable beschreiben 4) Flash wieder locken (für jeden diese Punkte gibt es im FLASH teil der Std Lib Funktionen) So hat es bei mir zumindest unter CooCox schonmal funktioniert.
Hallo AVerr! Danke für deine Hilfe! Ich habe jetzt ein Beispiel gefunden fürs EVAL Board MCBSTM32C. Ich besitze dieses Board. Ich schau mir auch die Lib an. Aber das mit den Sections habe ich noch nicht begriffen, wo/wie ich dies tun muss!? Danke und gruss! M.B.
Gast
#2748163
Da man den Flash nur seitenweise beschreiben kann, muss man eine komplette memory page für die Nutzdaten reservieren. Die Größe und Adresse der pages entnimmst du dem Reference Manual. In meinem Fall ( STM32F103C8 ) waren es 64 pages a 1K, ab 0x08000000. D.h. die letzte Page ( die ich für Daten benutze ) fängt bei 0x0800FC00 an. Das Linker Script besteht aus 2 Teilen ( meist in den Dateien memory.ld und/oder link.ld ... je nach Entwicklungsumgebung ): 1) MEMORY Definition:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Hier wird das vorhandene Memory festgelegt. rom ist in diesem Fall das restliche Flash ( Pages 1-63 ) und rom1 die letzte memory page, die für die Daten verwendet wird. 2) Section Definition:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
Hier wird eine Section namens .mydata definiert, sodass alle Variablen, welche in diese Section wandern im Memory Bereich rom1 landen. Zu guter letzt wird die Variable in die section .mydata gepackt:
1 | |
2 | |
Ich habe mein gefundenes Beispiel angehängt! Darun sehe ich niergends ein Hinweis, dass eine Section ausgewählt wurde! Ich bin kein Schnelldenker, das kapier ich noch nicht! bei uVision kann ich dies doch Target options --> Linker einstellen oder? Auch sehe ich im Beispiel nicht, welche Daten abgespeichert werden. Sorry und danke!
>Darun sehe ich niergends ein Hinweis, dass eine Section ausgewählt wurde!
Unbedigt brauchst du das nicht. Nur dann, wenn dein Programm annähhernd
das ganze Flash aufbraucht. Es ist nur wichtig, dass sich deine Flash
Daten nicht mit dem Programm überschneiden.Wenn du die Pages ganz am
Ende des Flash für deine Daten nutzt, passiert das sowieso nicht. Der
Linker bewirtschaftet (defaultmässig) das Flash von 0 an.
Grüsse
Wenn du den Flash mehr oder weniger als EEPROM Ersatz benutzen willst, schau dir auch mal die EEPROM Emulationsbeispiele bei ST in der Sotware Library an. Hab ich in meinen Motorkontroll Projekten auch schon erfolgreich benutzt. Schreiben des Flash geht natürlich nicht so oft wie ein richtiges EEPROM, du solltest also haushalten oder evtl. doch ein externes EEPROM in Betracht ziehen, wenn die Schreibvorgänge häufig stattfinden.
Gast
#2748530
ok, danke für den Tip! Ich hoffe ich kapier es bald :-) Das Ziel ist, dass einmal am Tag die Zurückgelegte Strecke abgespeichert wird und mittels Service -Kit per CAN ausgelesen werden kann. Also Ich muss immer das Flash unlocken, die page löschen, die Variable beschreiben, das flash locken. Der Linker setzt die Variable dann automatisch an nullter Stelle im Flash, so muss ich also auch nur die page 0 löschen? Gibt es eine Kontrollmöglichkeit, um sicher zu sein, dass es geklappt hat? Gewisse teilen ja den Flashbereich und speichern alles doppelt? Danke und Gruss!
Mit der o.a. EEPROM Emulation sieht das in der EEPROM Schreiberoutine dann so aus(aus einem PMSM Motorcontroller):
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
ErrValue kannst du noch untersuchen und bei <> 0 als Fehler auswerten.
Gast
#2748540
M. B. schrieb: > Der Linker setzt die Variable dann automatisch an nullter Stelle im > Flash, so muss ich also auch nur die page 0 löschen? Der Linker setzt sie nicht an Stelle 0, dort liegt der Einstiegspunkt in dein Hauptprogramm. Vom Löschen von Page 0 ist DRINGEND abzuraten. Es stimmt, man kann auch ohne Sections arbeiten, allerdings besteht dann halt die Gefahr, dass auf der Page, auf der man arbeitet, weitere Daten abgelegt werden. Aber wie Gebhard Raich (geb) gesagt hat, ist das eher unwahrscheinlich. Die saubere Lösung wäre natürlich, alles fein säuberlich in Sections aufzuteilen, damit nichts passieren kann. Für den Testbetrieb kann man das aber auch weglassen. > Gibt es eine Kontrollmöglichkeit, um sicher zu sein, dass es geklappt > hat? Naja, wenn es funktioniert, weisst du es ;) Du kannst dir die map-File ansehen, die der Compiler erstellt. Darin stehen die Adressen aller deiner Variablen nachdem der Linker sie verteilt hat. Als erstes solltest du rausfinden wie viele pages dein Controller hat und wie groß diese sind. Dann suchst du die Adresse der letzten page raus und probierst testweise, dort daten abzulegen und auszulesen. Wenn das klappt, kannst du dich immer noch um das Sectioning kümmern wenn du willst.
Schaue Dir auch den "Backup RAM" einmal näher an. Per Batterie kann man dort 42 Worte für 10 Jahre speichern. Der STM32F4xx hat sogar 4KB Backup-RAM und kann wie ein gewöhnlicher RAM genutzt werden. Wenn man die Batterie heraus nimmt, sind natürlich die Daten auch weg. Mit parallel 100µF kann man aber schon einige Sekunden für den Batteriewechsel überbrücken.
Gast
#2748554
Hier auch mal ein einfaches, aber funktionierendes Beispiel:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Hier wird die Seite beginnend bei 0x0800FC00 gelöscht und an der Stelle 0x0800FC00 werden 4 byte geschrieben ( der Inhalt der Variable data ). Man könnte nun mittels eines Zeigers darauf zugreifen:
1 | |
2 | |
3 | |
Morgen! Der STM32F103VDT6 hat im Block Main memory 256 Pages a 2Kbytes (0 - 255). Base Addresse 0x0807 F800 - 0x0807 FFFF.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
jetzt habe ich alle Daten, die ins Flash gehören in einn Struct gefasst.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
Ich muss jetzt aber alle Variablen einzeln ins flash laden und jede Variable kommt in eine neue Page, hab ich das richtig verstanden? Was hat es eigentlich mit dem Information Block auf sich. Ich benötige ja nur das Main Memory! Vielen Dank und Gruss! M.B.
Mit dem Debugger habe ich das Programm laufen gelassen. Und jetzt schaue ich im Memory an der Adresse 0x0807F800: Wert: 0B000000 Die Variable, die ich abgespeichert habe oder wollte hat den Wert 2!? Gruss!
Mein Fehler!! Die Variable hat den Wert 11. Also hat es geklappt!! So jetzt muss ich noch aus dem Flash lesen bzw. laden. Vielen Dank und freundliche Grüsse! M.B.
Gast
#2749057
M. B. schrieb: > jetzt habe ich alle Daten, die ins Flash gehören in einn Struct gefasst. > Ich muss jetzt aber alle Variablen einzeln ins flash laden und jede > Variable kommt in eine neue Page, hab ich das richtig verstanden? Ich habe es anders verstanden (FLASH_ErasePage z.B. habe ich im zip aber auch nicht gefunden). Statt FLASH_ProgramWord kann man ja bestimmt auch eine ganze page schreiben. Oder in einer Schleife ein word nach dem anderen. Wahrscheinlich gibt es auch eine Funktion, mit der man einen Block mit variabler Größe schreiben kann. Oder schreibt sich die, wie gerade beschrieben, mit einer Schleife selbst.
ja, das Beispiel im Zip gab nicht so viel her, habe die StandLib hinzugeführt. Da finde ich aber auch nur FLASH_ErasePage und kein anderer Löschbefehl. Zum Daten aus dem Flash laden, gibts da keinen Read Befehl? Danke und Gruss! M.B.
Gast
#2749077
Lutz schrieb: > Oder in einer Schleife ein word nach dem anderen. Genau so wird das gemacht. Dein Struct schreibst du Word für Word in diese eine Page, hast ja 2KB Platz. Ansonsten wäre das ja ein ziemlich großer Flashverbrauch. Die Lib hat nur Funktionen zum schreiben von Word und HalfWord.
Gast
#2749080
M. B. schrieb: > Zum Daten aus dem Flash laden, gibts da keinen Read > Befehl? Nein, weil es ja mittels Pointern ziemlich einfach ist ( siehe oben ). Wenn du eine Linker Section für die Variable hinbekommst, kannst du sie sogar ganz regulär lesen.
jetzt mal ne andere Frage: Im Datenblatt steht, dass der STM32F103VDT6 384kByte Flash zur Verfügung hat. Wenn ich die Pages 0 - 255 a 2kB zusammenzähle ergibt dies ja 512kB und das nur das Main Memory.? Was Stimmt jetzt? Vielen Dank für Eure Hilfe!
Gast
#2749111
Im Datenblatt steht wahrscheinlich "up to 255 Pages" ... Also hast du nur 192 Seiten a 2kB, was dann deine 384kB ergibt.
Ah Ok! Aber die Startadresse der Page stimmte trotzdem, sie ist einfach die Addresse der page 192!?
Gast
#2749141
Die Adresse 0x0807F800 wäre die Startadresse der page 255. Weil dein Controller aber nur 192 pages hat, ist die Adresse der letzten Seite 0x0805F800 ( = 0x08000000 + 191 * 2048 ).
Habe es im Datenblatt gefunden "up to..". Verstehe ich aber nicht, sorry! 2.3.3 Embedded Flash memory The high-performance Flash memory module has the following key features: ● For XL-density devices: density of up to 1 Mbyte with dual bank architecture for readwhile- write (RWW) capability: – bank 1: fixed size of 512 Kbytes – bank 2: up to 512 Kbytes ● For other devices: density of up to 512 Kbytes ● Memory organization: the Flash memory is organized as a main block and an information block: – Main memory block of size: up to 128 Kbytes × 64 bits divided into 512 pages of 2 Kbytes each (see Table 6) for XL-density devices up to 4 Kb × 64 bits divided into 32 pages of 1 Kbyte each for low-density devices (see Table 2) up to 16 Kb × 64 bits divided into 128 pages of 1 Kbyte each for medium-density devices (see Table 3) up to 64 Kb × 64 bits divided into 256 pages of 2 Kbytes each (see Table 4) for high-density devices up to 32 Kbit × 64 bits divided into 128 pages of 2 Kbytes each (see Table 5) for connectivity line devices Wenn ich mir diesen Ausschnitt aus dem Datenblatt ansehe, so würde ich doch annehmen, dass ich 256 Pages habe --> high-density device Liege ich da falsch oder lese ich das Datenblatt falsch? 192 Pages wäre schon logischer! danke für die Formel!
Gast
#2749190
Also, dein Controller ist laut Datenblatt aus der High-density performance line. Von dem gibt es mehrere Versionen, z.B. deine STM32F103VDT6 mit 384 kB Flash oder auch STM32F103VET6 mit 512 kB Flash ( nur das E ist hier in der Bezeichnung anders ). Nun könnten ST zu jeder dieser Versionen eine eigene Tabelle machen, das wäre aber zu viel Arbeit. Daher geht man im Reference Manual von der Vollbestückung ( in diesem Fall 512 kB ) aus, für alle anderen Modelle muss man ein wenig rechnen. In Abschnitt 3.3.3 vom Reference Manual steht:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
Also wieder das "up to". Da dies 512 kB Flash entsprechen würde, musst du halt deine 192 Pages a 2 kB selbst ausrechnen und kommst wie oben erklärt zur Adresse der letzten page. Die wichtigsten Informationen hier sind nur die page size und der Start ( 0x08000000 ). Den Rest kann man dann selbst berechnen.
Super danke, jetzt hats geklappt! Musste sicher sein, dass... >> Also, dein Controller ist laut Datenblatt aus der High-density >>performance line. ...ist, aber trotzdem nur 192 Pages hat. Vielen Dank für Deine Geduld und Hilfe! Gruss M.B.
Hallo
AVerr schrieb:
>Man könnte nun mittels eines Zeigers darauf zugreifen:1 | |
2 | |
3 | |
Ich habe jetzt einen struct ins flash gespeichert.
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
1 | |
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
Jetzt interessiert mich nur die Variable "cal_OK". Wie kann ich jetzt mittels Pointer auf die einzelne Variable im struct im Flash draufzeigen? Das habe ich noch nicht ganz geschnallt! Dein Beispiel oben greift doch auf die ganze Page des flash zu. oder? Danke und Gruss! M.B.
Ich glaube das Lesen geht ganz einfach...
1 | |
2 | |
3 | |
4 | |
5 | |
Vielen dank für die Hilfe! Mich interessiert eine einzelne Variable, kann ich auf eine einzelne Variable zugreifen?
Ah, nach dem Lesen kann ich normal auf einzelne Variablen zugreifen, super danke viel mal!! Grüsse M.B.
xxx = ((tSetup2*)FLSHBSEADRPG192)->cal_OK;
Diese Berechnung: > int x = (sizeof(tSetup2) / sizeof(int)); und diese Schleife > for(i=0;i<x;i++) > { > FLASH_ProgramWord(FLSHBSEADRPG192, pData[i]); > } können funktionieren. Zwischen dem BOOL und dem ersten int ist vermutlich ein Loch von 3 Byte. Wenn dies auf eine andere Architektur portiert würde oder jemand im Makefile global -fpack-struct einstellt oder dem struct ein _attribute_ ((packed)) hinzufügt, dann fliegt es Dir vermutlich um die Ohren. Eine korrekte Serialisierung im Sinne eines definierten "byte streams" ist das nicht.
Es funktioniert nicht immer die erste Variable BOOl erfasst er fast immer, die restlichen bytes sind immer null: 0x0805F800: 01 00 00 00 FF FF FF FF FF FF FF FF ect. Obwohl die Variablen im Struct Setup2 mit Werten gefüllt wurden. Was könnte das jetzt sein. Roland H. schrieb > Eine korrekte Serialisierung im Sinne eines definierten "byte streams" >ist das nicht.
Gast
#2750585
M. B. schrieb: > void set_in_Flash(tSetup2 *setup) > { > > uint32_t *pData = (uint32_t *)setup; > uint8_t i; > int x = (sizeof(tSetup2) / sizeof(int)); > > FLASH_Unlock(); > FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR); > FLASH_ErasePage(FLSHBSEADRPG192); > > for(i=0;i<x;i++) > { > FLASH_ProgramWord(FLSHBSEADRPG192, pData[i]); > } > FLASH_Lock(); > > } Kein wunder, du schreibst alle deine Daten an die selbe Adresse.
1 | |
Gast
#2751959
AVerr schrieb: > Kein wunder, du schreibst alle deine Daten an die selbe Adresse. > FLASH_ProgramWord(FLSHBSEADRPG192 + i*sizeof(uint32_t), pData[i]); ^^^^ Sicher? Frage: Versuchst du mit pData[i] auf ein struct-member zuzugreifen?
Gast
#2751986
Etwas Ordnung bzw. Weitblick sollte dazu führen, daß du eine globale volatil-Variable (man weiß ja nie, was noch dazukommt oder wo man es noch nutzt) einführst, die dir die nächste freie Speicherstelle in deiner section anzeigt. Sinnvollerweise muß die natürlich selbst in die section deines Flash gelegt werden, um auch nach einem reset noch ihre Funktion erfüllen zu können; so quasi als Inhaltsverzeichnishilfe. Da fällt einem bei Nachdenken sicher noch etwas mehr sinnvolle Struktur für diese section ein ... Roland H. schrieb: > Zwischen dem BOOL und dem ersten int ist vermutlich ein Loch von 3 Byte. Wenn BOOL hier als uint8_t definiert ist, ja. Also sollte man ... oder ... .
Hi Leute, ich beschäftige mich momentan mit exakt dem gleichen Problem, benutze aber einen stm32f205vg und muss ca. 1kb Daten speichern. Hardware ist vorgegeben, einen eeprom kann ich also nicht hinzufügen. Meine Frage dreht sich um die Aufteilung des Flashspeichers: 4x16kb 1x64kb 7x128kb Wenn ich die erste Page verwende würde (afaik) der Startpointer in meinen Speicherbereich zeigen anstatt auf den Startupcode. Die letzte Page will ich nicht nehmen da mein Code ziemlich viel Platz des Flashs belegen wird und mir 128kb Platz für 1kb Daten einfach zu schade ist. Am liebsten wäre es mir wenn ich dem Linker mitteilen könnte dass er die zweite Section für die Daten nutzen soll und den Code darum herum platziert. Leider habe ich keinen Ansatz wie ich dafür das Linkerfile modifizieren muss. Als Linkerfile verwende ich aktuell das File für das Atollic True Studio das in der StdPeriphLib von ST (http://www.st.com/web/en/catalog/tools/PF257898) enthalten ist. Vielen Dank für eure Hilfe im Voraus, viele Grüße Alex
Gast
#3172022
Was du brauchst, ist die definierte Pageadresse(n). Ich würde immer das Ende vom Flash dafür nutzen.
Hi, wie ich die letzte Page des Flashspeichers nutzen kann ist mir klar, mein Problem ist jedoch dass die letzte Page mit 128kB für mein 1kB Daten überdimensioniert ist, vor allem in Anbetracht des doch recht umfangreichen Codes der noch mit auf den Flash muss. Deshalb würde ich gerne eine der kleinsten Pages verwenden, bevorzugt eine der ersten mit 16kB. Nur wie bringe ich dem Linker bei dass er für den Programmcode z.B. Page 1-3&5-12 benutzen soll, also im Prinzip um meine gespeicherten Daten herum mappt? Danke für die Antwort im Voraus, viele Grüße Alex
Gast
#3172696
Eine Page ist je nach Device entweder 1KByte oder 2KByte groß. Dem linker musst du nicht beibringen, sondern "nur" in deinem Programmcode auf die gewünschte Page zugreifen. So in der Art:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
Also recht simpel.
Gast
#3172698
Ach ja und beim Download "Erase affected" Option verwenden, so wird beim Programmieren nur der beschriebene Bereich des uC's gelöscht.
Das Problem ist wie beschrieben dass ich glaube das der stm32f205 eben keine pagesize von 1-2kB besitzt, sondern die riesigen 128kB im Falle des letzten "Sector" (Terminologie im Datenblatt, denke aber das damit Pages gemeint sind). In dem Falle kann ich nicht die letzte Page verwenden sondern muss eine aus der Mitte herausgreifen und weis nicht wie ich dem Linker das bei bringen soll. Liege ich mit meiner Interpretation richtig? http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/CD00225773.pdf Seite 53 Vielen Dank für die Antworten im Voraus, viele Grüße Alex
Gast
#3328319
Ich hänge mich mal hier an. Das folgende:
1 | |
2 | |
3 | |
funktioniert beim STM32F4 NICHT. Ich bekomme dort völlig irrationale Werte. Gibt es bei der F4 Serie eigene Lesebefehle von ST?
Gast
#3328508
Ich habe so etwas ähnliches bereits realisiert, da mir das EEPROM Emulation Beispiel von ST nicht wirklich gefallen hat. Ich teile es gerne. Eine Beschreibung ist nicht dabei und ist nicht ausgiebig auf Bugs getestet. Gespeichert wird ein Byte/Word im Flash, um die Überschreibzyklen zu reduzieren, also bei einer Page von 1024 Byte stehen 512 Bytes zu Verfügung.
Gast
#3343656
Das kann doch nicht funktionieren. Woher weiss der Compiler denn, dass ich mit "0x0800FC00" eine Adresse meine? Gibt es keine Spezielle Lesefunktion beim STM32F4? Page und solche Dinge gibt es beim F4 nicht.
Das Ganze habe ich für ein Firmware-Update auf dem F103 schonmal gebraucht, sollte auf dem F4xx aber genauso funktionieren: Falls du mit dem ARM GCC arbeitest, kannst du im C-Code Variablen in Sektionen mappen: Beispiel:
1 | |
2 | |
Damit findet der Linker später die Variable in der entsprechenden "Sektion". Jetzt musst du dem Linker nur noch klar machen, wo die Sektion liegen soll. Das geht im Memory Mapping / Linker-File:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | |
34 | |
Problematisch wird es aber, .text in zwei Sektionen zu teilen. Ich hatte alles was vor 0x1000 war in extra Sektionen gepackt und .text erst ab 0x1110 anfangen lassen.
Gast
#3343929
Ich will aber nicht die Variablen in so eine selbst definiert Sektion schreiben, sondern aus beliegen Speicherstellen lesen können, um Z.B zeigen zu können, dass mein Flashvorgang geklappt hat. Und um Linkerfile schreibt die Keil IDE schon herum. Vielleicht kann ich da in den Einstellungen etwas übergeben. Ok, mal sehen...
@Phantomix: Vielen Dank für Deinen Post, Du bringst die Lösung für den GCC auf den Punkt. Mit einem entsprechenden Linkerscript bekommt man eine EEPROM-Emulation auf dem F4 sauber mit jeder beliebigen Codegröße hin: sector0 (rx) : ORIGIN = 0x08000000, LENGTH = 0x00004000 feeprom (rx) : ORIGIN = 0x08004000, LENGTH = 0x00008000 rom (rx) : ORIGIN = 0x0800C000, LENGTH = 0x00074000 sector0 enthält nur die Vektoren. feeprom enthält Flashseiten 1 und 2. Rom enthält alle anderen Festwerte und liegt in den großen Flashpages. Mit diesem Setup kann man mit nur knapp 3x16kB ein EEPROM emulieren. Ist bei den F4 meist kein Beinbruch und spart das externe EEPROM.
Gast
#3591264
Hallo zusammen,
ich beschäftige mich momentan auch damit, Daten während der Laufzeit in
den Flash-Speicher zu schreiben.
Ich verwende einen STM32F429 mit der Entwicklungsumgebung µVision und
dem Compiler von Keil.
Ich schreibe Daten aus einem Array ab einer bestimmten Adresse im
Flash-Speicher.
Ich schreibe die Daten dazu Wort für Wort in den Speicher ohne vorher
den Speicherbereich zu löschen.
Er beschreibt auch die gewünschten Adressen allerdings sind die Daten im
Flash verändert gegenüber den Werten im Array.
Beispielsweise soll 0xC8 geschrieben werden und im Flash-Speicher steht
0xC0 oder 0x48 oder statt eines Wertes 0x1AC2 (Array) steht 0x1A82 im
Flash-Speicher. Also irgendwie scheinen die Werte leicht verändert zu
sein.
Folgender Code verwende ich zum Schreiben der Daten:
/* Enable the flash control register access */
FLASH_Unlock();
/* Calculate the end address */
u32l_start_address = u32param_start_adr;
u32l_end_address = u32param_start_adr + u32param_length;
/*Check if the start-address is valid */
if (u32l_start_address >= ADDR_FLASH_START)
{
/*Check if the end-address is valid */
if (u32l_end_address <= ADDR_FLASH_END)
{
/* Program the user Flash area word by word */
while (u32l_start_address < u32l_end_address)
{ /* Write data to flash */
if (FLASH_ProgramWord(u32l_start_address, *u32param_data) ==
FLASH_COMPLETE)
{ /* Increment address to write */
u32l_start_address = u32l_start_address + 4;
/* Increment the address of the data field to save */
u32param_data++;
}
else
{
/* Error occurred while writing data in Flash memory, set error
*/
u32l_error_code = ERR_WRITING_FLASH;
}
}
}
else
{
/* Illegal end-address, set error*/
u32l_error_code = ERR_END_ADR_FLASH;
}
}
else
{
/* Illegal start-address, set error*/
u32l_error_code = ERR_START_ADR_FLASH;
}
/* Lock the Flash to disable the flash control register access
(recommended
to protect the FLASH memory against possible unwanted operation) */
FLASH_Lock();
Also das Schreiben auf die Adressen klappt, und die Adressen stimmen
auch, lediglich stimmt der Inhalt nicht.
Ich würde mich über alle Hilfen freuen.
Grüße vom Flasher
Hallo, Daten in ein nicht gelöschtes Flash schreiben ist wie auf eine schon bemalte Tafel zu malen - man kann immer nur weiss hinzufügen, nie jedoch schwarz und das dabei herauskommende Bild sieht nicht so aus wie man es sich vorstellt. Flash kann nur mit "0"en beschrieben werden. Das Löschen vorher sorgt dafür, dass nur noch "1"en im Flash stehen (die mit "0"en überschrieben werden können) und keine "0"en (die nicht mit "1"en überschrieben werden können). Schreibst Du z.B. Deine C8 in eine Zelle, in der vorher schon F7 stand, wirst Du eine C0 zurücklesen. Also: Flash vor dem neubeschreiben immer löschen. Schöne Grüße, Martin
Gast
#3591442
Hallo Martin, vielen Dank für deine Antwort, sowas habe ich mir schon gedacht, allerdings ist es blöd einen ganzen Sektor zu löschen, ich würde gerne nur Teile eines Sektors löschen. Doch in der Standardbiblithek habe ich noch keine derartige Funktion gefunden. Den gewünschten Speicherbereich mit Nullen zu beschreiben wird nicht gehen oder? Oder gibt es eine Möglichkeit einen Speicherbereich von z.B. 100Bytes zu löschen? Grüße der Flasher
Gast
#3591464
Flasher schrieb: > Oder gibt es eine Möglichkeit einen Speicherbereich von z.B. 100Bytes > zu löschen? Nein, nur ganze Pages sind möglich! Warum stört Dich das Löschen??
Gast
#3591470
Hi Flasher, Du kannst problemlos jeden "gewünschten Speicherbereich mit Nullen zu beschreiben". Weiterführende Tipps, z.B. wie man auch wieder 1en in die Sektoren bekommt, findest Du in den Handbüchern (RM0090 oder auch in AN3969). Grüße, RoyalFlush
Gast
#3591481
Hallo Sepp, die Pages sind 128kByte groß (zumindest die im oberen Speicherbereich) ich verwende aber für verschiedene Daten verschiedene Bereiche (Konfigurationsdaten, Fehler, Logging-Daten und Zeitdaten, etc.) wenn ich jetzt in einen Sektor mehrere Daten ablegen will, will ich davor ja nicht alle Daten wieder löschen. Und so viele Datenarten und Code wie ich verwende, gibts nun mal nicht genügend Sektoren. Natürlich kann ich kleinere Sektoren verwenden, aber die kleinsten haben nun mal auch min. 16kByte. Oder gibt es noch ne andere Lösung für meine Daten? Grüße der Flasher
Hallo, Du musst den Flash nicht löschen, um Daten hineinzuschreiben, Du musst ihn nur löschen, bevor Du Daten überschreibst. Auf diese Weise funktioniert die EEProm-Emulation, die man z.B. in App-Note AN2594 unter http://www.st.com/st-web-ui/static/active/en/resource/technical/document/application_note/CD00165693.pdf findet. Mit dieser Methode können viele Variablen in eine Flash-Page gelegt und auch überschrieben werden, wobei es nur bei jedem x-ten Schreibzugriff zu einem Flash-Erase kommt. Wenn Du zusätzlich diese Emulation an den Anfang des Flash legst, verschwendest Du auch nicht viel Speicher, da hier die Pages entsprechend kleiner sind, wie Du schon festgestellt hast. Minimum sind 2 Pages für 1 bis 8000 (16-Bit-)Variablen. Schöne Grüße, Martin
Gast
#3592392
Hallo Martin, also soweit alles verstanden, was die Speicherung betrifft. Jetzt habe ich nur folgendes Problem: Ich möchte die kleinsten Sektoren des Flash-Speichers benutzen (Sektor0 bis Sektor3 mit jeweils 16kB und Sektor4 mit 64KB) Das Programm beginnt momentan bei 0x08000000, jetzt habe ich in der µVision-Umgebung den Beginn des Programms auf 0x08020000 verschoben, die Länge angepasst im Programm habe ich das Headerfile angepasst, in dem beispielsweise Definitionen zum Flash-Speicher-Start und zum Ort der Vektortabelle angegeben sind ebenfalls auf die neue Adresse des Programmcodes angepasst. Aber jetzt läuft mein Programm gar nicht mehr, wenn ich es wieder zurückstelle geht es wieder. Was muss ich beachten um mein Programm (meine Interrupt-Vektortabelle) im Speicher nach hinten in den ersten 128kB-Sektor zu schieben? Hab ich noch was vergessen, oder geht es ganz anders? Grüße der Flasher
Hallo, die Vektor-Tabelle muss immer am Anfang liegen (im Sektor 0), Sektor 1 und 2 werden dann EEProm-Emulation und ab 3 darf dann der Programmcode beginnen. Um diese Aufteilung zu bekommen muss man das Linker-Script wie weiter oben in diesem Thread (Post von Marcus H) oder wie unter https://my.st.com/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=%2Fpublic%2FSTe2ecommunities%2Fmcu%2FLists%2Fcortex%5Fmx%5Fstm32%2FHow%20to%20allocate%20variable%20in%20Flash%20to%20desired%20address&FolderCTID=0x01200200770978C69A1141439FE559EB459D7580009C4E14902C3CDE46A77F0FFD06506F5B¤tviews=3878 beschrieben anpassen (dabei aber natürlich Platz für 2 EEProm-Pages einplanen). Schöne Grüße, Martin Edith sagt: Hinweis auf 2 Pages hinzugefügt
> die Vektor-Tabelle muss immer am Anfang liegen (im Sektor 0)
Nicht zwingend, man kann jede beliebige Speicherposition für die Tabelle
benutzen, wichtig ist, dass am Anfang des Flashes steht:
0x08000000 Stack-Size
0x08000004 Reset-Vector
Auf die Weise kann man sich bspw einen eigenen Bootloader bauen, und die
Ziel-Anwendung bringt ihre Vectortabelle selbst mit.
Gast
#3715340
Hallo zusammen, wenn Daten überschrieben werden sollen, die z.B. in der Mitte einer Page liegen, davor befindliche Daten aber erhalten bleiben sollen, müssen dann alle zu erhaltenden Daten zunächst zwischengespeichert werden und nach dem Erase wieder geschrieben werden? Grüßle
Yep, das ist der Haken an Flash.
Gast
#3715420
Hm... ich war "ideelich" auf dem Weg da eine Art FAT System anzulegen ähnlich wie bei SD Karten, aber da rappelt man sich ja nen Ast mit den Lösch und Schreibzugriffen... Ich tausche die letzten 8 Pages meine Flashes gegen 16kiB internes EEPROM - jemand interessiert^^
Jasson schrieb: > Ich tausche die letzten 8 Pages meine Flashes gegen 16kiB internes > EEPROM - jemand interessiert^^ Wenn dir das alles zu heikel ist, nimm doch einen externen EEPROM wie z.B. den 24C128 mit 16kB oder den 24C256 mit 32kB. Die halten auch mehr Schreibzyklen aus und sind bei Bedarf leicht auszutauschen - oder eben wirklich eine SD Karte.
Gast
#4149590
Sorry für's Ausgraben dieses alten Beitrags, aber es passt hier genau dazu, es geht um den Ausschnitt aus dem Linkerscript oben:
1 | |
2 | |
3 | |
Gibt es eine Möglichkeit eine eigene Section zu definieren, die Mitten in einer anderen liegt, so dass die andere Section sich drumherumlegt? Gemeint ist das so:
1 | |
2 | |
3 | |
Sinn ist dass ich ein paar Variablen an eine feste Adresse im Hexfile bekomme, so dass ich "von außen" (etwa in einem Firmwareupdatetool) z.B. die Version aus der Datei lesen kann. Wennn man rom1 ans Ende legt, hat man immer eine bin-Datei die so groß wie das Flash ist und zwischen der Applikation und dem rom1 Bereich ist alles leer. Stefan
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.