Array ins Flash speichern STM32F103VDT6

OP #2953379
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.
#2953400
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.
OP #2953412
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.
#2953426
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.
OP #2953437
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.
OP #2953447
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
}
#2953457
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.
#2953459
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.
OP #2954331
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!?
OP #2954389
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
#2954475
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.
#2954636
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?
OP #2954732
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
#2954768
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 ;)..

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren