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
Ü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.
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/