Forum: Mikrocontroller und Digitale Elektronik Variable an definierte Adress im RAM schreiben


von Johannes (Gast)


Lesenswert?

Hallo,
weiß einer wo es bescrieben steht, wie ich eine Variable auf einer 
definierten Adresse erstellen kann? Hintergrund ist, dass ein TEil vom 
RAM bei einem Reset nicht gelöscht wird. Dort muss ich ein FLAG setzen, 
welches nach einem Reset abgefragt werden muss. Allerdings habe ich 
keine Ahnung, wie ich sagen kann, dass die Variable xy an Adresse xyz 
erstellt werden soll.

von abc. (Gast)


Lesenswert?

öhm, steht das nicht in der doku deines compilers?

von S. R. (svenska)


Lesenswert?

In C kannst du mit:
1
*(uint8_t*)0x1234 = 0x56

direkt auf eine Adresse schreiben.

von Einer K. (Gast)


Lesenswert?

Johannes schrieb:
> Allerdings habe ich
> keine Ahnung, wie ich sagen kann, dass die Variable xy an Adresse xyz
> erstellt werden soll.

Vielleicht möchtest du die Variable in der .noinit Section erstellen?
https://www.microchip.com/webdoc/AVRLibcReferenceManual/mem_sections_1sec_dot_noinit.html

von Matthias M. (Firma: privat) (quadraturencoder)


Lesenswert?

Du kannst das mit volatilen pointern machen. Volatil, damit der Compiler 
Dir nicht Deine Leseoperationen wegoptimiert, also z.B.:
1
  *(volatile uint8_t*)0x12345678u = 1; // write
2
  int var = *(volatile uint8_t*)0x12345678u; // read

Wenn Dir das zu hässlich ist, dann baust DU halt ein Define drumherum:
1
#define MY_VAR (*(volatile uint8_t*)0x12345678u)
2
3
  MY_REGISTER = 1;  // write
4
  int var = MY_REGISTER;  // read

Oder wenn Du mehrere Variablen hast und C++ verwendest, dann machst Du 
halt ne Klasse draus (wobei DU hier auch noch volatile setzen musst, so 
wie Dein compiler das zulässt):
1
class MyMem 
2
{
3
public:
4
  uint32_t somePort;
5
  uint32_t someOtherPort;
6
};
7
8
class MyMem *mem = (MyMem*)(uintptr_t)0x12345678;
9
10
mem->somePort = 100;
11
uint32_t data = mem->someOtherPort;

Du kannst auch weit auseinander liegende Speicherstellen so belegen, da 
ja Dein Klasse nie alloziert wird, also:
1
class MyMem 
2
{
3
public:
4
  uint32_t PORT_A;
5
  uint32_t offset_zu_b[1023]; // A, B und C sind 4096 bytes auseinander
6
  uint32_t PORT_B;
7
  uint32_t offset_zu_c[1023];
8
  uint32_t PORT_C;
9
};
10
11
class MyMem *mem = (MyMem*)(uintptr_t)0x12345678;

verbraucht 0 bytes Speicher.

von Sven P. (Gast)


Lesenswert?

Der eigentlich (fast) einzig sinnvolle Weg mit zeitgemäßen Compilern 
ist, das Symbol im Linkerskript festzunageln.

von Michael D. (nospam2000)


Lesenswert?

Matthias M. schrieb:

> class MyMem *mem = (MyMem*)(uintptr_t)0x12345678;

So legst du zwar die Speicheradresse fest, aber du allokierst sie nicht. 
Der Compiler/Linker könnte den Speicherbereich daher bereits anderweitig 
verwendet haben (wenn es sich um RAM und nicht um Hardware-Register 
handelt). Das gibt ganz tolle Fehler, viel Spass beim Suchen.

Sven P. schrieb:
> Der eigentlich (fast) einzig sinnvolle Weg mit zeitgemäßen Compilern
> ist, das Symbol im Linkerskript festzunageln.

Genau, zusammen mit dem attribut
1
section ("section-name")
siehe https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html

 Michael

von MatthiasM (Gast)


Lesenswert?

Michael D.

Ich habe die Variable absichtlich nicht alloziert, da solche Tricks ja 
eigentlich nur nötig sind, um auf Hardwareregister zuzugreifen, und dann 
wäre eine Allokation falsch.

Auch in allen anderen Fällen, die wohl eher nicht in den Mikrocontroller 
Bereich gehören, so wie Shared Memeory, MMU und DMA Aufgaben wäre der 
Speicher ja bereits anderweitig alloziert worden.

Aber wenn es da noch einen anderen Fall gibt, dann würde mich das sehr 
interessieren.

von Julian Mettler (Gast)


Lesenswert?

Wie Fanboy schon sagt. Du musst einfach eine Variable in der .noinit 
section anlegen.

von Rolf M. (rmagnus)


Lesenswert?

Sven P. schrieb:
> Der eigentlich (fast) einzig sinnvolle Weg mit zeitgemäßen Compilern
> ist, das Symbol im Linkerskript festzunageln.

Oder die beiden unterschiedlichen RAM-Bereiche in separate Sektionen zu 
stecken und beim Anlegen der Variablen die gewünschte Sektion anzugeben.

MatthiasM schrieb:
> Ich habe die Variable absichtlich nicht alloziert, da solche Tricks ja
> eigentlich nur nötig sind, um auf Hardwareregister zuzugreifen, und dann
> wäre eine Allokation falsch.

Die Variable soll nicht allokiert werden, sondern es muss sichergestellt 
sein, dass sie nicht im Pool, den der Compiler zur freien Verwendung 
hat, enthalten ist.

> Aber wenn es da noch einen anderen Fall gibt, dann würde mich das sehr
> interessieren.

Der steht doch im Ursprungsposting:

Johannes schrieb:
> Hintergrund ist, dass ein TEil vom RAM bei einem Reset nicht gelöscht
> wird. Dort muss ich ein FLAG setzen, welches nach einem Reset abgefragt
> werden muss.

von S. R. (svenska)


Lesenswert?

Julian Mettler schrieb:
> Wie Fanboy schon sagt. Du musst einfach eine Variable
> in der .noinit section anlegen.

Dann bekommt er eine nicht initialisierte Variable irgendwo im Speicher, 
aber ganz sicher nicht an der Stelle, an der er das Flag für den 
Bootloader setzen muss.

Dieser Vorschlag geht am Problem vorbei.

Ein Beispiel, um direkt in den Arduino "Caterina" Bootloader (AVR) zu 
springen:
1
#include <stdint.h>
2
#include <avr/wdt.h>
3
4
void __attribute__((noreturn)) bootloader(void) {
5
  *(uint16_t*)0x0800 = 0x7777;
6
  wdt_enable(WDTO_15MS);
7
  while(1);
8
}

von Einer K. (Gast)


Lesenswert?

S. R. schrieb:
> aber ganz sicher nicht an der Stelle, an der er das Flag für den
> Bootloader setzen muss.

Das ist ja eine lustige Anforderung....
Wie kommst du darauf?

Bisher war noch nicht mal von AVR die Rede...
Geschweige denn vom 32U4 oder Bootloader

von Rolf M. (rmagnus)


Lesenswert?

Arduino Fanboy D. schrieb:
> S. R. schrieb:
>> Dann bekommt er eine nicht initialisierte Variable irgendwo im
>> Speicher, aber ganz sicher nicht an der Stelle, an der er das Flag für
>> den Bootloader setzen muss.
>
> Das ist ja eine lustige Anforderung....
> Wie kommst du darauf?

Schauen wir uns die Frage des TO doch mal an:

Johannes schrieb:
> weiß einer wo es bescrieben steht, wie ich eine Variable auf einer
> definierten Adresse erstellen kann?

Da steht zwar nichts von einem Bootloader, aber dass die Variable an 
einer ganz bestimmten Adresse stehen soll.

von Einer K. (Gast)


Lesenswert?

Rolf M. schrieb:
> aber dass die Variable an
> einer ganz bestimmten Adresse stehen soll.

Dafür wurden Pointer erfunden! (wenn mich nicht alles täuscht)
Und die wurden hier schon durchgekaut.

von mh (Gast)


Lesenswert?

Matthias M. schrieb:
> verbraucht 0 bytes Speicher.

Und ist den meisten Fällen undefined behavior und wenn nicht darf der 
Compiler vermutlich alles wegoptimieren.

von Rolf M. (rmagnus)


Lesenswert?

Arduino Fanboy D. schrieb:
> Dafür wurden Pointer erfunden! (wenn mich nicht alles täuscht)
> Und die wurden hier schon durchgekaut.


Na also, jetzt bist du schon einen Schritt weiter. Mach noch einen, und 
dann bist du auch so weit, wie der Rest hier.

von Einer K. (Gast)


Lesenswert?

Rolf M. schrieb:
> Mach noch einen, und
> dann bist du auch so weit, wie der Rest hier.

Häää...

Bisher ist mir nur klar, dass eine Variable(besser: ihr Inhalt), einen 
Reset überleben soll.
Alles andere ist Kaffeesatzleserei.

Macht das, wenn es Spaß macht.....
Ich warte lieber auf etwas konkretere Informationen.

von Mach (Gast)


Lesenswert?

Beispiel unter FreePascal:
1
EineVariableMitAbsoluterAdresse : byte absolute $26;

von Rolf M. (rmagnus)


Lesenswert?

Arduino Fanboy D. schrieb:
> Rolf M. schrieb:
>> Mach noch einen, und
>> dann bist du auch so weit, wie der Rest hier.
>
> Häää...
>
> Bisher ist mir nur klar, dass eine Variable(besser: ihr Inhalt), einen
> Reset überleben soll.

Ich zitiere nochmal die initiale Frage des TO:

Johannes schrieb:
> weiß einer wo es bescrieben steht, wie ich eine Variable auf einer
> definierten Adresse erstellen kann?

Wenn ich dann davon ausgehe, dass er wissen will, wie er eine Variable 
auf einer definierten Adresse erstellen kann, würde ich das nicht als 
Kaffeesatzleserei bezeichnen.

von Einer K. (Gast)


Lesenswert?

Rolf M. schrieb:
> Ich zitiere nochmal die initiale Frage des TO:
Und ich zitiere den initialen Irrtum des TE.

Johannes schrieb:
> Hintergrund ist, dass ein TEil vom
> RAM bei einem Reset nicht gelöscht wird. Dort muss ich ein FLAG setzen,
> welches nach einem Reset abgefragt werden muss.

Zumindest in der AVR gcc Welt kann man davon ausgehen, dass Speicher bei 
einem Reset nicht gelöscht wird.

Allerdings werden (nicht lokale) Variablen üblicherweise initialisiert.
Nur eben nicht in der .noinit Section, woher sie ja auch ihren Namen 
hat.

Johannes schrieb:
> Allerdings habe ich
> keine Ahnung, wie ich sagen kann, dass die Variable xy an Adresse xyz
> erstellt werden soll.
Wenn man in C oder C++ eine Variable erstellt, bekommt sie auch einen 
Speicherplatz zugewiesen. Spätestens vom Linker.
Die Frage, warum dieser Variablen händisch eine Adresse vorgegeben 
werden muss, ist hier für mich noch nicht geklärt.
Könnte eine überflüssige Bedingung sein, basierend auf einer weiteren 
irrtümlichen Annahme, da ja der Compiler/Linker das durchaus selber 
erledigen kann.

Und muss es wirklich händisch sein, dann geht der Weg eben über Pointer

von S. R. (svenska)


Lesenswert?

Arduino Fanboy D. schrieb:
> Die Frage, warum dieser Variablen händisch eine Adresse vorgegeben
> werden muss, ist hier für mich noch nicht geklärt.

Einen möglichen Grund hatte ich genannt: Kommunikation mit dem 
Bootloader. Genau da tritt ein solches Problem auf und die Frage des TO 
in Bezug auf Reset lässt darauf schließen, dass es darum geht.

von Einer K. (Gast)


Lesenswert?

Also doch: Kaffeesatzleserei.

von S. R. (svenska)


Lesenswert?

Arduino Fanboy D. schrieb:
> Also doch: Kaffeesatzleserei.

Also ist es deiner Meinung nach besser, garnichts zu sagen und den TO 
allein stehen zu lassen, als eine möglicherweise passende Lösung zu 
posten.

Verstehe.

von Rolf M. (rmagnus)


Lesenswert?

Arduino Fanboy D. schrieb:
> Zumindest in der AVR gcc Welt kann man davon ausgehen, dass Speicher bei
> einem Reset nicht gelöscht wird.

Aha, und das ist also im Gegensatz zur Beantwortung der ursprünglichen 
Frage keine Kaffeesatzleserei?

von Einer K. (Gast)


Lesenswert?

S. R. schrieb:
> Also ist es deiner Meinung nach besser, garnichts zu sagen und den TO
> allein stehen zu lassen, als eine möglicherweise passende Lösung zu
> posten.
Nunja...
Offensichtlich habe ich das Gegenteil deiner Behauptung schon längst 
getan:

Arduino Fanboy D. schrieb:
> Vielleicht möchtest du die Variable in der .noinit Section erstellen?

Mir reicht das erstmal an Kaffesatzleserei...
Solange der TE nicht etwas mehr Information liefert.

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.