ARM/GNU Struktur im FLASH an fester Adresse

OP #7719163
Lesenswert?

Hallo, folgendes Problem habe ich bisher nur unzufriedenstellend gelöst:

Ich habe ein Projekt, bei dem es die Möglichkeit gibt einen Paramtersatz, gespeichert in einer Struktur, nach der Programmierung mittels Bootloaders zu erstellen oder zu ändern.

Im Hauptprogramm gibt es einen Pointer auf diese Stelle (die Struktur wird hier nicht angelegt sondern nur gelesen) und soweit funktioniert es auch.

Nun möchte ich manchmal die Struktur doch anlegen lassen und habe dafür eine Sektion an der entsprechenden Adresse erstellt. Dies funktioniert auch, aber ich habe jetzt an mehreren Stellen die Adresse stehen. Im Linker und bei der Initialisierung des Pointers.

1
static const struct_t struct_var __attribute__ ((section( ".struct_section "))) = 
2
 {
3
   .a = 1,
4
   .b = 2,
5
 };
6
const struct_t *struct_ptr = (const struct_t *) (0x1FE00);
1
//[LINKER]
2
.struct_section=0x1FE00

Ich könnte natürlich den Pointer auf die Strukur initialisieren, aber falls ich die Struktur nicht anlegen möchte habe ich ein Problem. deklariere ich die Struktur ohne sie zu initialisieren wird der Flash an der Stelle mit Nullen gefüllt und das Hex-File entsprechend aufgebläht.

Ich hoffe ich habe mich verständlich ausgedrückt und frage ob ihr vielleicht eine bessere Idee habt.

Vielen Dank Simon

Persönliche Seite #7719193
Lesenswert?

Im Linker-Script NOLOAD verwenden:

1
.struct_section 0x1FE00 (NOLOAD) : {
2
  . = ALIGN(4);
3
  *(.struct_section)
4
  . = ALIGN(4);
5
}

Dann wird dafür einfach nur Platz freigehalten aber nicht mit irgendwas initialisiert.

Im Code musst du das struct nur noch in die Section packen genau wie du es schon gemacht hast, aber das "struct_ptr " brauchst du dann nicht mehr:

1
static const struct_t struct_var __attribute__ ((section( ".struct_section "))) = 
2
 {
3
   .a = 1,
4
   .b = 2,
5
 };

und dann ganz normal drauf zugreifen. So wird es dann eben nicht mehr initialisiert, die Werte 1 und 2 verschwinden beim Linken (d.h. beim ersten Programmstart wirst du Nonsense lesen), dafür brauchst du dann die üblichen Flash-Zugriffs-Routinen.

Wenn du das struct dann doch mal befüllen möchtest (z.B. beim Flashen in der Produktion) lasse das (NOLOAD) weg und die gewünschten Werte (1, 2) werden geflasht.

Persönliche Seite #7719209
Lesenswert?

Johann L. schrieb:

sondern volatile const

Das wäre aber ziemlich ineffizient, weil sie dann wirklich jedes Mal neu geladen werden... Wäre es da nicht sinnvoller das "static" wegzulassen und nach dem Schreiben ins-Flash ein memory-Barrier hinzuzufügen (asm volatile ("" : : : "memory") )?

Das funktioniert vermutlich nur in C, nicht in C++. In C++ könnte man "static" und "const" weglassen, aber die Variablen privat machen und nur getter hinzufügen...

OP #7719476
Lesenswert?

Niklas G. schrieb:

Im Linker-Script NOLOAD verwenden:

Super vielen Dank, das werde ich wahrscheinlich so umsetzen.

Aktuell erstelle ich die Sektion mittels Parameter

1
-Wl,-section-start=.struct_section=0x1FE00

kann ich dort auch NOLOAD verwenden?

Johann L. schrieb:

Da sich die Daten ändern können, sind sie streng genommen nicht const, sondern volatile const. Damit die Daten bei jedem Zugriff gelesen werden und nicht etwa vom Compiler in Immediate Operanden von Instruktionen eingebaut werden.

Die Problematik verstehe ich scheinbar noch nicht ganz. Für mich ist der Pointer konstant und die Struktur auf die dieser zeigt, sind für dieses Programm ebenfalls konstant, da sie sich innerhalb des Programms nicht ändern. Entweder werden sie bei der Initialisierung einmalig geschrieben, oder über den Bootloader.

Persönliche Seite #7719477
Lesenswert?

Simon G. schrieb:

kann ich dort auch NOLOAD verwenden?

Weiß nicht, das erscheint mir eine recht hinterhältige Methode, im Linkerscript vermutet man so etwas eher...

Simon G. schrieb:

Die Problematik verstehe ich scheinbar noch nicht ganz

Wenn der Compiler sieht, dass die Daten sich nicht ändern (In C: Weil "static const" dran steht, in C++: Weil "const" oder "constexpr" dran steht), kann es sein, dass der Compiler den Lesezugriff komplett wegoptimiert. D.h. die Initializer-Werte (bzw 0 wenn nicht angegeben) werden in den Maschinencode hart kodiert und es erfolgt überhaupt kein Lesezugriff auf die gewünschte Stelle.

OP #7719492
Lesenswert?

Niklas G. schrieb:

Simon G. schrieb:

kann ich dort auch NOLOAD verwenden?

Weiß nicht, das erscheint mir eine recht hinterhältige Methode, im Linkerscript vermutet man so etwas eher...

Da ich das Microchip Studio benutze boot sich das an, in der Projekt-Konfiguration kann man die Sektionen einfach anlegen und sie werden dann entsprechend als Paramter eingefügt. Aber ich kann natürlich, und ich werde es wahrscheinlich auch machen, die Sektion im Linkersript entsprechend anlegen.

Niklas G. schrieb:

Wenn der Compiler sieht, dass die Daten sich nicht ändern (In C: Weil "static const" dran steht, in C++: Weil "const" oder "constexpr" dran steht), kann es sein, dass der Compiler den Lesezugriff komplett wegoptimiert. D.h. die Initializer-Werte (bzw 0 wenn nicht angegeben) werden in den Maschinencode hart kodiert und es erfolgt überhaupt kein Lesezugriff auf die gewünschte Stelle.

Das leuchtet ein, wahrscheinlich gab es noch keine Probleme, da ich bisher immer über den Pointer auf die Struktur zugegriffen habe.

Niklas G. schrieb:

Wäre es da nicht sinnvoller das "static" wegzulassen und nach dem Schreiben ins-Flash ein memory-Barrier hinzuzufügen (asm volatile ("" : : : "memory") )?

Wie würde ich dies in meinem Fall nutzen?

OP #7719511
Lesenswert?

Niklas G. schrieb:

Simon G. schrieb:

schreibe ja in dem Programm den Flash nie

Und wie kommen dann die Parameter ins Flash?

Durch den Bootloader, der aber ein eigenständiges Programm ist, oder in Ausnahmefällen durch die Initialisierung der Struktur im Programm.

1
static const struct_t struct_var __attribute__ ((section( ".struct_section "))) = 
2
 {
3
   .a = 1,
4
   .b = 2,
5
 };
Persönliche Seite #7719524
Lesenswert?

Simon G. schrieb:

Durch den Bootloader, der aber ein eigenständiges Programm ist

Dann brauchst du die Memory Barrier nicht. Aber woher bekommt der Bootloader die Daten wenn sie nicht im Hex/Bin File stehen?

Simon G. schrieb:

oder in Ausnahmefällen durch die Initialisierung der Struktur im Programm.

Diese Initialisierung greift aber nicht wenn NOLOAD im Spiel ist. Hier brauchst du die Memory Barrier dann auch nicht aber du musst dennoch mit dem "const" aufpassen weil sonst ggf. gar keine Lesezugriffe gemacht werden.

OP #7719532
Lesenswert?

Niklas G. schrieb:

Dann brauchst du die Memory Barrier nicht. Aber woher bekommt der Bootloader die Daten wenn sie nicht im Hex/Bin File stehen?

Die Daten werden dem Bootloader per Serieller Schnittstelle übertragen.

Niklas G. schrieb:

Diese Initialisierung greift aber nicht wenn NOLOAD im Spiel ist. Hier brauchst du die Memory Barrier dann auch nicht aber du musst dennoch mit dem "const" aufpassen weil sonst ggf. gar keine Lesezugriffe gemacht werden.

Dann werde ich zwei Linkerscripte vorhalten, eins für den Standardfall in welchem NOLOAD steht und bei dem keine Initialisierung gewünscht wird, und ein zweites ohne NOLOAD.

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