Guten Tag!
Ich arbeite mit dem STM32F103VDT6 und dem uVision von Keil.
Nach einer Lernfahrt möchte ich zwei Arrays mit je 2100 Speicherstellen
ins Flash ablegen.
1 | tMotorCurrentSample MotI_TableCW[TRAV_MAXDIST_SAMPLES];
| 2 | tMotorCurrentSample MotI_TableCCW[TRAV_MAXDIST_SAMPLES];
|
sind in einem Struct verpackt, ich denke die müsste ich aus dem Struct
nehmen!? 1 | typedef struct {
| 2 | float motspd_max;
| 3 | float motspd_cal_max;
| 4 | float motspd_inc;
| 5 | float motspd_dec;
| 6 |
| 7 | tMotorCurrentSample MotI_TableCW[TRAV_MAXDIST_SAMPLES];
| 8 | tMotorCurrentSample MotI_TableCCW[TRAV_MAXDIST_SAMPLES];
| 9 | int MotDistCntVal;
| 10 | float MotDistCal_pmm;
| 11 | tPIDparameter PIDpar;
| 12 | }
| 13 | tSetup;
|
Ins Flash speichern habe ich auch schon gemacht. Jedoch nur Pageweise.
Ich kann mir einfach nicht vorstellen, wie man pageübergreifend ins
Flash speichert!?
Bis Jetzt: 1 | void set_in_Flash(tSetup2 *setup)
| 2 | {
| 3 |
| 4 | uint32_t *pData = (uint32_t *)setup;
| 5 | uint8_t i;
| 6 | int x = (sizeof(tSetup2) / sizeof(int));
| 7 |
| 8 |
| 9 | FLASH_Unlock();
| 10 | FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
| 11 | FLASH_ErasePage(FLSHBSEADRPG192);
| 12 |
| 13 | for(i=0;i<x;i++)
| 14 | {
| 15 | FLASH_ProgramWord(FLSHBSEADRPG192 + i*sizeof(uint32_t), pData[i]);
| 16 | }
| 17 | FLASH_Lock();
| 18 | }
|
Kann mir jemand einen Anhaltspunkt geben? Wie schaffe ich es, dass die
Tabelle (Array) auf zwei Pages aufgeteilt ist!?
Vielen Dank und freundliche Grüsse
M.B.
Wieso berechnest du x durch:
1 | int x = (sizeof(tSetup2) / sizeof(int));
|
sollte es nicht eher wie folgt sein, wenn du 32bit-Daten auf den Flash
schreibst?:
1 | int x = (sizeof(tSetup2) / sizeof(uint32_t));
|
Außerdem kann es dir dabei passieren, dass bei der Anzahl ein Rest
bleibt, x sollte also ggf. aufgerundet werden, z.B.:
1 | if ((sizeof(tSetup2) % sizeof(uint32_t) != 0) x++;
|
In dem Fall solltest du dir aber sinnvoll überlegen womit du das letzte
Datenwort befüllst, oder du stellst beim auslesen sicher, dass das
letzte Datenwort nur zum Teil in deine Variable vom Typ tSetup2
geschrieben wird.
Ansonsten muss ich dir ehrlich sagen, habe ich keine Ahnung was du mit
"Tabelle auf 2 Pages schreiben" meinst, mit dem von dir obig
beschriebenen Verfahren schreibst du doch bereits alle Bytes deiner
Variable setup in den Flash, wieso sollen es genau 2 Pages sein?
Um zu wissen ob das überhaupt geht sollten wir schon wissen wie viele
Byte tMotorCurrentSample benötigt und wie groß TRAV_MAXDIST_SAMPLES ist.
Hallo Michael
1 | TRAV_MAXDIST_SAMPLES = 2100
| 2 | typedef uint16_t tMotorCurrentSample;
| 3 |
| 4 | typedef struct {
| 5 | float motspd_max;
| 6 | float motspd_cal_max;
| 7 | float motspd_inc;
| 8 | float motspd_dec;
| 9 |
| 10 | tMotorCurrentSample MotI_TableCW[TRAV_MAXDIST_SAMPLES];
| 11 | tMotorCurrentSample MotI_TableCCW[TRAV_MAXDIST_SAMPLES];
| 12 |
| 13 | int MotDistCntVal;
| 14 | float MotDistCal_pmm;
| 15 | tPIDparameter PIDpar;
| 16 | }
| 17 | tSetup;
|
Der Struct, der ich bis jetzt ins Flash speichere ist nicht grösser als
2kB also nicht grösser als eine Page.
Die Arrays, die im oben aufgelisteten Struct liegen, sind jetzt grösser
als eine Page, 2100 * 2 Byte = 4.2 kB
Ich habs kompliziert beschrieben, aber ich muss einfach eine
Wertetabelle (Array[2100]) ins Flash legen, die grösser ist als eine
einzelne Page.
Gruss und Danke!
M.B.
Darf ich mal fragen, wo du den Registerwert FLSHBSEADRPG192 her hast?
Ich kann den gerade nicht definiert finden.
Ansonsten würde ich spontan vermuten, dass die nächste Page bei
FLSHBSEADRPG192 + 2048 anfängt und wenn du über 2048 Byte schreibst, du
mit deiner Implementierung sowieso dann auf der nächsten Page landest.
Oder hast du im Flash nach der Page 192 keine mehr die ungenutzt sind?
Tut mir leid, falls ich es jetzt vielleicht komplizierter mache als
nötig, aber ich verstehe offenbar noch nicht ganz wo das Problem liegt.
1 | // ==== Flash Page Adresses =====
| 2 | #define FLSHBSEADRPG192 0x0805F800
|
Ich habe ein Struct der nicht grösser ist als eine Page des Flash und
speichere diesen in die letzte Page mit der Adresse FLSHBSEADRPG192.
Struct: 1 | typedef struct {
| 2 |
| 3 | uint8_t CntCal;
| 4 | int ShttrueIdx[CNTSHT];
| 5 | int Nmbr_of_Shttr;
| 6 | uint8_t Nmbr_of_Shttr_part;
| 7 | int MotDir;
| 8 | int MotDistCal_PulsesMax;
| 9 | int MotDistShttrPoints[6];
| 10 | BOOL cal_OK;
| 11 | }
| 12 | tSetup2;
|
Jetzt habe ich einen weiteren Struct, der ich ins Flash speicheren
möchte, z.B. in die Page 186.
Struct: 1 | typedef struct {
| 2 | float motspd_max; // 4 Byte
| 3 | float motspd_cal_max; // 4 Byte
| 4 | float motspd_inc; // 4 Byte
| 5 | float motspd_dec; // 4 Byte
| 6 |
| 7 | tMotorCurrentSample MotI_TableCW[TRAV_MAXDIST_SAMPLES]; // 4200 Byte
| 8 | tMotorCurrentSample MotI_TableCCW[TRAV_MAXDIST_SAMPLES]; //4200 Byte
| 9 |
| 10 | int MotDistCntVal; // 4 Byte
| 11 | float MotDistCal_pmm; // 4 Byte
| 12 | tPIDparameter PIDpar; // 5 * 4 Byte = 20 Byte
| 13 | }
| 14 | tSetup;
|
Dieser Struct ist aber wesentlich grösser (8444 Byte). Eine Page ist
2000 Byte gross. Also benötigt dieser Struct doch 5 Pages!?
Bis jetzt habe ich aber noch nie einen Struct ins Flash gespeichert, der
grösser war als eine Page des Flashs.
Vielleicht ist ja meine Frage zu einfach für Dich, Michael B. :-) 1 | void set_in_Flash(tSetup2 *setup)
| 2 | {
| 3 |
| 4 | uint32_t *pData = (uint32_t *)setup;
| 5 | uint8_t i;
| 6 | int x = (sizeof(tSetup2) / sizeof(int));
| 7 |
| 8 |
| 9 | FLASH_Unlock();
| 10 | FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
| 11 | FLASH_ErasePage(FLSHBSEADRPG192); // Hier lösche ich ja die Page vor dem Beschreiben
| 12 |
| 13 | for(i=0;i<x;i++)
| 14 | {
| 15 | FLASH_ProgramWord(FLSHBSEADRPG192 + i*sizeof(uint32_t), pData[i]);
| 16 | }
| 17 | FLASH_Lock();
| 18 | }
|
Ich könnte auf einmal alle Pages löschen, in die ich schreiben möchte??
1 | void set_in_Flash(tSetup *setup)
| 2 | {
| 3 |
| 4 | uint32_t *pData = (uint32_t *)setup;
| 5 | uint8_t i;
| 6 | int x = (sizeof(tSetup2) / sizeof(int));
| 7 |
| 8 |
| 9 | FLASH_Unlock();
| 10 | FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
| 11 | FLASH_ErasePage(FLSHBSEADRPG186);
| 12 | FLASH_ErasePage(FLSHBSEADRPG187);
| 13 | FLASH_ErasePage(FLSHBSEADRPG188);
| 14 | FLASH_ErasePage(FLSHBSEADRPG189);
| 15 | FLASH_ErasePage(FLSHBSEADRPG190);
| 16 |
| 17 | for(i=0;i<x;i++)
| 18 | {
| 19 | FLASH_ProgramWord(FLSHBSEADRPG192 + i*sizeof(uint32_t), pData[i]);
| 20 | }
| 21 | FLASH_Lock();
| 22 | }
|
Ah ok, jetzt verstehe ich.
Also wenn du keine Folge von Pages zur Verfügung hast auf denen Daten
frei sind, kann ich dir nur empfehlen etwas zu machen wie:
1 | #define PAGESIZE 2048
| 2 | for(i=0;i<x;i++)
| 3 | {
| 4 | uint32_t adrs;
| 5 | switch (x / PAGESIZE)
| 6 | {
| 7 | case 0:
| 8 | adrs = FLSHBSEADRPG192 + i*sizeof(uint32_t);
| 9 | break;
| 10 | case 1:
| 11 | adrs = FLSHBSEADRPG186 + (i - 1 * PAGESIZE)*sizeof(uint32_t)
| 12 | break;
| 13 | case 2:
| 14 | adrs = FLSHBSEADRPG187 + (i - 2 * PAGESIZE)*sizeof(uint32_t)
| 15 | break;
| 16 |
| 17 | ...
| 18 | }
| 19 | FLASH_ProgramWord(adrs, pData[i]);
| 20 | }
|
Also indem du dir eine Liste (ggf. etwas intelligenter als Array o.ä.)
von freien Pages definierst und die dann geeignet auswählst.
Beim Auslesen aus dem Flash und beschreiben in deine Variable vom Typ
struct solltest du dann natürlich ebenfalls Stückchenweise vorgehen.
Ich hoffe das Hilft dir und ich stehe nicht immer noch auf em Schlauch.
Also alle auf einmal löschen wird wohl nichts, gibt zwar ein
FLASH_EraseAllPages() - aber das kann auch Pages löschen die du nicht
löschen willst.
Würde dabei bleiben ein Array von programmierbaren Pages zu definieren
und dann kannst du ja erst das ganze Array abarbeiten und immer die Page
löschen und im Anschluss beschreibst du die und nimmst die Adressen zum
schreiben wiederum aus dem Array.
EDIT:
Für das auslesen aus dem Flash wäre es natürlich günstig bei einer Seite
zu beginnen und nur die folgenden n Pages zu beschreiben, am besten
aufeinanderfolgend, dann lässt sich das leichter auslesen weil die
Registeradressen einfach folgend sind.
Eine Meldung wie: "war doch ganz anders" oder "hab es jetzt hinbekommen
indem ich ...", oder "ich probiere jetzt noch mal ..." wäre gut, sonst
machen wir uns nämlich weiter Gedanken wie wir dir helfen können.
Hallo!
Bin leider erst jetzt wieder dazu gekommen, um an diesem Projekt zu
arbeiten. Ich bin mir nicht sicher, ob wir das selbe Problem behandeln!?
Ich weiss, dass die Pages 186 - 190 mir zur Verfügung stehen um den
Struct, der 8444 Bytes gross ist, darin abzuspeichern. Die Pages liegen
also nacheinander. Ich weiss jetzt aber nicht wie ich den Struct so
ablegen kann, dass automatisch, nach dem die Page 186 voll ist auf die
Page 187 zugegriffen wird. Ich werde Deinen Vorschlag mal ausprobieren.
Aber da die Pages aneinander liegen benötige ich keine Liste mit
verfügbaren Pages!?
So wies ausschaut hats nicht geklappt....
1 | void set_in_Flash1(tSetup *setup)
| 2 | {
| 3 | #define PAGESIZE 2048
| 4 |
| 5 | uint32_t *pData = (uint32_t *)setup;
| 6 | int i, y;
| 7 | int x = (sizeof(tSetup) / sizeof(int));
| 8 |
| 9 | FLASH_Unlock();
| 10 | FLASH_ClearFlag(FLASH_FLAG_BSY | FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
| 11 |
| 12 | for(i = 0; i < x ; i++)
| 13 | {
| 14 | uint32_t adrs;
| 15 |
| 16 | switch(x / PAGESIZE)
| 17 | {
| 18 | case 0: adrs = FLSHBSEADRPG186 + i * sizeof(uint32_t);
| 19 | break;
| 20 |
| 21 | case 1: adrs = FLSHBSEADRPG187 + (i - 1 * PAGESIZE) * sizeof(uint32_t);
| 22 | break;
| 23 |
| 24 | case 2: adrs = FLSHBSEADRPG188 + (i - 2 * PAGESIZE) * sizeof(uint32_t);
| 25 | break;
| 26 |
| 27 | case 3: adrs = FLSHBSEADRPG189 + (i - 3 * PAGESIZE) * sizeof(uint32_t);
| 28 | break;
| 29 |
| 30 | case 4: adrs = FLSHBSEADRPG190 + (i - 4 * PAGESIZE) * sizeof(uint32_t);
| 31 | break;
| 32 | }
| 33 |
| 34 | FLASH_ErasePage(adrs);
| 35 | FLASH_ProgramWord(adrs, pData[i]);
| 36 | }
| 37 | FLASH_Lock();
| 38 | }
|
Wenn ich im Memory schaue hat er nicht gar nichts geschrieben, aber die
Werte, die ins Flash geschrieben wurden können nicht stimmen.
Ich frage mich auch, ob ich den erasePage am falschen ort platziert
habe.
Danke und Gruss
Das ErasePage ist def. am falschen ort. So fliegt mir ja das Flash bald
um die Ohren...
Ja, wenn du die Page nach dem Schreiben löscht ist das falsch. Dann
löscht du die Page nachdem du das erste Wort geschrieben hast nochmal
bevor du das 2. schreibst...
Nimm es mal aus der for-Schleife raus und füge eine zusätzliche Schleife
direkt nach dem ClearFlag ein, in etwa:
1 | #define PAGESIZE 2048
| 2 | const uint32_t PAGES[]=
| 3 | {
| 4 | FLSHBSEADRPG186
| 5 | ,FLSHBSEADRPG187
| 6 | ,FLSHBSEADRPG188
| 7 | ,FLSHBSEADRPG189
| 8 | ,FLSHBSEADRPG190
| 9 | };
| 10 |
| 11 | ... // Unlock und Clearflags
| 12 |
| 13 | for (i=0;i<sizeof(PAGES);i++)
| 14 | {
| 15 | FLASH_ErasePage(PAGES[i]);
| 16 | }
| 17 |
| 18 | for(i = 0; i < x ; i++)
| 19 | {
| 20 | const uint32_t adrs = PAGES[i / PAGESIZE] + i * sizeof(uint32_t);
| 21 | FLASH_ProgramWord(adrs, pData[i]);
| 22 | }
| 23 | FLASH_Lock();
|
EDIT:
Huch, da war etwas nicht richtig im array-Index.
Ich möchte an dieser Stelle darauf hinweisen, dass ich mir bei:
nicht sicher bin, vielleicht muss es auch
sein. Das solltest du anhand vom Manual raus finden: wie viele 32-Bit
Wörter passen in eine Page.
#define FLASH_PAGE_SIZE 0x800
Nein, ich seh nichts im Memory, leider!
Ich hoffe bevor du zu lesen versuchst, gehst du mit z.B.:
FLASH_GetReadOutProtectionStatus() sicher, dass du überhaupt lesen
darfst und aktivierst es nötigen falls mit z.B.:
FLASH_ReadOutProtection(DISABLE)?
Ich beobachte das Memory mit dem Debugger
Kann der Debugger anzeigen was im Flash steht? Wäre davon ausgegangen,
dass das so nicht geht, weiß es aber nicht. Hast du das schon mal
gemacht oder von jemandem gesagt bekommen, dass im Debugger die Werte
aus dem Flash übernommen werden?
Im übrigen hast du in deinem letzten größeren Codebeispiel weiterhin:
1 | int x = (sizeof(tSetup) / sizeof(int));
|
Ist das nun ein Denkfehler von mir gewesen am Anfang, dass es:
1 | int x = (sizeof(tSetup) / sizeof(uint32_t));
|
heißen müsste? Wenn ja, warum muss es da int sein wenn du in der
for-Schleife 32-Bit-Int-Weise schreibst?
Ja, im Memory View sehe ich was wo abgespeichert wurde.
Bin Deiner Meinung..
1 | int x = (sizeof(tSetup) / sizeof(uint32_t));
|
ist korrekt!
Hast du mal Interrupts bzgl. Flash aktiviert, wie z.B.: FLASH_IT_ERROR,
FLASH_IT_EOP und dann geguckt ob der InterruptHandler anspringt?
Wäre mal interessant ob das auftritt, dann würde das heißen, dass das
schreiben nicht funktioniert (mgl. schreibgeschützte Pages).
He jetzt funktioniert es!! Der Interrupt habe ich nicht aktiviert!
Super Danke viel mal!
Das ist schön, Hauptsache es geht jetzt.
Welche Änderungen waren zum Schluss noch nötig?
1 | int x = (sizeof(tSetup) / sizeof(uint32_t));
|
Das uint32_t anstelle int!
Bin aber selber erstaunt, dass dies den Unterschied ausmachte!
nochmals Danke!
Wenn ich auf eine Page des Flashes Zugreiffen möchte: 1 | Setup2 = *((tSetup2*)FLSHBSEADRPG192);
|
Jetzt kann ich doch einfach die erste Page angeben und es werden alle
nachfolgenden Pages ausgelesen, oder? 1 | Setup = *((tSetup*)FLSHBSEADRPG186);
|
Vielen Dank!
Gruss
Glaube schon, dass du das kannst: ich würde nur eher sowas machen wie:
(ist jetzt nur quick and dirty hingeschrieben)
1 | tSetup2 * tempSetup = (tSetup2*)FLSHBSEADRPG192;
| 2 | tSetup2 Setup;
| 3 | memcpy((void*)&Setup,(void*)tempSetup,sizeof(tSetup2));
|
(Ich fülle Setup quasi "Byteweise" mit den Daten aus dem Flash um
sicherzugehen, dass ich nicht Bytes nach dem Ende von Setup mit Daten
aus dem Flash überschreibe.)
Hätte bei mir folgenden Grund: einem Operation wie 1 | Setup = *((tSetup*)FLSHBSEADRPG186);
|
würde ich selber nicht unbedingt trauen, weil ich mir nicht sicher bin,
ob der = Operator für dein Struct genau das tut, was man erwartet (in
deinem Fall, wo du keine Pointer im Struct hast vermutlich kein
Problem).
Manche Leute würden mich wegen meiner Paranoia vermutlich lünchen und es
aus Prinzip genau wie von dir vorgeschlagen lösen, weil vermutlich
schneller und weniger Flash-Lesezugriffe, musst du mal einfach
ausprobieren, ob es funktioniert, oder du rufst schnell den Lünch-Mob
;-).
EDIT: Bei Pointern im Struct (als Repräsentanten für dynamisch
allozierte Variablen) würde auch mein Vorgehen nicht sicher sein, stell
ich gerade fest... Also vielleicht ignorierst du meine letzte Aussage
einfach ;)..
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
|