Forum: Mikrocontroller und Digitale Elektronik Struct an bestimmte Speicherstelle legen


von Le_Q (Gast)


Lesenswert?

Hallo Zusammen,

ich muss eine structur an einer spezifischen Speicheradresse anlegen. 
Ich glaube zu wissen wie es funktioniert, bin mir aber nicht sicher. 
Funktionieren tut es mal nicht. ;)

Der Folgende Code erzeugt eine Struktur die mit der Adresse 0xA2000000 
beginnend im Speicher (32 Bit) liegen soll. Folglich sollte der Member 
"Reg0" an Adresse A2000000 stehen und "Reg1" an 0xA2000001. Dies soll 
mir den einfachen Zugriff auf die sich an diesen Stellen im Speicher 
befindlichen Kontrollregistern für einen Controler ermöglichen. Somit 
sollte ich über die Struct die Register einfach lesen und schreiben 
können. (siehe letzte Codezeile)

1
typedef struct
2
{
3
   struct
4
   {      
5
      int32_t Reg0;
6
      int32_t Reg1;
7
   }subStruct;
8
   
9
   int32_t anderes;
10
} MYSTRUCT;
11
12
/* Pointer erzeugen und Anfang der Structure auf A2000000 setzten */
13
volatile MYSTRUCT *assignedStr;
14
assignedStr = (volatile MYSTRUCT *) 0xA2000000;
15
16
/* In Reg1 den Wert 33 schreiben */
17
assignedStr->subStruct.Reg0 = 2;
18
assignedStr->subStruct.Reg1 = 16;

Frage: Wieso funktioniert es nicht? Wo ist mein Denkfehler? Der Compiler 
(GCC) meckert nicht ich bekomme so aber nicht die Werte die in der 
Registern stehen sollten bzw. sehe keine Auswirkung wenn ich einen Wert 
schreibe.

Danke schon mal für eure Hilfe.

von (prx) A. K. (prx)


Lesenswert?

Le_Q schrieb:

> Der Folgende Code erzeugt eine Struktur die mit der Adresse 0xA2000000
> beginnend im Speicher (32 Bit) liegen soll.

Ein Hardware-Steuerregister ist nicht das, was man gemeinhin unter 
"Speicher" versteht. Auch wenn es im gleichen Adressraum wie Speicher 
liegt.

> Folglich sollte der Member
> "Reg0" an Adresse A2000000 stehen und "Reg1" an 0xA2000001.

Wenn das Zeug dort 32 Bits breit ist, dann liegt das zweite Register 
garantiert nicht an Adresse 0xA2000001. Und wenn es doch an dieser 
Adresse liegt, dann sind die Register nicht 32 Bits breit, sondern 8 
Bits.

Denn ich kann mich nicht erinnern, jemals von einer wortadressierenden 
32-Bit Maschine gelesen zu haben.

von arno nyhm (Gast)


Lesenswert?

http://stackoverflow.com/questions/682697/fixed-address-variable-in-c
...nimmt man die antworten dazu, ist das 'ne gute zusammenfassung!

für welches system programmierst du, welcher prozessor/architektur, 
speicherbereiche, ...?

ansonsten: schau' mal in den prozessorspezifischen headerdateien, wo die 
labels für z.b. andere register definiert werden; nichts anderes 
möchtest du ja auch tun.

von Le_Q (Gast)


Lesenswert?

Sorry das Register0 an 0 liegt und Register1 an 1 kann nicht sein. ;)

Ich arbeite auf nem Cortex-M3. In einen Adressraum ist der RAM eines 
externen Controllers (ne Steuerung) gemapped. In diesem RAM liegen ab 
Adresse 0x0 - 0x1F Konfigurationsregister dieses Controllers. Dieser 
SRAM ist für den Cortex in einem bestimmten Adressbereich sichtbar. 
Nehmen wir jetzt einfach mal an ab 0xA0000000. Dann ist es mir möglich 
diese Register zu lesen und zu schreiben. Das mache ich mit:
1
#define PUT_UINT32(addr, data)    (*((volatile INT32U *) (addr)) = (data))
2
#define GET_UINT32(addr, pData)   (*(pData) = *((volatile INT32U *) (addr)))
3
4
#define CTRL_REG0 0xA2000000
5
#define CTRL_REG1 0xA2000020
6
7
uint32_t data;
8
/* liest den Wert aus dem Register an 0xA2000000 aus.
9
GET_UINT32(CTRL_REG0, &data);
10
11
/* schreibt die Daten in das Register an Stelle 0xA2000000 */
12
PUT_UINT32(CTRL_REG0, data);

Und das funktioniert wunderbar. Ich kann somit die Register des 
Controllers konfigurieren, klappt alles super. Ich frage mich jetzt 
wieso kann ich den Speicherbereich bzw. den Adressraum an dem diese 
Register stehen nicht auf eine Struct "mappen" dann kann ich doch viel 
einfacher auf die Register zugreifen. Wenn ich für dieses Beispiel eine 
Structur, mit 2 32bit int, erzeuge und diese an Adresse 0xA2000000 lege, 
dann sollte das doch funktionieren?

Oder verstehe ich hier irgendwas nicht?


@ arno nyhm: Für den Controller den ich ansteuere gibt es leider keine 
Treiber. Aber eine gute Doku. Selber schreiben ist also kein Problem. :) 
Folglich gibts aber auch keine Symbole die schon in Treibern definiert 
sind.

von Le_Q (Gast)


Lesenswert?

Jetzt klappts... man muss die Variablen/member der Struct auch als 
volatile definieren.

Danke für eure Bemühungen mir zu helfen. :)

von (prx) A. K. (prx)


Lesenswert?

Le_Q schrieb:

> Wenn ich für dieses Beispiel eine
> Structur, mit 2 32bit int, erzeuge und diese an Adresse 0xA2000000 lege,
> dann sollte das doch funktionieren?

In der oben von dir definierten struct liegt Register 1 an 0xA2000004, 
nicht an 0xA2000020.

von Sven P. (Gast)


Lesenswert?

Man schlägt mich zwar generell dafür, aber ich halte die Predigt extra 
für dich nochmal:
Zeiger sind keine Adressen, auch wenn das vielen nicht in den Kram passt 
und aber und doch und blablabla.

Le_Q schrieb:
> ich muss eine structur an einer spezifischen Speicheradresse anlegen.
Warum musst du das? Das ist eigentlich eher untypisch.


> Der Folgende Code erzeugt eine Struktur die mit der Adresse 0xA2000000
> beginnend im Speicher (32 Bit) liegen soll.
Nein, er erzeugt zunächst eine beliebig geartete Struktur, die aus einer 
Unterstruktur und einer Zahl besteht. Zwischen alledem kann eine 
unbestimmte Zahl von Füllbytes liegen, wenn es der Compiler für Nötig 
hält, sodass du keinerlei Aussage darüber treffen kannst, was denn nun 
wo liegt.
Anschließend lässt du den Strukturzeiger irgendwohin in den Speicher 
zeigen, und zwar an die Stelle, die dein Compiler unter 'A2000000' 
versteht. Was er darunter versteht, musst du ihn fragen, er könnte die 
Zahl beispielsweise irgendwie in Segment- und Offset zerlegen. Der 
Zusammenhang zwischen der Ganzzahldarstellung eines Zeigers und der 
Speicheradresse der Daten, auf die er zeigt, ist beliebig und dem 
Compiler überlassen.

Kurzum: Ohne Architektur und Compiler zu kennen, wirst du mit deinem 
Versuch irgendwann aufs Maul fallen...

von Le_Q (Gast)


Lesenswert?

Gut aber was ist die elegante Art? Ich habe es jetzt bisher mit der 
Struktur implementiert. Mir sagt aber jeder das es unschön ist, weil man 
sich eben damit vom compiler abhängig macht.

Die "Füllbytes" kann man beim gcc mit attribute (_packed_) 
unterbinden. Wenn ich den Pointer auf die struct dann auf die Adresse 
0xA2000000 "mappe" funktioniert es. Ich habe sogar in Büchern etwas über 
diese "Strategie" gefunden... Aber hier liegt das Problem, wird der Code 
mit einem anderen Compiler übersetzt, kann es krachen. Bzw. der syntax 
für "packed" vom GCC wird z.B. auf einem Keil Compiler nicht 
funktionieren.

Die beste Lösung soll, so sagte man mir mehrfach, das Verwenden eines 
Byte-Arrays sein, dass man über den Speicher legt. Weil nur dann ist mit 
jedem compiler sichergestellt, dass wirklich jedes Byte so addressiert 
wird, wie es auch im speicher liegt, und keine "Füllbytes" dazwischen 
liegen. Nunja das mag sein, allerdings macht es dies doch extrem 
unübersichtlich? Wenn ich eine sehr große Struktur habe, die mir z.B. 
Daten die in einem Bestimmten Format im Speicher liegen, und diese dann 
nur noch Byte-weise in C ansprechen kann wird es doch sehr 
unübersichtlich... Da ist es doch schönder wenn ich sowas wie:
data[0]->header.type
Schreiben kann, anstatt byte[364].

Hoffe mein Problem wird klar. :)

Und noch zu der Aussage von Dir:
"Zeiger sind keine Adressen, auch wenn das vielen nicht in den Kram 
passt
und aber und doch und blablabla."

Die verstehe ich nur bedingt. Denn was ist ein Pointer? Es ist eine 
Speicherstelle, in der eine Referenz auf eine andere Speicherstelle 
gespeichert wird. So verhält es sich ja auch im Assembler wenn ich einen 
Pointer dereferenziere. Ich lade mir die Adresse des Pointers in ein 
Register und de-referenziere den Inhalt (hole den Inhalt aus dem 
referenzierten Register). Dann habe ich den Wert des Registers auf den 
der Pointer zeigt. Falls es Architekturen gibt, bei denen es anders ist, 
lasse ich mich gerne beleeren. Aber in meinen Augen ist ein Pointer eine 
Speicheraddresse, deren Wert eine andere Speicheradresse beinhaltet 
nämlich die auf die der Pointer zeigt.

Beispiel:
1
uint32_t * ptrHallo;    /* Wird vom compiler an irgend eine Stelle im speicher gelgt, z.B. 0x1000 0000 */
2
uint32_t var = 1;  /* Wird vom compiler an irgend eine Stelle im speicher gelegt z.B. 0x1000 0004 */
3
4
ptrHallo = &var; /* In die Speicherstelle 0x1000 0000 wird der Wert 0x10000004 geschrieben */

Aber genug von der Pointer-Theorie...



Hoffe Du oder jemand anders kann mir die eig. Frage beantworten. :)

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.