Forum: Compiler & IDEs Custom Linkerscript: eigene Text-Section


von N. G. (newgeneration) Benutzerseite


Lesenswert?

Hallo Forum,

mal wieder eine Frage von mir.

Es geht um einen ATmega2560 und dessen Flash-Speicher.

Ich habe Konfigurationsdaten im Flash (sehr viele Tabellen, passsen und 
sollen nicht ins EEPROM), soweit klappt auch alles.
Diese Tabellen sollen jedoch "im Feld" also ohne PC oder Programmer oder 
Ähnliches veränderbar sein.

Ein AVR kann ja seinen eigenen Flash-Inhalt verändern 
(Bootloader-Funktion), aber dazu muss der Code, der den Flash verändern 
soll aus dem Bootloaderbereich ausgeführt werden.

Dazu muss ich also einige Funktionen in eine eigene Section legen, die 
dann an der Adresse 0x7E00 liegt (Startadresse des kleinsten 
Bootloader-Bereichs).
Für meine Bootloader verschiebe ich immer die gesamte .text-Section an 
die Adresse, aber das ist hier ungewünscht.

Ich werde wohl eine eigene section erstellen müssen und die Funktionen 
mit dem passenden Attribut versehen.
Da ich aber mittels -Wl,--gc-sections linken muss, muss wohl das 
Linkerscript verändert werden, damit die section nicht verworfen wird 
(oder ist das falsch?)

Des weiteren brauche ich eine 2. Custom-Section, die die 
Kofiguratonsdaten immer an die selbe Stelle im Flash schreibt. Diese 
Section sollte 1-2 Pages lang sein und darin sollte kein ausführbarer 
Code stehen, damit die Pages komplett gelöscht und neu beschrieben 
werden können.

so eine Art Pseudo-Code, wie es dann mal aussehen soll:
1
const __attribute__((section(".flashData"))) 
2
  uint16_t table[360] = { /* ... */ };
3
4
void updateDataTables(void) 
5
  __attribute__((section(".updateFlash")));
6
void updateDataTables(void) {
7
  //hole die neuen Daten
8
  //und berechne die werte des arrays
9
10
  //lösche die Pages der Section .flashData
11
  //und fülle sie mit den neuen Daten
12
}

Schön wäre natürlich, wenn man dann im Porgramm auf table[i] genauso 
zugreifen könnte, wie wenn ich es mit __flash gekennzeichnet hätte.

Könnte mir jemand erklären, wie ich das Default-Linkerscript der 
avr6-Architektur (zu der der ATmega2560 meines Wissens gehört) 
modifizieren müsste?

Danke im Voraus
N.G.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Für den Bootloader bietet sich .bootloader an.

Wozu braucht table[] eine eigene Section? Alles, was der Bootloader 
braucht, ist das Symbol. Wenn der Bootloader Teil der Applikation ist 
sollte das kein Problem sein.  Und die Zieladresse braucht er natürlich 
auch, wobei zu beachten ist, dass die Adressen i.d.R nicht in 16 BIts 
passen.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Hallo Johann,

das heißt, dass es schon eine Section gibt, die ich nur noch passen 
verschieben müsste? Das wäre schon mal gut.

Johann L. schrieb:
> Wozu braucht table[] eine eigene Section?
Ich dachte, dass es einfacher ist, eine neue Section zu erzeugen, in der 
nur die Tabelle liegt. Diese Section liegt dann an einer festen Adresse, 
die dann vom Code im bootloader verändert wird.
Eine eigene Section deshalb, damit nicht direkt dahinter Code liegt, den 
ich dann auch lösche.

> Wenn der Bootloader Teil der Applikation ist
> sollte das kein Problem sein.

Der "Bootloader" hier ist eben kein Bootloader, er dient nur zum 
modifizieren des Flashes
> wobei zu beachten ist, dass die Adressen i.d.R nicht in 16 BIts
> passen.

Ja, soweit ich weiß, muss man EIND noch manuell auf 1 oder 0 setzen, 
oder kann das der GCC inzwischen automatisch?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

N. G. schrieb:
> Hallo Johann,
>
> das heißt, dass es schon eine Section gibt, die ich nur noch passen
> verschieben müsste? Das wäre schon mal gut.

Was willst du denn "verschieben"?

> Johann L. schrieb:
>> Wozu braucht table[] eine eigene Section?
> Ich dachte, dass es einfacher ist, eine neue Section zu erzeugen, in der
> nur die Tabelle liegt. Diese Section liegt dann an einer festen Adresse,
> die dann vom Code im bootloader verändert wird.

Die Adresse ist beim Static Link immer fest, und hier ist die Adresse 
dem Bootloader ja bekannt — im Gegensatz zu einem separaten Bootloader.

Weiters brauchst du nur die länge der Sequenz, die hier per sizeof zur 
Verfügung steht.  Auch wenn's ein paar Byte mehr kostet, kann diese Size 
in eine globale Variable geschrieben werden, die der Bootloader lesen 
kann.

Geht natürlich auch über Symbole, die du per Linker-Skript verfügbar 
machst.

> Eine eigene Section deshalb, damit nicht direkt dahinter Code liegt, den
> ich dann auch lösche.

Ak, ok. Leuchtet ein :-)

>> Wenn der Bootloader Teil der Applikation ist
>> sollte das kein Problem sein.
>
> Der "Bootloader" hier ist eben kein Bootloader, er dient nur zum
> modifizieren des Flashes

D.h. die zu beschreibenden Objekte sind als const volatile zu 
deklarieren.

>> wobei zu beachten ist, dass die Adressen i.d.R nicht in 16 Bits
>> passen.
>
> Ja,

> soweit ich weiß, muss man EIND noch manuell auf 1 oder 0 setzen,
> oder kann das der GCC inzwischen automatisch?

avr-gcc geht davon aus, dass EIND immer den gleichen Wert hat. 
Indirekte Sprünge werden über Linker-Stubs aka. .trampolines erledigt.

Aber es geht nicht um EIND sondern z.B. RAMPZ, d.h. Lesen aus dem Flash 
(.progmem.data) et al.

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Johann L. schrieb:
> N. G. schrieb:
>> Hallo Johann,
>>
>> das heißt, dass es schon eine Section gibt, die ich nur noch passen
>> verschieben müsste? Das wäre schon mal gut.
>
> Was willst du denn "verschieben"?

Woher weiß denn der Linker, wo die section liegen muss? Weil das ist ja 
einerseits vom Device abhängig (wobei das nicht das Problem wäre, da der 
Linker den Typen ja kennt) und andererseits von den Settings der Fuses 
(also wie groß der Bootloader ist).

Also denke ich, dass man dem Linker irgendwie mitteilen muss, wo die 
Section zu liegen hat. Das meint ich mit verschieben.

Johann L. schrieb:
> D.h. die zu beschreibenden Objekte sind als const volatile zu
> deklarieren.

Warum const volatile?
Also ich verstehe den Sinn dahinter, const weil ich sie nur lese und 
volatile, weil sie sich ohne zutun des Compilers ändern können, aber:
Wenn ich das volatile weglasse: was passiert dann? (Ich werde mir sobald 
ich den Code geschrieben habe das disassembly schauen, aber vllt gibts 
ja schon eine Prognose vom Guru ;) )

Johann L. schrieb:
>>> wobei zu beachten ist, dass die Adressen i.d.R nicht in 16 Bits
>>> passen.
>>
>> Ja,
>
>> soweit ich weiß, muss man EIND noch manuell auf 1 oder 0 setzen,
>> oder kann das der GCC inzwischen automatisch?
>
> avr-gcc geht davon aus, dass EIND immer den gleichen Wert hat.
> Indirekte Sprünge werden über Linker-Stubs aka. .trampolines erledigt.
>
> Aber es geht nicht um EIND sondern z.B. RAMPZ, d.h. Lesen aus dem Flash
> (.progmem.data) et al.

Okay, mein Fehler.
Ich meinte etwas anderes, bzw. habe zwei Dinge in einen Topf geworfen.
Brauche ich EIND nicht zu setzen, um zum Bootloader-Bereich zu springen, 
weil der über der 64kB-Grenze liegt? Weil das ist ja ein direkter 
Sprung/Call und sollte nichts mit den trampolines zu tun haben.

Aber nichts desto trotz hast du mit RAMPZ natürlich recht. Wobei RAMPZ 
doch 0 bleiben kann, wenn die zu verändernden Daten auf Pages liegen, 
die von einem 16bit-Pointer erreicht werden können.

PS: So eine Unterhaltung mit dir ist immer unglaublich bildend :D

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mal ne ganz andere Frage: Wozu dieses Umkopieren von Flash nach Flash 
anstatt einfach einen Zeiger umzubiegen?

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Okay, wenn ich das wollen würde, würde ich mein Problem seeeehr 
umständlich lösen...


Okay, nochmal von vorne mit genauerer Erklärung der Gegebenheiten:

ich habe mehrere Tabellen (am ende Wahrscheinlich 3, das Programm ist 
aber noch in der Entwicklung).
Diese Tabellen sind Lösungen verschiedener Gleichungen in Abhängigkeit 
verschiedener Winkel.
Soweit alles noch kein Problem.
Nur haben die Formel Koeffizienten, die von Zeit zu Zeit mal (manuell) 
verändert werden müssen.
Es soll ein Menü geben, in welchem man die Faktoren verändern kann.
Jetzt könnte man die Faktoren einfach im RAM speichern und jedes mal 
damit rechnen. Nur sind die Gleichungen lang und mit Gleitkomma sehr 
aufwändig.
Deswegen sollen Tabellen erstellt werden, die einmal vom AVR errechnet 
und anschließend gespeichert werden.
Genau da sitzt eben mein Problem: ich muss die __flash-Tabellen aus dem 
Programm heraus verändern.

Also:
Mensch geht an ein Interface und stellt in einem Menu einen neuen 
Koeffizienten ein.
Der AVR springt zum Bootloaderbereich.
Dort berechnet er die neue Tabelle mit dem geänderten Koeffizienten ein 
mal und speichert sie dann an den Platz der alten Tabelle.
Danach springt der AVR zurück zum Menü.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

N. G. schrieb:
> Warum const volatile?

Stell dir vor der Compiler kennt einen der Werte im Original-Array zur 
Compilezeit und macht z.B. ein LDI *,42 daraus.

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.