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
typedefstruct
2
{
3
struct
4
{
5
int32_tReg0;
6
int32_tReg1;
7
}subStruct;
8
9
int32_tanderes;
10
}MYSTRUCT;
11
12
/* Pointer erzeugen und Anfang der Structure auf A2000000 setzten */
13
volatileMYSTRUCT*assignedStr;
14
assignedStr=(volatileMYSTRUCT*)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.
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.
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.
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:
/* 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.
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.
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...
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. :)