Forum: Mikrocontroller und Digitale Elektronik [MSP430] Struct Daten auf FLASH Speicher dauerhaft sichern


von Daniel G. (daniel83)


Lesenswert?

Hallo zusammen,

Ich bin neu hier und hoffe mich richtig eingefunden zu haben. Gesucht 
habe ich schon, nur leider nicht ganz das richtige gefunden.

Kurz zur Hardware.
Ich habe einen MSP430F149. Dieser ist in ein fertiges System verbaut, 
eine Hardware änderung kommt nicht in Frage, da es sich um ein 
Verkaufsfertiges Produkt handelt und nur an der Software gedreht werden 
darf, alles andere wird unangenehm teuer.

Was ich machen möchte:
Ich habe ein Programm für den PC geschreiben, mit dem ich Parameter 
ändern kann. Aktuell werden diese über Dippschalter eingestellt, sind 
also nach einem Stromausfall reproduzierbar. Das ist bei einer 
Einstellung über Software nicht beliebig möglich.
Ich muss also meine Einstellungen auf den FLASH schreiben. Dies soll 
über eine Einstellrutine via UART erfolgen.

Was ich bisher gemacht habe:
Ich bekomme die Daten auf den Controler gesendet und empfange sie dort 
korrekt. Gespeichert werden sie noch nicht, da ich nun ein kleines 
Konzeptionelles Problem habe.

Lösungsansätze:
- 1. Erst habe ich überlegt, die Daten auf einen relativ weit 
hintenleigenden Bereich im FLASH zu speichern und von dort zu 
verarbeiten.

Warum nicht im Information Memory?
Ganz einfach zu viele Daten, Information Memory == 2* 128Byte
ich habe aber 3*280Byte, auch wenn ich von der PC Programierung komme, 
wo Datenmengen inzwischen keine Rolle mehr spielen ist da nicht mehr 
viel weg zu optimiern.

- 2. Ich Schreibe die Daten beim empfang in den RAM, da ist noch 
ausreichend Platz aktuell 1,4K da sollte ich die 840Byte wohl noch rein 
bekommen. Nach dem Empfang speichere ich diese in den FLASH und Prüfe 
sie auf Richtigkeit. Die Daten im RAM halte ich weiterhin vor. Dort sind 
sie nach dem was ich besher gelesen habe auch deutlich einfacher 
anzusprechen und auch deutlcih schneller und einfacher verfügbar. In der 
Startuprutine lese ich die Daten vom FLASH in den RAM und arbeite wie 
gewohnt mit den RAM Daten.

Fragen:
- Lösungsansatz 1 habe ich sinnvollerweise Verworfen?
- Ist die Lösung 2 vom Ansatz her Richtig?
- Kann ich Arrey[struct] einfach ab einer start adresse in den ROM 
schreiben oder muss ich das von hand Byte weise tun?
- Ist der FLASH echt so langsam oder kann ich mir den Platz im RAM 
sparen und mir bei Bedarf (Schon häufig, mögl. relativ Zeitkritsch) die 
DAten Satzweise aus dem FLASH hohlen?
- Bin aus den Informationen von TI nicht ganz schlau geworden was die 
Adressierbarkeit im Flash angeht. Geht das mit "Variablen" bezeichnern, 
oder muss ich da über die adresse gehen?

So nun gut viele Fragen für einen ersten Post, ich hoffe ich habe alle 
relevanten Daten geliefert und auch gezeigt dass ich mir bereits einige 
Gedanken gemacht habe.

Danke im Voraus

Daniel

von Christian R. (supachris)


Lesenswert?

Du kannst im Linker-Script einen beliebigen eigenen Flash-Bereich 
anlegen, dazu musst du nur das Script anpassen. Die txt Section wird 
dann kleiner, und der Linker lässt den Bereich für dich frei. 
Sinnvollerweise musst du da die Sektorgrenzen beachten. Da du die 
Adressen selbst vorgibst, kannst du über die normale Flash-Funktion (aus 
den C-Demos) dann einfach den/die Sektor(en) löschen, und den Strukt da 
rein schreiben. Du nimmst einen pointer auf das Strukt und per sizeof() 
die Länge und ab geht die Post. Einzig das Schreiben ist etwas langsam, 
aber das Lesen aus dem Flash ist genauso schnell wie das Lesen aus dem 
RAM, daher ist das egal. Ich hab sowas für einen Funk-Bootloader 
gemacht, klappt wunderbar. Mit GCC noch einfacher als mit dem CCE3, aber 
geht natürlich bei jedem Compiler/Linker.

von Daniel G. (daniel83)


Lesenswert?

Nochmal Hallo Zusammen

So, habe den Teil erstmal auf die lange Bank geschoben, aber jetzt bin 
ich wieder dran.
Das mit den Linker Files hab ich noch nicht ganz verstanden, glaube ich. 
Da ich mir damit bestimmt auch nen bischen was kaputt machen kann frag 
ich lieber nochmal nach. Ich habe einen File gefunden und Modifiziert. 
der sieht jetzt so aus:
1
<!DOCTYPE Linker_Placement_File>
2
<Root name="MSP430 Section Placement">
3
  <MemorySegment name="RAM">
4
    <ProgramSection load="Yes" start="0x0" name=".abs"/>
5
    <ProgramSection name="IDATA0"/>
6
    <ProgramSection name="UDATA0"/>
7
  </MemorySegment>
8
  <MemorySegment name="INFO_A">
9
    <ProgramSection load="Yes" name="INFO_A"/>
10
  </MemorySegment>
11
  <MemorySegment name="INFO_B">
12
    <ProgramSection load="Yes" name="INFO_B"/>
13
  </MemorySegment>
14
  
15
16
  <MemorySegment name="Element_1">
17
    <ProgramSection size="512" load="Yes" start="0x6000" name="Element_1"/>
18
  </MemorySegment>
19
  <MemorySegment name="Element_2">
20
    <ProgramSection size="512" load="Yes" start="0x6200" name="Element_2"/>
21
  </MemorySegment>
22
  <MemorySegment name="Element_3">
23
    <ProgramSection size="512" load="Yes" start="0x6400" name="Element_3"/>
24
  </MemorySegment>
25
26
27
28
  <MemorySegment name="FLASH">
29
    <ProgramSection load="Yes" name="ISR"/>
30
    <ProgramSection load="Yes" name="CONST"/>
31
    <ProgramSection load="Yes" name="CODE"/>
32
    <ProgramSection size="32" load="Yes" start="0xFFE0" name="INTVEC"/>
33
  </MemorySegment>
34
</Root>

eingefügt habe ich den Teil in der Mitte. Geht das so, oder bin ich da 
komplett auf dem Holzweg?


sollte das so gehen, komme ich gleich zur nächsten Frage. Nach ansehen 
der Beispiel Dateien von TI habe ich 3 Beispiel funktionen geschreiben, 
die in etwa zeigen sollen was ich vor habe.


1
typedef struct{
2
  unsigned byte ubByte1;
3
  unsigned int uiInt1;
4
  unsigned long ulLong1;
5
}TS_INNER_STRUCT
6
7
typedef struct{
8
  unsigned byte ubByte2;
9
  unsigned int uiInt2;
10
  unsigned long ulLong2;
11
  TS_INNER_STRUCT inner_struct[STRUCT_COUNT];
12
}TS_MAIN_STRUCT
13
14
15
int erase_Flash(unsigned int StartAdress)
16
{
17
  Flash_ptr = (TS_MAIN_STRUCT *) StartAdress;    //Initialise Flash pointer to StartAdress
18
19
  FCTL2 = FWKEY + FSSEL1 + FNO; // MCLK/2 for Flash Timing Generator
20
  FCTL1 = FWKEY + ERASE; // Set Erase bit
21
  FCTL3 = FWKEY;  // Clear Lock bit
22
23
  *Flash_ptr = 0;  // Dummy write to Erase
24
25
  while (! (FCTL3 & WAIT) );  // Wait while not ready
26
  
27
  return 1;
28
}
29
30
void write_Flash(TS_MAIN_STRUCT struct_to_save , unsigned int StartAdress)
31
{
32
  //_DINT();  // Disable Interrupts
33
34
  Flash_ptr = (TS_MAIN_STRUCT *) StartAdress;  
35
             //Initialise Flash pointer to StartAdress
36
37
  while( FCTL3 & BUSY );  // Check Flash Busy bit
38
39
  FCTL1 = FWKEY + BLKWRT + WRT; // Enable block-write operation
40
41
  *Flash_ptr = struct_to_save; // write value to flash
42
43
  while (! (FCTL3 & WAIT ) );  // Wait until Flash is ready
44
45
  FCTL1 = FWKEY;  // Clear BLKWRT & WRT bits
46
47
  while ( FCTL3 & BUSY );  // Check Busy bit
48
49
  FCTL3 = FWKEY + LOCK;  // Reset Lock bit
50
51
  //_EINT();    // Enable Interrupts
52
}
53
54
55
TS_MAIN_STRUCT read_Flash( unsigned int StartAdress )
56
{
57
  Flash_ptr = (TS_MAIN_STRUCT *) StartAdress;    //Initialise Flash pointer to StartAdress
58
59
  return (*Flash_ptr);              // return Value of Flash pointer
60
61
}

Ich meine Gelesen zu haben, dass ich die Interrupts beim Schreiben aus 
stellen muss, also sollte ich sie ein kommentieren.
In der Schreib rutine von TI waren keine drin, deshalb hab ich erstmal 
keine, oder aber die gelten in dem Beispiel wegen der Copy rutine.

Die Adressen kann ich mir ja entsprechend der MemoryMap und den dort 
angegebenen Adressen verwenden.

Wenn ich das so machen, kriege ich dann das komplette struct ("auf 
einaml") in den Flash oder muss ich das Byteweise schreiben?

Und krieg ich das wirklich soo einfach wieder heraus?

Ich habe leider eine etwas schlechte Debugumgebung, also Debuggen im 
System ist mir soweit ich weiß nicht möglich, deshalb gerade bei 
möglicherweiser kritschen Operation frage ich hier so ausführlich nach, 
nicht dass ich mir was kaputt mache.

So, wer hier angekommen ist, schonmal vielen Dank für die Mühe des 
lesens, und hoffentlich des beantwortens^^

Gruß Daniel

von Daniel G. (daniel83)


Lesenswert?

In der Datei, die als MemoryMap gelinkt ist habe ich den Folgenden Teil 
entdeckt:
1
<MemorySegment size="0xef00" access="Read" start="0x1100" name="FLASH"/>
2
  <MemorySegment size="0x80" access="Read/Write" start="0x1000" name="INFO_B"/>
3
  <MemorySegment size="0x80" access="Read/Write" start="0x1080" name="INFO_A"/>
4
  <MemorySegment size="0x800" access="Read/Write" start="0x200" name="RAM"/>

Das hießt doch dass mein Sectionplacement, was oben steht wohl falsch 
ist.
Weil wie oben geht es nicht. ich müsste also in diesem File es so 
ändern:
1
<MemorySegment size="0xef00" access="Read/Write" start="0x1100" name="FLASH"/>
2
  <MemorySegment size="0x80" access="Read/Write" start="0x1000" name="INFO_B"/>
3
  <MemorySegment size="0x80" access="Read/Write" start="0x1080" name="INFO_A"/>
4
  <MemorySegment size="0x800" access="Read/Write" start="0x200" name="RAM"/>

und in der oberen Datei so:
1
...
2
  <MemorySegment name="FLASH">
3
    <ProgramSection load="Yes" name="ISR"/>
4
    <ProgramSection load="Yes" name="CONST"/>
5
    <ProgramSection load="Yes" name="CODE"/>
6
    <ProgramSection size="512" load="Yes" start="0x6000" name="Element_1"/>
7
    <ProgramSection size="512" load="Yes" start="0x6200" name="Element_2"/>
8
    <ProgramSection size="512" load="Yes" start="0x6400" name="Element_3"/>
9
    <ProgramSection size="32" load="Yes" start="0xFFE0" name="INTVEC"/>
10
  </MemorySegment>
11
...


und diesen Teil raus löschen:
1
  <MemorySegment name="Element_1">
2
    <ProgramSection size="512" load="Yes" start="0x6000" name="Element_1"/>
3
  </MemorySegment>
4
  <MemorySegment name="Element_2">
5
    <ProgramSection size="512" load="Yes" start="0x6200" name="Element_2"/>
6
  </MemorySegment>
7
  <MemorySegment name="Element_3">
8
    <ProgramSection size="512" load="Yes" start="0x6400" name="Element_3"/>
9
  </MemorySegment>

von Daniel G. (daniel83)


Lesenswert?

Ok, das mit der Memory Map hab ich jetzt.

Also Memory Map muss rein:
1
  <MemorySegment size="0xe900" access="Read" start="0x1700" name="FLASH"/>
2
  <MemorySegment size="0x200" access="Read/Write" start="0x1500" name="Element_C"/>
3
  <MemorySegment size="0x200" access="Read/Write" start="0x1300" name="Element_B"/>
4
  <MemorySegment size="0x200" access="Read/Write" start="0x1100" name="Element_A"/>
5
  <MemorySegment size="0x80" access="Read/Write" start="0x1000" name="INFO_B"/>
6
  <MemorySegment size="0x80" access="Read/Write" start="0x1080" name="INFO_A"/>
7
  <MemorySegment size="0x800" access="Read/Write" start="0x200" name="RAM"/>

in dem Section placement File:
1
  <MemorySegment name="INFO_B">
2
    <ProgramSection load="Yes" name="INFO_B"/>
3
  </MemorySegment>
4
  <MemorySegment>
5
    <ProgramSection load="Yes" name="Element_A"/>
6
  </MemorySegment>
7
  <MemorySegment>
8
    <ProgramSection load="Yes" name="Element_B"/>
9
  </MemorySegment>
10
  <MemorySection>
11
    <ProgramSection load="Yes" name="Element_C"/>
12
  </MemorySection>

zumindest zeigt es so meine Entwicklungsumgebung richtig an ;-)

bleibt das Problem mit dem Zugriff/Speichern in diesem Bereich.

von Christian R. (supachris)


Lesenswert?

Du kannst nicht das ganze Struct aufs Mal schreiben, sondern musst das 
Byte oder Wortweise schreiben, ich hab das zum beispiel so:
1
unsigned char WriteInfoMemA(unsigned int *Data, unsigned char NumWords)
2
{
3
  if(NumWords < 129)
4
  {
5
    //_DINT();
6
    WDTCTL = WDTPW + WDTHOLD;                       // Stop watchdog timer
7
      FCTL2 = FWKEY + FSSEL_SMCLK + FN1 + FN3;      // SMCLK/10 for Flash Timing Generator -> ~ 400Khz
8
    unsigned int *FlashPtr;
9
    unsigned char i;
10
    FlashPtr = (unsigned int*)0x1080;
11
    FCTL1 = FWKEY + ERASE;                    // Set Erase bit
12
      FCTL3 = FWKEY;                            // Clear Lock bit
13
      *FlashPtr = 0;                           // Dummy write to erase Flash segment
14
    FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
15
    
16
    for (i=0; i<NumWords; i++)
17
      {
18
        *FlashPtr++ = *Data++;                   // Write value to flash
19
      }
20
  
21
      FCTL1 = FWKEY;                            // Clear WRT bit
22
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
23
    //_EINT();
24
    return NumWords+1;
25
  }
26
  else return 0;
27
}
Aufrufen müsstest du das dann:

WriteInfoMemA(TS_MAIN_STRUCT, sizeof(TS_MAIN_STRUCT)/2 );

Musst halt für dich noch das mit der Startadresse anpassen, und die 
Anzahl Bytes an das Flash-Segment.....es gehen ja immer nur 128 Worte 
aufs Mal zu schreiben....

von Daniel G. (daniel83)


Lesenswert?

Hallo Christan,

Danke für die Antwort,

Du meinst sicher 128Bytes, weil 128 Worte passen in Info_A nicht rein^^

Aus diesem Grund habe ich mir ja hoffentlich richtig 3 neue Daten 
bereiche eingerichtet, die 3* 512 Bytes groß sind, da mir die Info 
Speicher nicht reichen.

In deinem Beispiel löscht du Segment a und schreibst 128 * Int in den 
Speicher, int ist doch aber laut meinem schlauen Buch 2-4 Bytes lang, in 
meinem Fall meine ich 2 Bytes. Wäre also zuviel, aber du weist bestimmt 
was du tust. Vieleicht verhaue ich mich da.

Wenn aber int 2Bytes groß ist, dann kann ich doch auch Größe Datentypen 
auf mal schreiben, also bsp. nen Long, und wenn das geht warum kein 
Struct? ist ja auch "nur" ein Datentyp.

Wenn ich die Structs auseinander nehmen muss um sie in Teilen zu 
schreiben, und dann auch wieder in Teilen zu lesen?? habe ich dort 
einfach ein sehr großes Fehler Potential, welches ich gerne durch 
einfache Rutinen umgehen will.

Der Prozessor ist ja dummerweise immer nur so schlau wie der, der davor 
sitzt

von Daniel G. (daniel83)


Lesenswert?

Die Daten des Struktsliegen mir im RAM vor. Würde es gehen eine Schleife 
zu bauen, die mit 2 (char *) piontern arbeitet?

also so:
1
void write_Flash(TS_MAIN_STRUCT *struct_to_save, int StartAdress)
2
{
3
4
    //_DINT();
5
    WDTCTL = WDTPW + WDTHOLD;                       // Stop watchdog timer
6
      FCTL2 = FWKEY + FSSEL_SMCLK + FN1 + FN3;      // SMCLK/10 for Flash Timing Generator -> ~ 400Khz
7
    unsigned char *FlashPtr;
8
  unsigned char *StructPtr;
9
    FlashPtr = (unsigned char*)ELEMENT_A;
10
  StructPtr=(unsigned char*)struct_to_slave;
11
    FCTL1 = FWKEY + ERASE;                    // Set Erase bit
12
      FCTL3 = FWKEY;                            // Clear Lock bit
13
      *FlashPtr = 0;                           // Dummy write to erase Flash segment
14
    FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
15
    
16
    for (; StructPtr<=(struct_to_slave+sizeOf(TS_MAIN_STRUCT); )
17
      {
18
        *FlashPtr++ = *StructPtr++;                   // Write value to flash
19
      }
20
  
21
      FCTL1 = FWKEY;                            // Clear WRT bit
22
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
23
    //_EINT();
24
}

Der zugriff sollte wie oben beschrieben gehen , denke ich.

Gruß Daniel

von Christian R. (supachris)


Lesenswert?

Du kannst auch über Sektor-Grenzen hinwegschreiben, musst aber vorher 
den nächsten Sektor auch gelöscht haben. Daher die 128 Worte (gesamter 
InfoMem des F1611). Sowas mache ich beispielsweise beim Firmware-Update 
über Funk. Ich hab einen Bootloader-Bereich und lösche allles ab dem 
Bootloader-Bereich in einem Rutsch in einer Schleife, den WritePointer 
immer un 0x200 erhöht (FlashPinter ist unsignec char *, also Byte 
Programming). Dann FlashPointer wieder auf den Start des Hauptpogrammes 
setzen und aus dem externen RAM das neue Programm in den Flash schreiben 
(auch wieder Byte-Weise.

Wenn du nur eine Schreib-Operation mit einem uint16_t* Pointer machst, 
wird nur ein einziges Wort in den Flash geschrieben. Teilen musst du 
deine Structs nicht. Das hab ich oben falsch geschrieben. Man kann über 
die Sektoren schreiben, aber eben vorher jeden Sektor einzeln löschen, 
wenn man kein Mass Erase machen will.

von Christian R. (supachris)


Lesenswert?

Ich würds halt zur besseren lesbarkeit so machen:
1
void write_Flash(TS_MAIN_STRUCT *struct_to_save, int StartAdress)
2
{
3
4
    //_DINT();
5
    WDTCTL = WDTPW + WDTHOLD;                       // Stop watchdog timer
6
      FCTL2 = FWKEY + FSSEL_SMCLK + FN1 + FN3;      // SMCLK/10 for Flash Timing Generator -> ~ 400Khz
7
    unsigned char *FlashPtr;
8
  unsigned char *StructPtr;
9
    FlashPtr = (unsigned char*)ELEMENT_A;
10
  StructPtr=(unsigned char*)struct_to_slave;
11
    FCTL1 = FWKEY + ERASE;                    // Set Erase bit
12
      FCTL3 = FWKEY;                            // Clear Lock bit
13
      *FlashPtr = 0;                           // Dummy write to erase Flash segment
14
    //Segment B löschen
15
    FlashPtr = (unsigned char*)ELEMENT_B;
16
    FCTL1 = FWKEY + ERASE;                    // Set Erase bit
17
      FCTL3 = FWKEY;                            // Clear Lock bit
18
      *FlashPtr = 0;                           // Dummy write to erase
19
    FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
20
    
21
    unsigned char i;
22
    for (i=0; i< sizeOf(TS_MAIN_STRUCT); i++)
23
      {
24
        *FlashPtr++ = *StructPtr++;                   // Write value to flash
25
      }
26
  
27
      FCTL1 = FWKEY;                            // Clear WRT bit
28
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
29
    //_EINT();
30
}

Als Beispiel das (eventuell vorhandene) Segment B noch mit löschen, 
falls dein Struct größer ist als 512 Byte....

von Daniel G. (daniel83)


Lesenswert?

In meinem Fall schreibe ich in 512Byte große Bereiche im Flash, also 
löschen des Blocks sollte laut beschreibung die kompletten 512 Bytes 
löschen, ganz so viel brauche ich zwar nicht aber ich hab ja Platz ohne 
ende^^

Mir ist halt wichtig, dass die Structur des Structs erhalten bleibt.

Ich führe von einem PC aus eine Einstellung von "Parametern" durch. 
Diese will ich natürlich über einen möglichen strumausfall hin weg 
retten. Arbeiten tue ich mit dem Struct im RAM, da ich viele Schreib und 
überschreibzugriffe in bestimmten Teilen habe.

Ich brauche halt eine Funktion um die Structs vom Ram in den Flash zu 
bekommen und wieder zurück. Dies am besten ohne doll drüber nach zu 
denken.

Mit der von mir oben geposteten Version deiner Funktion schreibe ich ja 
nun Byteweise, sollte also gehen.

Muss ich auch wieder Byteweise lesen?

Wäre ja dann quasi genau so, wie die Schreib operation.

Wie gesagt ist mein Problem, dass ich erst zeimlich viel Code 
produzieren muss, um raus zu bekommen ob da jetzt das drin steht was ich 
rein schreiben wollte, deshalb hänge ich hier so ein bischen fest, und 
kaput schreiben will ich mir nach Möglichkeit auch nichts.
Deshalb bin ich hier so penetrant darauf bedacht zumindest ein ja es 
sollte so funktioneren als Antwort zu bekommen.

von Daniel G. (daniel83)


Lesenswert?

Hallo Christian,

danke dir für die Antwort.

Ich werde mich mal dran setzten und das so Implementieren.

Ja ein Element B ist vorhanden, aber das brauche ich für Array elemnt 2 
meines Struct Arrays^^

Ich sollte aber mit den 512 Bytes klar kommen, wenn nicht muss ich eh 
umbauen.

Hast du zum auslesen eine Idee, also muss ich das auch Byte weise tun 
oder geht das so wie beschrieben?

von Christian R. (supachris)


Lesenswert?

Du kannst dann natürlich auch Wortweise lesen. Ich nehm dazu die memcpy 
Funktion der Einfachheit halber. Flash lesen ist genauso wie RAM lesen, 
da muss nix am Flash-Controller getan werden.

von Daniel G. (daniel83)


Lesenswert?

Also Pointer auf struct mit der Start adresse und gib ihm...

von Christian R. (supachris)


Lesenswert?

memcpy(DeinStrukt, SEGMENT_A, sizeof(TS_MAIN_STRUCT));

von Daniel G. (daniel83)


Lesenswert?

So, habs zusammen und es schein zu funktionieren.

Schreiben:
1
void write_Flash(TS_MAIN_STRUCT*struct_to_save, int StartAdress)
2
{
3
      unsigned char *FlashPtr;
4
      unsigned char *StructPtr;
5
      unsigned int i;
6
7
       _DINT();
8
       WDTCTL = WDTPW + WDTHOLD;                       // Stop watchdog timer
9
       FCTL2 = FWKEY + FSSEL1 + FN0 ;      // SMCLK/10 for Flash Timing Generator -> ~ 400Khz
10
11
      FlashPtr = (unsigned char*)ELEMENT_A;
12
      StructPtr=(unsigned char*)struct_to_save;
13
      FCTL1 = FWKEY + ERASE;                    // Set Erase bit
14
      FCTL3 = FWKEY;                            // Clear Lock bit
15
      *FlashPtr = 0;                           // Dummy write to erase Flash segment
16
   
17
      FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation
18
19
      for (i=0; i< sizeof(TS_MAIN_STRUCT); i++)
20
      {
21
            *FlashPtr++ = *StructPtr++;                   // Write value to flash
22
      }
23
  
24
      FCTL1 = FWKEY;                            // Clear WRT bit
25
      FCTL3 = FWKEY + LOCK;                     // Set LOCK bit
26
      _EINT();
27
}

Auslesen:
1
void vSetStructs(void)
2
{
3
      TS_MAIN_STRUCT* Struct_ptr = (TS_MAIN_STRUCT*)ELEMENT_A;
4
      tsMainStruct[0]=*Struct_ptr;
5
}

ELEMENT_A ist eine Konstante auf den Speicherort.

von Daniel G. (daniel83)


Lesenswert?

So,

Speichern geht, zurück laden nicht ganz.

Da ich in früheren Beiträgen bereits auf mein suboptimale aufgelkistet 
Struct angesprochen wurde könnte es sein, dass damit zusammen hängt. 
hier erstmal meine Structs die ich ablege.

1
typedef struct   {
2
ubyte ubKeyDownCommand; 
3
ubyte ubKeyDownParameter;     
4
ubyte ubKeyUpCommand;      
5
ubyte ubKeyUpParameter;          
6
ubyte ubToggleCommand;         
7
ulong ulWindowUsed;            
8
ubyte ubState;                          
9
uword uwTimestamp;    
10
ubyte ubUpToDownFlags;            
11
ulong ulWindowsProcessed;      
12
                  } TS_KEYS;
13
14
typedef struct  {
15
ubyte ubDipSwitch;       
16
ubyte ubDipSwitchOld;     
17
ulong ulButtons;         
18
ulong ulButtonsOld;
19
ulong ulButtonsProcess;   
20
ubyte ubSlaveOnline;      
21
ubyte ubAvailableRetrys;  
22
ubyte ubModuleSoftwareFlag;   
23
ubyte ubModuleSoftwareFlagOld;
24
TS_KEYS tsKeys[KEY_COUNT_ONE];
25
                } TS_MODULE;

Das Problem ist, dass ich nach dem Speichern im Flash in einigen Stellen 
0xFF stehen hab, da der FGlash beim löschen ja mit 1 beschrieben wird 
legt das die vermutung nahe, dass ich hier auf die falsche stelle 
zugreife. Ich arbeite mit dem Struct nur im RAM, lege ihn aber im Flash 
ab und hohle ihn mir da beim Neustarten wieder raus.
Wenn ich etwas rein schreibe und sofort auslese ist alles richtig.
Wenn ich es erst abspeichere und dann aus dem Flash lade und dann 
auslese habe ich teilweise Falsche Werte Gerne bei "ubDownCommand" habe 
aber nicht alles restlos getestet, möglicherweise auch an anderer Stelle

Wie ich speichere Steht ja oben, lesen tue ich so
1
TS_MODULE* modulePtr;
2
modulePtr=(TS_MODULE *)ELEMENT_A;
3
tsModule[ubModuleID]=*modulePtr;

Sollte es so sein, dass evtl im RAM die Adressierbarkeit anders ist als 
im Flash könnte es durch einfaches Kopieren nicht getan sein.

Wenn dem so ist, oder jemand meint, dass es daran leigen könnte wäre es 
nett wenn mir jemand sagen könnte wie ich die Structs umstellen muss 
damit es keine Probleme gibt.

Ich speichere in einen Flashsector immer EIN "TS_MODULE"

Gruß Daniel

von Daniel G. (daniel83)


Lesenswert?

Weiteres Testen ergab, fehler treten nur bei den ersten beiden Structs 
auf, bei dem Dritten geht es zuverlässig.

Allerdings verarbeite ich alle drei gleich, versuche nun schon seit 2 
Stunden den Unterschied in den Rutinen zu finden.

Wird durch dieses Verhalten meine Idee mit den unterschiedlichen Größen, 
bzw. lager orten der einzelnen Bytes und Longs im Flash und im Ram hin 
fällig, oder hat das nichts zu sagen??

von Stefan (Gast)


Lesenswert?

Wie groß ist Dein STRUCT (in Bytes) ?

von Christian R. (supachris)


Lesenswert?

Normalerweise kümmert sich der Kompiler drum, die Daten an 16 Bit 
auszurichten. Allerdings ist der Speicher im MSP430 auch 
Byte-Adressierbar, selbst dann sollte es keine Probleme geben. Welchen 
Kompiler benutzt du überhaupt?

von Daniel G. (daniel83)


Lesenswert?

@ Stefan: ca 360 Bytes meine ich ausgerechnet zu haben aufjedenfall 
deutlich kleiner als 512Bytes

@ Christian Rowley CrossStudio Pro

von Rene B. (themason) Benutzerseite


Lesenswert?

@daniel ...

ich hab den thread nur mal eben kurz überflogen ...
aber wenn du in dem linkerfile für deine 3 speicherbereiche 0x1100 
0x1300 und 0x1500 angegeben hast wirst/kannst du probleme bekommen. die 
flash-page size ist ja 512 byte (0x200) groß, und 0x1100, 0x1300 und 
0x1500 liegen auf einer "halben page" ... mit 0x1200, 0x1400 und 0x1600 
dürften keine probleme auftauchen.
ich weiß nicht ob das im thread schon gesagt worden ist, aber das 
müsstest du beherzigen, vor allem wenn in dem bereich von 0x1000 - 
0x1100 und 0x1700-0x1800 code drin steht, da dieser beim löschen der 
page ebenfalls gelöscht wird und die fehlersuche dann erst richtig 
lustig wird.

von Daniel G. (daniel83)


Lesenswert?

Ich habe mit 0x1100 angefangen, da dort laut datenblat der Code teil 
anfängt, hängt evtl. mit den 2*128Bytes im Info A und Info B speicher 
zusammen, das sollte eigentlich kein Problem sein

von Stefan (Gast)


Lesenswert?

>ca 360 Bytes meine ich ausgerechnet zu haben aufjedenfall
>deutlich kleiner als 512Bytes

Hat vermutlich nicht unbedingt mit Deinem Problem zu tun...
aber Du betreibst den Flash beim Beschreiben ausserhalb der 
Spezifikation!

Ich kann nicht behaupten, dass ich alles genau verstanden habe, was TI 
zu dem Thema sagt. Aber kurz zusammengefasst verstehe ich das so:
(Grundlage: Datenblatt F149 und AppNote slaa334)

Jeder Schreibvorgang ins Flash (Byte/Word) dauert 35 Taktzyklen (bezogen 
auf den Clock des Memory Controllers). Davon wird 29 TZ lang die 
Programmierspannung an eine zusammenhängende 64-Byte-Reihe Flashzellen 
gelegt. Diese Programmierspannung "stresst" die Flashzellen. Daher darf 
diese Spannung nur für eine maximale Zeitdauer anliegen (cumulative 
program time). Beim F149 beträgt diese max. 4ms !

Bei Dir -meine ich hier irgendwo gelesen zu haben- ist fFTG = 400kHz
D.h. beim Schreiben eines Bytes liegt die Spannung für 29/400kHz = 
72,5µs an.
Bei tCPT = 4ms kannst Du also maximal 4ms/72,5µs = 55Bytes am Stück 
programmieren. Wenn Du die vollen 64Bytes programmierst, überschreitest 
Du max. zulässige CPT!

Einzige Möglichkeit:
-entweder fFTG auf Maximum (476kHz)
-oder WORD anstatt BYTE-weise schreiben

von Daniel G. (daniel83)


Lesenswert?

@ Stefan:

Was du meinst ist bestimmt diese Zeile:
>FCTL2 = FWKEY + FSSEL1 + FN0 ;      // SMCLK/10 for Flash Timing Generator -> ~ 
400Khz

Die Kommentare daran habe ich aus Christans Bespiel übernommen, der Wert 
ist aus dem TI Beispiel

FCTL2 = FWKEY + FSSEL1 + FN0 ;  // MCLK/2 for Flashtiming Generator

wäre entsprechend dem Beispiel, etwas anderes sehe ich dort nicht, was 
irgendwas mit Timing oder Frequenzen zu tun hat, jedoch jedoch ist MCLK 
mit Dafault 800Khz angegeben, wären wenn MCLK/2 stimmt also auch 400kHz.

Wie krieg ich dass denn schneller?

von Stefan (Gast)


Lesenswert?

>Wie krieg ich dass denn schneller?
Na den Teilerfaktor über FNx gemäß User Guide anpassen.
Gegebenenfalls auch die Clock source anders wählen.
Musst halt auch aufpassen, dass die Toleranzen der Clock source nicht 
den Memory Controller Clock über die max. 476kHz treiben können!

von Daniel G. (daniel83)


Lesenswert?

Durch die Appnotes bin ich nicht ganz durchgestiegen, bzw. habe das 
Datenblatt mit den Werten nicht gefunden, aber das Timing Problem habe 
ich über Wortweises schreiben gelöst.

habe mal die Größe exakt bestimmt. mit optimierung also irgendwie passen 
zusammen gelegt ergibt das für TS_KEYS 17 Bytes und für TS_MUDOLE 18 
Bytes + 20* TS_KEYS also insgesamt 358Bytes

Ohne optimierung sind das TS_KEYS im schlechtesten fall 20 Bytes und 
TS_MODULE 20 Bytes + 20* TS_KEYS also 420 Bytes

Der Knackpunkt ist bei index 12, also 12 geht noch 13 nicht mehr.
nur in ELEMENT A und ELEMENT B in ELEMENT C bekomme ich alles passend 
rein und wieder raus.
12 wäre nach optimierter rechnnung 12*17+18=222Bytes
ohne Optimierung 12*20+20=260Bytes
Sollte 256 der knackpunkt sein, würden die letzten 4 Byte von 
TS_KEYS[12] auch fehler, werde ich gleich mal test, ob ein umlegen um 
0x0100 etwas bewirkt.

von Christian R. (supachris)


Lesenswert?

Lass dir doch die Größe mit SizeOf Berechnen. Kannst du in einer 
variable zum Test mal ausgeben und im Debugger auslesen....dann weißt du 
es genau. Kommt ja drauf an, wie der die Padding Bytes einfügt...

von Stefan (Gast)


Lesenswert?

>habe mal die Größe exakt bestimmt. mit optimierung also irgendwie passen
>zusammen gelegt ergibt das für TS_KEYS 17 Bytes und für TS_MUDOLE 18
>Bytes + 20* TS_KEYS also insgesamt 358Bytes

>Ohne optimierung sind das TS_KEYS im schlechtesten fall 20 Bytes und
>TS_MODULE 20 Bytes + 20* TS_KEYS also 420 Bytes

Was für eine Optimierung?
Ich bin kein C-Standard-Auswendig-Wisser... aber soweit ich mich 
erinnere, sollte/dürfte ein Compiler an einer Struktur nix optimieren 
bzw. ändern?!

An Deiner Stelle würde ich mal die Strukturen so organisieren, dass das 
Alignment passt (ggf. Dummy-Bytes einfügen)!

... ist doch kein Zustand, sowas undefiniertes...

von Christian R. (supachris)


Lesenswert?

Das Padding macht der Kompiler alleine. Allerdings nur für seine 
Architektur, da muss man beim Austausch von Strukturen aufpassen. Der 
mspgcc packt die Strukturen in 16 Bit Grenzen, wie das der Rowley macht, 
weiß ich nicht. Denke aber auch, dass er sie an der nativen Wortbreite 
des Speichers ausrichtet. Das sollte nicht das Problem darstellen....

von Daniel G. (daniel83)


Lesenswert?

Gut, geht jetzt wohl.

Ich habe einfach den Speicherbereich ab 0x2000 anfangen lassen, ist ja 
massig Platz im Flash, wahrscheinlich ist da ein teil kaput gegangen, 
auf jedenfall geht es jetzt, werde es morgen noch bis zum exess Testen, 
auch mal mit anderer Hardware.

Soweit Danke ich erstmal allen, die sich ihre Gedanken gemacht haben und 
mir geholfen haben

von Stefan (Gast)


Lesenswert?

>Das Padding macht der Kompiler alleine
Es geht nicht ums Padding! Dass das der Compiler macht, ist klar!
Es geht um die (anscheinend) unterschiedliche Struktur-Größe, je nach 
Optimierung (was für eine auch immer da gemeint sein mag)...
Wenn man "nur" das Padding betrachtet, müsste die Struktur ja immer 
gleich groß sein!

von Daniel G. (daniel83)


Lesenswert?

Die unterschiedliche Größe war ein reine theoretischer Überlegungsansatz 
von mir.
Da wir zwar ne teure Entwicklungsumgebung gekauft haben aber keinen 
tollen debugger sondern nur so ein Teil zum rein schreiben, sind meine 
Debug möglcihkeiten leider etwas eingeschränkt, also hab ich mit nem 
Stift und Papier mal gerechnet, ob sich da etwas ergeben könnte.

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.