Forum: Mikrocontroller und Digitale Elektronik Arduino: Start und Ende des Datensegments ermitteln?


von Christian J. (Gast)


Lesenswert?

Hallo,

gibt es da Zauberworte, welche dem Compiler zur Laufzeit oder 
Übersetzungszeit die Start und Enadresse des .bss Section mitteilt?

Ich brauche die, da ich zur Laufzeit eine Kopie im EEProm speichere, die 
nach Reset wieder eine identische Umgebung erzeugt. Da meine 
Kopierroutine variablenmässig aus dem Stack heraus arbeitet dürfte kein 
Absturz erfolgen.

Gruss,
Christian

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

1
#include <stdint.h>
2
3
uintptr_t get_bss_start (void)
4
{
5
    extern char __bss_start[]; // Defined in linker script.
6
    return (uintptr_t) __bss_start;
7
}
Dito für __bss_end.

Allerdings ist der Ansatz nicht wirklich empfehlenswert: Falls der 
Inhalt von (statischen) Konstruktoren gesetzt wird, funktioniert das 
nicht mehr.

Stattdessen kann man die Daten als Struktur bzw. POD modellieren und von 
diesem 2 Instanzen halten, eine im RAM und eine im EEPROM.  Bei Bedarf 
werden die dann mit eeprom_read_block bzw. eeprom_update_block kopiert. 
Auch hier müssen die Daten POD sein.

Das hab ich in Projekten, wo Konfiguration nach (Powerdown) Reset 
erhalten bleiben soll, aber nie war dazu nötig den ganzen RAM zu 
speichern.

AUßerdem ist zu bedenken was mit .data und .rodata passieren soll.

von Chris J. (Gast)


Lesenswert?

Danke erstmal. Ist ein reines C Programm ohne Cpp Anteile, ausser in den 
verwendeten Libs. Moeglich waere noch eine Zusammengassung aller 
Variablen in einem Struct, da ich nur globale Zaehler etc sichern will 
und das moeglichst nicht alle einzeln.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Die einzelnen frei flottierenden Variablen werden zu einem Strukt 
zusammengefasst, in welchem sie als Komponenten auftreten.  Der Struct 
kann als ganzes gelesen, gespeichert, kopiert etc. werden.  Die 
Möglichkeit Komponenten einzeln zuzugreifen besteht natürlich, ist aber 
nicht zwingend.

Ardiuno kenne ich nicht, ist meines wissens aber C++.  Und selbst in C 
kann man Konstruktoren haben — zumindest in GNU-C.  Wenn solche in den 
Libs Verwendung finden dann hast du prinzipiell dieses Problem.

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Warum sollte man ein Problem mit Hackertricks lösen, wenn man es auch 
problemlos lehrbuchartig machen kann?

KISS!

von Oliver S. (oliverso)


Lesenswert?

Der saubere Weg wäre aber schon, die Variablen einzeln ins EEPROM zu 
kopieren, und auch wieder zu holen. Wenn’s unbedingt zusammengefasst 
passieren soll, dann pack die halt alle zusammen in einen struct.

Oliver

von Christian J. (Gast)


Lesenswert?

Falk B. schrieb:
> Warum sollte man ein Problem mit Hackertricks lösen, wenn man es auch
> problemlos lehrbuchartig machen kann?

Und was sagt das Lehrbuch? Auch ein Windows PC macht beim Ruhezustand 
ein Image und zieht sich das stur wieder rein beim Aufwecken.

Alle Vars in struct sind einfach, zerreissen mir aber das Programm, da 
ich diverse structs habe wo alles zusammen gefasst ist, was da rein 
gehört. Lieber wäre mir den ganzen Bereich einfach rein zu holen und da 
die laufvars etc auf dem Stack liegen passiert da auch nix.

von Christian J. (Gast)


Lesenswert?

Johann L. schrieb:
> Stattdessen kann man die Daten als Struktur bzw. POD modellieren und von
> diesem 2 Instanzen halten, eine im RAM und eine im EEPROM.

Ich verstehe von C++ leider nichts, will das aber noch ändern.

Wie erzeugt man denn so tolle Sachen wie EEPROM[Adresse] = .... ? Das 
geht nämlich beim Arduino und dahinter verbirgt sich dann der 
Schreibvorgang. Das EE wird aber wie ein Array angesprochen. Ich bin ja 
schon voll begeistert von den Stream Klassen, alles mit << und schon 
flutscht es rein in die Ausgabe.

von Falk B. (falk)


Lesenswert?

Christian J. schrieb:
> Falk B. schrieb:
>> Warum sollte man ein Problem mit Hackertricks lösen, wenn man es auch
>> problemlos lehrbuchartig machen kann?
>
> Und was sagt das Lehrbuch? Auch ein Windows PC macht beim Ruhezustand
> ein Image und zieht sich das stur wieder rein beim Aufwecken.

Wollen wir wetten, daß es auch da DEUTLICH geordneter zugeht, als du es 
dir ausmalst?

> Alle Vars in struct sind einfach, zerreissen mir aber das Programm,

Nö, denn dann ist deine Datenorganistation nicht sinnvoll.
Wenn ich schon spezielle Daten habe, welche eben derartig im EEPROM 
gesichert werden sollen, dann faßt man die sinnvollerweise zusammen und 
verteilt sie NICHT über sonst wie viele Objekte.

> da
> ich diverse structs habe wo alles zusammen gefasst ist, was da rein
> gehört. Lieber wäre mir den ganzen Bereich einfach rein zu holen und da
> die laufvars etc auf dem Stack liegen passiert da auch nix.

Schuster bleib bei deinen Leisten. Einem Compiler so auszutricksen ist 
selten eine gute Idee. Erst recht, wenn man einen Tunnelblick hat und zu 
faul ist, sein Problem durch passende Umstrukturierung der Daten zu 
lösen.

von Christian J. (Gast)


Lesenswert?

Falk B. schrieb:
> Schuster bleib bei deinen Leisten. Einem Compiler so auszutricksen ist
> selten eine gute Idee.

Klappt bei meinem Z80 Bauwerk auch :-) Boot Loader Kopiert sich aus 
EPROM ins Higher RAM, schaltet untere Bank von EPROM auf RAM um und 
zieht sich dann den Hex Code von der Uart rein und startet ihn 
anschließend. Und das alles in C mit dem SDCC. RAM ist allerdings ein 
Uhren RAM mit interner Batterie, da bleibt eh alles erhalten.

Gehen tut alles... aber ich denke drüber nach wie ich das mit 
Bordmitteln lösen kann.

PS: Mein PC schaltet die Monitore nicht mehr ein beim Aufwecken :-(

von Dr. Sommer (Gast)


Lesenswert?

Was hast du denn alles an Anwendungs-Status, der so behalten werden 
muss? Soll das Display genau im selben Untermenü wie vorher sein, genau 
in der Mitte der Animation wie vorher? Extern anzusprechende Komponenten 
bleiben auch garantiert in ihrem Zustand und müssen nie neu 
initialisiert werden?

Bei den meisten Embedded-Geräten ist der Zustand so flüchtig, dass man 
bei einem Neustart sowieso alles neu initialisieren muss. Nur ein paar 
Grundeinstellungen/Parameter müssen behalten werden, was man problemlos 
mit einem struct machen kann.

Christian J. schrieb:
> Wie erzeugt man denn so tolle Sachen wie EEPROM[Adresse] = .... ?

Überladung des []-Operators und des = Operators. Ist im Endeffekt auch 
nur ein Funktionsaufruf (ggf. mit ein paar Hilfsfunktionen).

von Oliver S. (oliverso)


Lesenswert?

Johann L. schrieb:
> #include <stdint.h>
>
> uintptr_t get_bss_start (void)
> {
>     extern char __bss_start[]; // Defined in linker script.
>     return (uintptr_t) __bss_start;
> }
> Dito für __bss_end.
>
> Allerdings ist der Ansatz nicht wirklich empfehlenswert: Falls der
> Inhalt von (statischen) Konstruktoren gesetzt wird, funktioniert das
> nicht mehr.

Warum eigentlich nicht?

Wenn man alles zwischen __data_start und __heap_start kopiert, sollte 
man doch eigentlich wirklich alles erwischen.

Oliver

von Christian J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Überladung des []-Operators und des = Operators. Ist im Endeffekt auch
> nur ein Funktionsaufruf (ggf. mit ein paar Hilfsfunktionen).

Nur ein Bastelgerät, was Bewegung, Temperaturen, Uhrzeit, Datum usw. 
aufzeichnet. Bisher lese ich alles manuell zurück aber wie schön 
einfacher wäre es doch wenn alles was geht auf einmal wieder da wäre, 
alle Zeiger auf Arrays usw. Die DS3231 usw. werden ja per Hand 
initialisiert. Es ist nur Spielerei, weil ich leidenschaftlich gern 
programmiere und Problemchen löse.

Ich werde das mit dem Code oben mal ausprobieren. Sehe es dann ja ob es 
klappt.

von Einer K. (Gast)


Lesenswert?

Oliver S. schrieb:
> Wenn man alles zwischen __data_start und __heap_start kopiert, sollte
> man doch eigentlich wirklich alles erwischen.

Leider nein!

Es fehlt eben der Heap.
Und ja, teilweise wird Speicher reserviert.
z.B. die SD Klassen tun das

Auch geht dir der Stack durch die Lappen.
Sowie alle Register. Ja, der Optimierer sorgt dafür, dass möglichst 
viele Daten in den Registern gehalten werden.
Ebenso sind die akuten Daten in externer Hardware dem Verlust preis 
gegeben.

Christian J. schrieb:
> weil ich leidenschaftlich gern
> programmiere und Problemchen löse.
Ich vermute, so machst du dir eher welche...
;-)


Christian J. schrieb:
> Wie erzeugt man denn so tolle Sachen wie EEPROM[Adresse] = .... ? Das
> geht nämlich beim Arduino und dahinter verbirgt sich dann der
> Schreibvorgang. Das EE wird aber wie ein Array angesprochen. Ich bin ja
> schon voll begeistert von den Stream Klassen, alles mit << und schon
> flutscht es rein in die Ausgabe.
Ja, das lohnt sich anzusehen!
Ein ganzer Eimer von Operatoren wird da überladen.
Viel interessanter/universeller, als das Array Access Interface, sind 
die get() und put() Methoden.

Lesenswert:
https://github.com/arduino/ArduinoCore-avr/blob/master/libraries/EEPROM/src/EEPROM.h

von Oliver S. (oliverso)


Lesenswert?

Arduino Fanboy D. schrieb:
> Leider nein!
>
> Es fehlt eben der Heap.

Dann halt bis heap-end, wobei das dann wiederum noch andere Maßnahmen 
nach sich ziehen dürfte, um den wieder aus der Kopie wieder 
herzustellen. Das ganze Konzept ist eh Murks, und hat natürlich seine 
Grenzen.

Aber hier gehts letztendlich um ein paar globale Zähler. Die landen 
nicht auf den heap.

Oliver

: Bearbeitet durch User
von Christian J. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:

Moin,

da Du dich ja sehr gut mit C++ auskennst und ich langsam Gefallen an 
einigen nützlichen Dingen finde nochmal ne Frage. Ich kriege das allein 
noch nicht hin.

Ich habe für den TSOP eine prima Übertragung zum PC hin. Bastelei sendet 
mit einer IR Diode und es schnurrt aufs Terminal. Wahlweise IR oder eben 
auf die UART. Mit Streaming.h und << klappt das gut. 8N1 Protokoll. 
Parity ginge aber auch.

Diese Sache möchte ich nun auch für den Empfang einsetzen:
IR-Diode >..... durch die Luft.....> TSOP -> Arduino rein. Und der Ardu 
decodiert das möglichst über eine Uart, entweder die RX0/TX0 oder eine 
Softserial, die aber auch INT gesteuert einen Buffer füllt, so dass ich 
etwas Zeit habe zu reagieren.

Wie sähe ein C++ Konstrukt aus, dass mir genau das macht?

Irgendwie etwas mit IRQuelle >> myVariable und einige Funktionen 
drumherum die den Umgang damit einfach machen?



struct IrSend_t: Print {
  virtual size_t write(uint8_t value) {
  SendIRByte(value);
  //Serial.write(value);
     return 1;
  }
};

von Einer K. (Gast)


Lesenswert?

Meinen Dank, für die Blumen.

Aber da hast du dir schon was vorgenommen......

Christian J. schrieb:
> Wie sähe ein C++ Konstrukt aus, dass mir genau das macht?
Unschön!

Eine ISR in einer Klasse unter zu bringen, ist nicht ganz trivial.
Auch darf man diese dann nur statisch nutzen, also nicht instanziieren, 
oder alternativ, sollte man sie zu einem Singleton machen, damit nix 
anbrennen kann.
Also alles in allem, gibt es zwar klare und saubere Lösungen, diese sind 
allerdings nicht "schön".

Das Singelton Design Pattern findest du z.B. bei Wikipedia beschrieben.
Wie man ISR in Klassen stopft, findest du hier:
https://www.mikrocontroller.net/articles/AVR_Interrupt_Routinen_mit_C%2B%2B

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.