Forum: Mikrocontroller und Digitale Elektronik Array ins Flash speichern STM32F103VDT6


von Ma B. (drumstick)


Lesenswert?

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.

von Michael B. (michael_b93)


Lesenswert?

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.

von Ma B. (drumstick)


Lesenswert?

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.

von Michael B. (michael_b93)


Lesenswert?

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.

von Ma B. (drumstick)


Lesenswert?

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.

von Ma B. (drumstick)


Lesenswert?

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
}

von Michael B. (michael_b93)


Lesenswert?

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.

von Michael B. (michael_b93)


Lesenswert?

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.

von Michael B. (michael_b93)


Lesenswert?

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.

von Ma B. (drumstick)


Lesenswert?

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!?

von Ma B. (drumstick)


Lesenswert?

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

von Ma B. (drumstick)


Lesenswert?

Das ErasePage ist def. am falschen ort. So fliegt mir ja das Flash bald 
um die Ohren...

von Michael B. (michael_b93)


Lesenswert?

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.

von Michael B. (michael_b93)


Lesenswert?

Ich möchte an dieser Stelle darauf hinweisen, dass ich mir bei:
1
#define PAGESIZE 2048
nicht sicher bin, vielleicht muss es auch
1
#define PAGESIZE 2000
sein. Das solltest du anhand vom Manual raus finden: wie viele 32-Bit 
Wörter passen in eine Page.

von Ma B. (drumstick)


Lesenswert?

#define FLASH_PAGE_SIZE   0x800

von Michael B. (michael_b93)


Lesenswert?

Bist du weiter gekommen?

von Ma B. (drumstick)


Lesenswert?

Nein, ich seh nichts im Memory, leider!

von Michael B. (michael_b93)


Lesenswert?

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)?

von Ma B. (drumstick)


Lesenswert?

Ich beobachte das Memory mit dem Debugger

von Michael B. (michael_b93)


Lesenswert?

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?

von Ma B. (drumstick)


Lesenswert?

Ja, im Memory View sehe ich was wo abgespeichert wurde.

Bin Deiner Meinung..
1
int x = (sizeof(tSetup) / sizeof(uint32_t));

ist korrekt!

von Michael B. (michael_b93)


Lesenswert?

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).

von Ma B. (drumstick)


Lesenswert?

He jetzt funktioniert es!! Der Interrupt habe ich nicht aktiviert!

Super Danke viel mal!

von Michael B. (michael_b93)


Lesenswert?

Das ist schön, Hauptsache es geht jetzt.
Welche Änderungen waren zum Schluss noch nötig?

von Ma B. (drumstick)


Lesenswert?

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

von Michael B. (michael_b93)


Lesenswert?

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.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.