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
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.
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:
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
typedefstruct{
2
unsignedbyteubByte1;
3
unsignedintuiInt1;
4
unsignedlongulLong1;
5
}TS_INNER_STRUCT
6
7
typedefstruct{
8
unsignedbyteubByte2;
9
unsignedintuiInt2;
10
unsignedlongulLong2;
11
TS_INNER_STRUCTinner_struct[STRUCT_COUNT];
12
}TS_MAIN_STRUCT
13
14
15
interase_Flash(unsignedintStartAdress)
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
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
FCTL2=FWKEY+FSSEL_SMCLK+FN1+FN3;// SMCLK/10 for Flash Timing Generator -> ~ 400Khz
8
unsignedint*FlashPtr;
9
unsignedchari;
10
FlashPtr=(unsignedint*)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
returnNumWords+1;
25
}
26
elsereturn0;
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....
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
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.
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.
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?
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.
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
typedefstruct{
2
ubyteubKeyDownCommand;
3
ubyteubKeyDownParameter;
4
ubyteubKeyUpCommand;
5
ubyteubKeyUpParameter;
6
ubyteubToggleCommand;
7
ulongulWindowUsed;
8
ubyteubState;
9
uworduwTimestamp;
10
ubyteubUpToDownFlags;
11
ulongulWindowsProcessed;
12
}TS_KEYS;
13
14
typedefstruct{
15
ubyteubDipSwitch;
16
ubyteubDipSwitchOld;
17
ulongulButtons;
18
ulongulButtonsOld;
19
ulongulButtonsProcess;
20
ubyteubSlaveOnline;
21
ubyteubAvailableRetrys;
22
ubyteubModuleSoftwareFlag;
23
ubyteubModuleSoftwareFlagOld;
24
TS_KEYStsKeys[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
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??
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?
@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.
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
>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
@ 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?
>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!
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.
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...
>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...
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....
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
>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!
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.