Hallo ihr GCC-Profis, ich will folgendes machen: Um das Programmieren mit einem ARM7-Mikrocontroller ein bisschen zu vereinfachen, dachte ich mir folgendes: Ich defineire für jedes Register, das der Controller hat, ein Bitfeld. Also bekommt z.B. das Register "PLLSTAT" ein Bitfeld, das wie folgt aussieht: struct stPLLStatus { int MSEL : 15; int NSEL : 8; int PLLE : 1; int PLLC : 1; int PLOCK : 1; } tstPLLStatus, *tpstPLLStatus; Dann definiere ich eine Variable vom Typ "tpstPLLStatus" (also ein Zeiger), der auf das entsprechende Register zeigt, ungefähr so: tpstPLLStatus test = (tpstPLLStatus)0xE01FC088; jetzt kann ich ja wunderbar auf die Bits zugreifen: test->MSEL oder test->PLOCK geht. ABER: Bei einigen Registern gibt es ja mitten drin ein oder zwei Bits, die nicht benötigt werden. Wie 'richte' ich jetzt die Bits in einem solchen Bitfeld aus, sodass alle an der richtigen Position sind? Weil, beim Beispiel oben wäre das Bit PLLE an der Position 23, in wirklichkeit ist es aber an Position 24. Zwischen MSEL und PLLE ist ein 'unused' Bit. Diese Bitfelder funktionieren also bis jetzt nur mit Registern, die keine 'unused' Bits haben.... Kann mir einer Verraten, ob mein Gedanke mit den Bitfeldern grundsätzlich funktioniert mit dem GCC und ob/wie ich das Bitfeld umschreiben muss, dass auch die nicht genutzten Bits mitgezählt werden? Der Vorteil von solchen Bitfeldern wäre natürlich, dass man nicht umständlich über Maskierungen und solchen Kram Bits bearbeiten muss, sondern schön auf die einzelnen Felder zugreifen kann. Das macht dann auch den Code besser lesbar ;-) Das ganze möchte ich mit GCC machen, und es soll auf einem ARM7 LPC2470 laufen. Vielen Dank, Schöne Grüsse
Für doch einfach Dummydaten ein. struct stPLLStatus { unsigned MSEL : 15; unsigned NSEL : 8; unsigned unused : 1; <---- unsigned PLLE : 1; unsigned PLLC : 1; unsigned PLOCK : 1; } tstPLLStatus, *tpstPLLStatus; Ich weiss jetzt auch nicht wie der gcc auf deine "int" in den bitfeldern reagiert, normal kenne ich das nur mit signed/unsigned
Das könnte so aussehen:
1 | typedef union |
2 | {
|
3 | struct
|
4 | {
|
5 | unsigned MSEL :15; // 0..14 |
6 | unsigned NSEL :8; // 15..23 |
7 | unsigned :1; |
8 | unsigned PLLE :1; // 24 |
9 | unsigned PLLC :1; // 25 |
10 | unsigned PLOCK :1; // 26 |
11 | unsigned :6; // 27..31 |
12 | } bits; |
13 | unsigned int reg; |
14 | } __attribute__((packed)) PLLStatus_t; |
15 | |
16 | #define PLL_STATUS (*((PLL_Status_t volatile *) 0x12345678))
|
Über .reg kann auf's ganze SFR gegriffen werden, über .bits auf einzelne Bit(felder). In GNU-C gehen auch anonyme Strukts, macht's etwas bequemer hinzuschreiben beim Codieren später (.bits kann entfallen), würd ich aber nicht empfehlen. Das volatile hab ich nicht in den Typ reingemacht, weil man manchmal mehrere Felder zu setzen hat, aber nur einen Zugriff haben will/darf. Dann kann man eine lokale Variable von dem Typ machen, ohne daß diese volatile ist; die Felder setzen, und schließlich alles zusammen per Zuweisung schreiben. Allerdings setzt das ganze eine gewisse Unterstützung durch den Compiler voraus, wenn du direkt Zugriffe codierst wie
1 | PLL_STATUS.PLLE = 1; |
(für avr-gcc zB gäbe ähnliche Konstrukte grottenüblen Code, weil er was Bits angeht noch hinzulernen muss. Da arm7-Entwickler nicht so rar sind wie für avr, wurde das bestimmt schon komplett beackert) Johann
Antwort auf Frage gab es ja bereits aber in dem Zusammenhang noch einen Nachtrag. Da das Thema in mal in anderen Forum aufkam, habe ich das mit den Regisiter-zu-Bitfeldern-Mapping vor einer ganzen Weile (wohl noch zu gcc 3.x-Zeiten) ausprobiert. Dabei wurden die Zugriffe über Bitfelderelemente zwar korrekt in ARM-Assemblercode umgesetzt, jedoch auch so optimiert, dass bei Bedarf auch nur Bytezugriffe erzeugt wurden. Sehr viele Hardwareregister beim seinerzeit verwendeten Controller (LPC2k, genauen Typ vergessen) dürfen aber nur als ganzes (32-bit) geschrieben/gelesen werden, folglich gab es eine Exception. Es gibt dazu auch entspr. Einträge im gcc Bugzilla. Es ist aber mglw. gar kein Fehler, da der Compiler den Quellcode m.M. schon korrekt umgesetzt hat. Kann ja nicht wissen, das die Hardware dies einschränkt. Der Ansatz mit den Bitfeldern mag zwar Tipparbeit sparen und etwas Übersicht schaffen, kann aber Verdruss bereiten. Portablen Code erzeugt man damit auf jeden Fall nicht. Falls die Idee aus Beispielquellcode für EWARM kommt: es gibt im IAR Compiler eine herstellerspezifische Erweiterung dafür. Wie anfangs geschrieben: Test sind schon eine Weile her, mglw. wurde in der zwischenzeigt etwas an impliziten Regeln für volatile (fehlt oben übrigens) verändert und/oder ein spezielles Attribut eingeführt.
@Johann L.: Genial! Vielen Dank :-) das sieht doch super aus! THX!
Bit Bastler wrote: > @Johann L.: > Genial! Vielen Dank :-) das sieht doch super aus! THX! Aber beachte das, was mthomas gesagt hat und ich mit "ob das der Compiler unterstützt" gemeint habe! Ich kann dir hier Tipps auf C-Ebene geben, aber nicht auf foo-gcc-Ebene. Vielleicht sind die Regionen, wo spezielle Zugriffsregeln herrschen, in gcc hinterlegt, und er weiß wie Zugriff auf SFRs sein soll. Auch vorstellbar, daß es über ne Section geht, hab ich auch mal gesehen: Die Section dient dann nur als Tag für den Zugriff; Objekte werden ja keine in der Section angelegt. Dadurch kann das in Headern codiert werden und muss nicht in gcc rein, was bei den 1000 arm-Derivaten bestimmt übel ist. Johann
Ha, eines meiner Lieblingsthemen! mthomas wrote: > Dabei wurden die Zugriffe über Bitfelderelemente zwar korrekt in > ARM-Assemblercode umgesetzt, jedoch auch so optimiert, dass bei > Bedarf auch nur Bytezugriffe erzeugt wurden. Ein ABI compliant Compiler darf das nicht. Der Zugriff muss auf den Container erfolgen. Bei Registern ist das üblicherweise ein 32-Bit Typ. Kompliziert wird es erst, wenn man Bitfeldstrukturen mit mehreren, ggf überlappenden, Containern definiert. > Der Ansatz mit den Bitfeldern mag zwar Tipparbeit sparen und etwas > Übersicht schaffen, kann aber Verdruss bereiten. Ja. Vor allem wenn man sich verzählt und damit versehentlich ein neuer Container aufgemacht wird :-) Ich bevorzuge Bitfelder trotzdem. Shift und Mask hat seine eigenen Probleme und sieht furchtbar aus. > Portablen Code erzeugt man damit auf jeden Fall nicht. Doch, solange man sich an ABI compliant Compiler hält. Was anderes sollte man für ARM ohnehin nicht verwenden. > Test sind schon eine Weile her, mglw. wurde in der zwischenzeigt > etwas an impliziten Regeln für volatile (fehlt oben übrigens) > verändert und/oder ein spezielles Attribut eingeführt. Das ist ebenfalls alles im AAPCS (Teil des ABI) detailliert ausgeführt. Gruß Marcus http://www.doulos.com/arm/
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.