Hallo,
ich bin/war nun eine ganze Zeit aus der AVR-Programmierung raus und
steige nun wieder mit einem Projekt ein - zuvor verwendete ich die zu
diesem Zeitpunkt (vor zwei, drei Jahren?!) normale Vorgehensweise:
eigenständige WinAVR-Installation die mit den, in einem beliebigen
Editor erstellten, Ausgangsdaten per Makefile gefüttert wird.
Inzwischen hat sich das 'AVR Studio' ja zum 'Atmel Studio' entwickelt
und bringt seinen eigenen AVR-GCC gleich mit; 'Atmel Studio 6.0' läuft
nun auch bei mir und ich finde es soweit auch ganz gut - bin zügig dabei
mich einzuarbeiten.
Nun zu meiner eigentlich Frage: 'Früher' war die Nutzung von Bitfeldern
im WinAVR/AVR-GCC ja ziemlich nutzlos, da sie nicht entsprechend
umgesetz wurden - inzwischen ließt man öfter (auch hier im
AVR-GCC-Tutorial) über Bitfelder ohne jeglichen Hinweis, dass diese
eigentlich Nutzlos sind, da sie nicht entsprechend vom Kompiler
umgesetzt werden - auch habe ich schon ELF-Files mit entsprechendem Code
gesehen, in dem eine Bitfeld-Struktur korrekt umgesetzt wurde. Hier
z.B.: Beitrag "AVR-gcc und Bitfelder"
Kann der AVR-GCC inzwischen besser mit Bitfeldern umgehen?
Werden entsprechende Bitfelder im IO-Bereich mit eintaktigen
sbi/cbi-Assemblerbefehlen umgesetzt (sieht ja ganz so aus, in dem eben
genannten Forenbeitrag) und außerhalb des IO-Bereich mit entsprechenden
Bitmanipulationen ('x |= y', 'x &= ~y') auf Byte-Ebene?
Ich sach mal, Versuch macht kluch...
Wenn du das Studio doch schon installiert hast, probier es halt einfach
aus. Ändern kannst du an dem Ergebnis dann eh nichts.
Oliver
Sascha W. schrieb:> 'Früher' war die Nutzung von Bitfeldern> im WinAVR/AVR-GCC ja ziemlich nutzlos, da sie nicht entsprechend> umgesetz wurden
Das war schon immer Quatsch.
Was allerdings bezüglich Bitfeldern stimmt ist, dass die Reihenfolge
der Bits "implementation-defined" ist, d. h. entsprechender Code ist
nicht portabel und kann selbst für den gleichen Prozessor (also AVR
in diesem Falle) bei einem anderen Compiler genau andersrum
implementiert sein.
Außerdem ist es "implementation-defined", was passiert, wenn ein
Bitfeld eine Grenze der kleinsten allozierbaren Einheit überspannt,
aber das war beim AVR meines Wissens noch nie ein Thema, da er
keinerlei Alignment-Anforderungen seitens der CPU hat.
Solange das kein Problem ist, sind Bitfelder benutzbar und waren es
schon immer, auch "früher".
Es gibt in der avr-libc sogar einen Controller, bei dem die Register
über Bitfelder zugreifbar sind: der ATmega128RFA1. Das hat den
Vorteil, dass man nicht mehr Gefahr läuft, das Bit in einem völlig
falschen Register zu setzen. Leider hat sich diese Sichtweise
innerhalb von Atmel nicht durchgesetzt, alle anderen AVRs bieten
derartiges nicht an. (Außerdem ist Atmel im Moment sowieso mächtig
ins Hintertreffen gekommen, die Unterstützung für ihre neueren
AVRs mal in die offizielle avr-libc zurück zu füttern.)
Jörg Wunsch schrieb:> Solange das kein Problem ist, sind Bitfelder benutzbar und waren es> schon immer, auch "früher".
Dann ist die Aussage, dass 'früher' für jeden einzelnen Bezeichner im
Bitfeld eine eingene, ein ganzes Byte breite, Variable vom Compiler
angelegt wurde also aus der Luft gegriffen/unwahr? Eben dies habe ich
nämlich dazu gelesen.
Das mit der 'implemention-defined' bezüglich der Anordnung der Bits
macht mein (experimentelles) Vorhaben wohl doch gefährlich, ich habe
daran gedacht mir eine Bitfeld-Struktur über ein GPIO-Portregister zu
mappen um die Portpins, mit Klartext-Namen versehen, bequem, wie
Variablen, ansprechen zu können:
1
#define PortA (*(PortA_t*)&PORTA)
2
3
...
4
5
typedef struct
6
{
7
unsigned OutLedStatur:1;
8
unsigned OutLedTrigger:1;
9
unsigned OutMotorPhaseA:1;
10
unsigned OutMotorPhaseB:1;
11
} PortA_t;
12
13
PortA_t PortA;
14
15
...
16
17
PortA.OutLedStatus = 1;
18
PortA.OutLedTrigger = 0;
War aber wohl eher eine fixe Idee, je mehr ich darüber Nachdenke, desto
schwieriger/sinnfreier erscheint es - auch die Trennung von
Ein-/Ausgängen in PORTx/PINx-Register macht es nicht besser mit dieser
Umsetzung. Schon die Tatsache, dass nicht direkt klar ist ob der erste
Eintrag im Bitfeld dem LSB oder MSB entspricht macht es heikel - wenn
dies aber nicht einmal irgendwo definiert ist, wie es zu sein hat, ist
es nicht sinnvoll für diesen Zweck zu gebrauchen.
Bleibt es wohl das beste per #define festgelegte Konstanten für die
jeweiligen Bits (PA1, PA2, ...) zu benutzen.
Vielen Dank für den Hinweis, Jörg!
Grüße
Sascha
Ich kenne die AVR nicht, aber hier aus einem PIC C-Manual:
> The convention in the processor header files is that each SFR is> named, using the same name that appears in the data sheet for the> part – for example, CORCON for the Core Control register. If the> register has individual bits that might be of interest, then> there will also be a structure defined for that SFR, and the name> of the structure will be the same as the SFR name, with “bits”> appended. For example, CORCONbits for the Core Control register.> The individual bits (or bit fields) are named in the structure using> the names in the data sheet – for example PSV for the PSV bit of the> CORCON register. Here is the complete definition of CORCON
> The symbols CORCON and CORCONbits refer to the same register and> will resolve to the same address at link time.
Ich denke, so was meinst du. Ich gebe dann via #define den Portbits in
meiner Schaltung noch passende Namen.
MfG Klaus
Sascha W. schrieb:> Dann ist die Aussage, dass 'früher' für jeden einzelnen Bezeichner im> Bitfeld eine eingene, ein ganzes Byte breite, Variable vom Compiler> angelegt wurde also aus der Luft gegriffen/unwahr? Eben dies habe ich> nämlich dazu gelesen.
Ich kann mich nicht erinnern, ein solches Verhalten jemals gesehen, noch
darüber gelesen zu haben. Du hast da nicht zufällig was mit dem Debugger
des AVR-Studios zusammengewürfelt, der bei der Anzeige von Bit-Feldern
das Problem hatte, für jedes Element immer den ganzen Container
anzuzeigen?
Sascha W. schrieb:> Das mit der 'implemention-defined' bezüglich der Anordnung der Bits> macht mein (experimentelles) Vorhaben wohl doch gefährlich,> ...> Schon die Tatsache, dass nicht direkt klar ist ob der erste> Eintrag im Bitfeld dem LSB oder MSB entspricht macht es heikel - wenn> dies aber nicht einmal irgendwo definiert ist, wie es zu sein hat, ist> es nicht sinnvoll für diesen Zweck zu gebrauchen.
Es ist definiert. "implemention-defined" bedeutet, dass der Compiler es
definiert. Und das bedeutet wiederum, dass er feste Regeln diesbezüglich
aufstellen und dokumentieren muss, und sich dann natürlich auch an seine
eigenen Regeln halten muss. "Gefährlich" ist es also nur in Bezug auf
die Portierbarkeit. Natürlich besteht auch rein theoretisch die Gefahr,
dass der selbe Compiler seine Regeln von einer Version zur anderen
ändert, aber warum sollte er das tun? Diese "Gefahr" ist also praktisch
Null.
PS: In deinem Code-Beispiel hast du dir übrigens das volatile des
Registers weggecastet, was natürlich eine ganz schlechte Idee ist.
Sascha W. schrieb:> ich habe> daran gedacht mir eine Bitfeld-Struktur über ein GPIO-Portregister zu> mappen um die Portpins, mit Klartext-Namen versehen, bequem, wie> Variablen, ansprechen zu können:
Ist letztlich ziemlich genau das, was in <avr/iom128rfa1.h> für
alle IO-Register (optional) angeboten wird. Dort kann man eben
schreiben:
1
TRXPR_struct.slptr=1;
als Alternative zu
1
TRXPR|=(1<<SPLTR);
Würde man stattdessen sich beispielsweise verschreiben und versuchen:
1
TRX_CTRL_0|=(1<<SLPTR);
hat der Compiler keine Ahnung, dass man auf das falsche Register
zugreift. Versucht man aber:
1
TRX_CTRL_0_struct.slptr=1;
dann wird einem der Compiler mitteilen, dass das so nicht geht.
Jörg Wunsch schrieb:> dann wird einem der Compiler mitteilen, dass das so nicht geht.
und die IDE wird einem beim Schreiben die verfügbaren Bits oder Felder
anbieten.
MfG Klaus
Klaus schrieb:> und die IDE wird einem beim Schreiben die verfügbaren Bits oder Felder> anbieten.
Da bin ich mir nicht ganz so sicher, denn sie müsste dann den
dahinter liegenden Mischmasch aus struct-Definition, typecast,
#define, Zeigerbildung und -dereferenzierung durchschauen. Ganz
schön viel Anforderung für ein bisschen IDE.
Mal eine Frage.
Wer generiert eigentlich die C-Header Files?
Die werden/wurden ja meines Wissens aus den Atmel XML Part Description
Files generiert. Früher war das wohl Teil der WinAvr Generierung. Macht
Atmel das heute selber?
Hintergrund.
Ich hab mir mal ein paar entsprechende Part Description Files angesehen.
Noch aus dem 4-er Studio. So schlimm dürfte das jetzt nicht sein, da
automatisch für jeden Prozessor ein Header File mit entsprechenden
Strukturdefinitionen zu erzeugen.
Denn eines muss man schon sagen: Es hätte durchaus was für sich, wenn
man derartige Strukturen hätte. Alleine die Absicherung, dass das
entsprechende Bit auch wirklich im Register liegt wäre die Sache schon
wert.
Karl Heinz Buchegger schrieb:> Ich hab mir mal ein paar entsprechende Part Description Files angesehen.> Noch aus dem 4-er Studio. So schlimm dürfte das jetzt nicht sein, da> automatisch für jeden Prozessor ein Header File mit entsprechenden> Strukturdefinitionen zu erzeugen.
Das ist sogar ziemlich einfach. Vor allem, wenn man dann auch noch die
xml-Files des Studio 5 oder 6 mit benutzt. Deren Format ist etwas
ausführlicher. Das sollte bis auf die Korrektur der in den xml-Files
vorkommenden Fehler automatisiert machbar sein.
Ich hatte vor einer Weile mal angefangen, mit den Open-Source
AVR-Simulatoren etwas rumzubasteln, und mir dafür auch einen
rudimentären XML-Umsetzer geschrieben, der was so etwas ähnliches
generiert.
Oliver
Karl Heinz Buchegger schrieb:> Wer generiert eigentlich die C-Header Files?> Die werden/wurden ja meines Wissens aus den Atmel XML Part Description> Files generiert. Früher war das wohl Teil der WinAvr Generierung. Macht> Atmel das heute selber?
Die ersten waren alle handgefeilt. Das lässt sich zumindest für
alle die, die auch noch SIG_*-Vektornamen anbieten, praktisch auch
kaum ändern, d. h. diese kann man auch heute nich auf einfache
Weise neu generieren. (Das liegt daran, dass die SIG_*-Namen mehr
oder minder "nach Bauchgefühl" benannt worden sind und nicht direkt
aus den XML-Daten ableitbar sind, zumindest nicht 100%ig.) Kommt
hinzu, dass einige dieser Files eine Rückwärtskompatibilität zu
früheren Versionen mitschleppen (wollen), die dann entsteht, wenn
ein Register mal in einer späteren Datenblattversion (und damit im
XML) umbenannt worden ist.
Kurz und gut: für all diese gäbe es keine Chance, sie einfach mit
wenig Aufwand neu zu generieren.
Neuere Dateien hat Eric dann mit einem Script aus den Studio-4-XMLs
generiert, aber danach haben sie bezüglich avr-libc (und beispiels-
weise Schreibfehlern oder Registerumbenennungen) ggf. ebenfalls ein
"Eigenleben" entwickelt. Müsste man sich also von Fall zu Fall
ansehen, ob das sich ergebende automatisch generierte File abzüglich
der hinzugefügten Registerstrukturen dann noch mit der existierenden
Version übereinstimmt.
Die, die Atmel Studio mit ausliefert, sind dem Vernehmen nach bei
Atmel aus dem Studio-5/6-XML generiert, aber seit dem Weggang von
Anitha Boyapathi von Atmel ist die Zusammenarbeit der zuständigen
Atmel-Entwickler mit dem avr-libc-Team leider praktisch vollständig
abgerissen. :-(
Jörg Wunsch schrieb:> Kurz und gut: für all diese gäbe es keine Chance, sie einfach mit> wenig Aufwand neu zu generieren.
Ich hab jetzt auch nicht daran gedacht, die bisherigen Header über Bord
zu werfen. Die könnten ruhig weiter bestehen.
Ich hab mir das eher so vorgestellt, dass es ein weiteres Include File
gibt, in dem die Register in Bitstrukturen aufgeschlüsselt werden.
Eventuell wäre es sogar möglich, zb für Timer sowas wie gefakte
Strukturen zu bauen, so dass man schreiben kann
_Timer1_CS00 = 1;
und durch die Definitionen schlüsselt sich das selber in die richtigen
Register auf. Die entsprechenden Informationen wären in den XML
vorhanden, was ich so gesehen habe.
Ein Mechanismus, ähnlich dem io.h sorgt dann für die entsprechende
Verteilung des Include auf den konkreten Register Header.
1
#include<avr/io.h>
2
#include<avr/io_reg.h>
3
4
5
intmain()
6
{
7
_PortB.b0=1;
8
}
> Die, die Atmel Studio mit ausliefert, sind dem Vernehmen nach bei> Atmel aus dem Studio-5/6-XML generiert, aber seit dem Weggang von> Anitha Boyapathi von Atmel ist die Zusammenarbeit der zuständigen> Atmel-Entwickler mit dem avr-libc-Team leider praktisch vollständig> abgerissen. :-(
Schade.
Denn: Machbar wäre das schon. Nur macht es nur dann wirklich Sinn, wenn
man es als eine Art Standard etablieren kann. Am besten wär natürlich,
wenn auch Atmel da mit am Strang ziehen würde.
Was denkt ihr? Würde es Sinn machen, da sowas wie einen µC.Net
'Standard' zu kreieren und zu versuchen den zumindest hier bzw. auf
AVRFreaks zu pushen?
Karl Heinz Buchegger schrieb:> Was denkt ihr? Würde es Sinn machen, da sowas wie einen µC.Net> 'Standard' zu kreieren und zu versuchen den zumindest hier bzw. auf> AVRFreaks zu pushen?
Fände ich absolut sinnvoll.
Jörg Wunsch schrieb:> Da bin ich mir nicht ganz so sicher, denn sie müsste dann den> dahinter liegenden Mischmasch aus struct-Definition, typecast,> #define, Zeigerbildung und -dereferenzierung durchschauen. Ganz> schön viel Anforderung für ein bisschen IDE.
Wenn ich die Werte aus den struct-Definitionen verwende, geht das. Bei
allem, was man hinter #defines "versteckt" nicht, da hast du recht. Aber
um ein komplexes Peripheral zu initialisieren, wo man sich die #defines
kneift, da es nur einmal im Code vorkommt, ist es hilfreich. Auch beim
Schreiben der #defines sieht man sofort, ob ein Portbit auch wirklich
implementiert ist.
Ich spreche aber hier von MPLABX, die AVR-Umgebung kenne ich nicht. Und
Microchip liefert für wirklich jeden ihrer Chips diese Headerfiles, und
da das explizit in der Doku des Compilers erwähnt wird, gehe ich davon
aus, daß das auch für zukünftige Chips so sein wird.
MfG Klaus
Karl Heinz Buchegger schrieb:> Was denkt ihr? Würde es Sinn machen, da sowas wie einen µC.Net> 'Standard' zu kreieren und zu versuchen den zumindest hier bzw. auf> AVRFreaks zu pushen?
Wäre gut - wenn man sich grundlegend schon die Arbeit einer solchen
Implementierung macht ist es auch sinnvoll einen Quasistandard zu
nutzen.
Genau das von Euch näher beschriebene ist ja auch mein Wunsch - eben nur
mit dem Unterschied, dass ich mir statt der prozessororientierten
Bennenung der Bits eine funktionale angedacht habe.
Der Unterschied ist ja aber nur gering bzw. eine funktionale Bennung
ließe sich ja nachträglich noch im jeweiligen Projekt hinzufügen.
Ich fände es jedenfalls parktisch eben über benannte Strukturen auf die
einzelnen Bits der Prozessorregister zuzugreifen, nicht nur der
Sicherheit bei der Entwicklung die richtigen Bits im richtigen Register
zu setzen halber, sondern auch wegen der besseren Lesbarkeit.