mikrocontroller.net

Forum: Compiler & IDEs GPIOR-Register 16-bit


Autor: ** Lötlackl (pappnase) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe hier in einem Programm auf einem attyni2313 den Bedarf eines 
Flagbytes und einer 16-bit globalen Variablen. Fein, dachte ich, 
versuchen wir's mal so:
typedef struct {
   uint8_t speed_ok:1;
   uint8_t disp_act:1;
} FlagByte_TypeDef;

#define flagbyte  (*(volatile FlagByte_TypeDef *)(&GPIOR0))
#define pulsetime (*(volatile uint16_t *)(&GPIOR1))
Damit hätten wir GPIOR1 und GPIOR2 zusammengefaßt, geht sogar. Aber: 
ist's so auch richtig?

mfg

Autor: Grrrr (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alias Lötlackl schrieb:
> Aber:
> ist's so auch richtig?

Verzeihe bitte die Ironie:

Ist das das Fach "Theoretische Programmierung"? Oder ist der Compiler 
heute nacht irgendwie stromlos geworden?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alias Lötlackl schrieb:
> Ich habe hier in einem Programm auf einem attyni2313 den Bedarf eines
> Flagbytes und einer 16-bit globalen Variablen.

Warum zum Geier[tm] müssen die unbedingt in einem IO-Register
liegen?

Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg

Die GPIO-Register sind doch von Atmel extra dafür gedacht, um globale 
Variablen zu speichern und um auf einzelne Bits in diesen zugreifen zu 
können.

"This is a general purpose register that can be used to store data such 
as global variables in the bit accessible I/O memory space."

Auszug aus dem Datenblatt vom AtXMega, beim AtTiny wird es wohl nicht 
anders sein.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
netb schrieb:
> Die GPIO-Register sind doch von Atmel extra dafür gedacht, um globale
> Variablen zu speichern und um auf einzelne Bits in diesen zugreifen zu
> können.

Kann ja sein, aber das heißt doch nicht, dass das der einzige
Weg wäre, um eine simple globale Variable unterzubekommen.  Normal
lässt man die einfach erstmal da, wo sie der Compilter hinpackt:
im unteren Bereich des SRAMs.

So ein GPIOR benutzt man bestenfalls dann mal, wenn es wirklich beim
Zugriff auf jeden Takt ankommt, sodass es Sinn hat, die Möglichkeiten
der Befehle CBI/SBI/SBIS/CBIS auszunutzen, weil man vielleicht dann
in einer ISR ein paar push/pop-Befehle dadurch einspart.

Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun ja, die AtTinys sind ja nun nicht gerade reicht mit SRAM gesegnet, 
da machen solche extra Register durchaus mehr Sinn als im AtXMega. Aber 
der Vorteil der schnellen Bitadressierung ist auch dort nicht zu 
verachten.

Grundsätzlich ist es ja nicht falsch die Möglichkeiten zu nutzen, die 
Atmel einem da bietet. Man erkauft es sich halt durch eine stärkere 
Gebundenheit des Programmes an diese eine Architektur von µC, die diese 
Register aufweisen.

Autor: ** Lötlackl (pappnase) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Sinnhaftigkeit der Verwendung lasse ich mal dahingestellt.
Meine Frage ging eigentlich dahingehend, wie man den Ausdruck mit den 
vielen Sternchen eigentlich zu verstehen hat (Der Adressoperator ist mir 
auch nicht entgangen). Ist schon blöd, wenn man nicht wirklich weiß, was 
man da so macht.

mfg

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alias Lötlackl schrieb:

> Meine Frage ging eigentlich dahingehend, wie man den Ausdruck mit den
> vielen Sternchen eigentlich zu verstehen hat

Wo sind denn da viele Sterne?
Das ist ein ganz normales Umcasten eines Pointers auf einen anderen 
Datentyp-Pointer und Zugriff über den umgecasteten Pointer.

Wenn dir das Schwierigkeiten macht, dann
* lass die GPdingsda Register erst mal links liegen
* lies ein C-Buch

> Ist schon blöd, wenn man nicht wirklich weiß, was
> man da so macht.

Noch ein Grund mehr zu einem C-Buch zu greifen und die Grundlagen zu 
lernen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
netb schrieb:
> Aber
> der Vorteil der schnellen Bitadressierung ist auch dort nicht zu
> verachten.

Der Versuch, da eine 16-bit-Variable reinzulegen, führt diese Idee
(die eigentlich der Anlass für die GPIORs überhaupt war) komplett
ad absurdum.

Autor: netb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Der Versuch, da eine 16-bit-Variable reinzulegen, führt diese Idee
> (die eigentlich der Anlass für die GPIORs überhaupt war) komplett
> ad absurdum.

Keine Ahnung, was der Threadersteller nun damit vor hat. Gibt es denn 
aus deiner Sicht einen guten Grund diese Register nicht zu benutzen?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
netb schrieb:
> Gibt es denn
> aus deiner Sicht einen guten Grund diese Register nicht zu benutzen?

Code obfuscation.  Der Quellcode wird unnötig kompliziert.  Ich
würde daher auf das GPIOR nur zurückgreifen, wenn es entweder auf
die zwei Byte wahrhaftig ankommt, oder aber für Fälle, wo die GPIORs
ihren eigentlichen Vorteil der Bitadressierbarkeit ausspielen können
(also z. B. für Flags in der Kommunikation zwischen ISR und dem
Rest der Applikation).

Autor: ** Lötlackl (pappnase) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Code obfuscation.  Der Quellcode wird unnötig kompliziert.  Ich
> würde daher auf das GPIOR nur zurückgreifen, wenn es entweder auf
> die zwei Byte wahrhaftig ankommt, oder aber für Fälle, wo die GPIORs
> ihren eigentlichen Vorteil der Bitadressierbarkeit ausspielen können
> (also z. B. für Flags in der Kommunikation zwischen ISR und dem
> Rest der Applikation).

Vor allem geht es mir um's Verständnis. Ob ich diese Register in meinem 
Programm nun wirklich unbedingt benötige, oder aber nur (für mich) neues 
probieren will, sollte eigentlich absolut keine Rolle spielen! Antworten 
like

Karl heinz Buchegger schrieb:
> Wenn dir das Schwierigkeiten macht, dann
> * lass die GPdingsda Register erst mal links liegen
> * lies ein C-Buch

sind dann natürlich nicht sonderlich hilfreich, selbst in 
Kernighan&Ritchie werden solch verschachtelten Konstrukte nicht 
unbedingt aufgelöst.
Ich lese hier schon 'ne ganze Weile mit, aber solche Antworten von einem 
ansonsten immer hilfsbereiten Karl heinz Buchegger geht mir dann schon 
irgendwie auf die Eier. Es tut mir ja wirklich leid, aber 'ne sachliche 
Erklärung dieses (aus meiner Sicht wild verschachteltem) geCaste hätte 
mir völlig genügt.

mfg

PS: mache sowas nicht beruflich, bin eher der "lonely home hacker", 
sozusagen Extremhobby, you know?

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
** Lötlackl schrieb:
> Antworten like
>
> Karl heinz Buchegger schrieb:
>> Wenn dir das Schwierigkeiten macht, dann
>> * lass die GPdingsda Register erst mal links liegen
>> * lies ein C-Buch
>
> sind dann natürlich nicht sonderlich hilfreich, selbst in
> Kernighan&Ritchie werden solch verschachtelten Konstrukte nicht
> unbedingt aufgelöst.

Die sind aber auch nur Kombinationen aus mehreren einfacheren 
Konstrukten. Du wirst kein Buch finden, wo jeder mögliche C-Konstrukt im 
Detail erklärt wird. Deshalb ist es besser, die Grundlagen zu kennen, 
damit man damit dann selbst so einen Konstrukt auflösen kann. Und das 
steht garantiert in diesem Buch drin.

> Ich lese hier schon 'ne ganze Weile mit, aber solche Antworten von einem
> ansonsten immer hilfsbereiten Karl heinz Buchegger geht mir dann schon
> irgendwie auf die Eier.

Das liegt daran, daß du die Antwort nicht verstanden hast.

> Es tut mir ja wirklich leid, aber 'ne sachliche Erklärung dieses (aus
> meiner Sicht wild verschachteltem) geCaste hätte mir völlig genügt.

Du kennst dieses Sprichwort à la "teach a man to fish"?

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
** Lötlackl schrieb:
> Es tut mir ja wirklich leid, aber 'ne sachliche
> Erklärung dieses (aus meiner Sicht wild verschachteltem) geCaste hätte
> mir völlig genügt.

Der Fall oben ist aber nicht wild verschachtelt, das ist eine einfache 
Dereferenzierung eines gecasteten Pointers. Dieser Fall sollte in jedem 
halbwegs brauchbaren C-Buch behandelt werden.

Für wirklich "haarige" Sachen gibt es Tools, z.B. cdecl (ursprünglich 
Commandline, online benutzbar unter http://www.cdecl.org/):
cdecl> explain int (*foo(int (*[])(), int))()
declare foo as function (array of pointer to function returning int, int) returning pointer to function returning int
cdecl> declare foo as function (bar as array of pointer to function returning int, idx as int) returning pointer to function returning int
int (*foo(int (*bar[])(), int idx))()

Andreas

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Ferber schrieb:
> Der Fall oben ist aber nicht wild verschachtelt, das ist eine einfache
> Dereferenzierung eines gecasteten Pointers. Dieser Fall sollte in jedem
> halbwegs brauchbaren C-Buch behandelt werden.
>
> Für wirklich "haarige" Sachen gibt es Tools, z.B. cdecl (ursprünglich
> Commandline, online benutzbar unter http://www.cdecl.org/):

Naja, einen C-Ausdruch anstatt in einen abstrakten Syntaxbaum nach 
Englisch zu parsen ist nicht wirklich erhellend...

Konkret scheint das cdecl für das obige Konstrukt etwas überfordert. 
Gehen wir aus vom einem C-Beispiel wie
#include <avr/io.h>

#define pulsetime (*(volatile uint16_t *)(&GPIOR1))

void foo ()
{
    pulsetime = 0;
}

gelangt man zunächst zu der netten Zeile
(*(volatile uint16_t *)(&(*(volatile uint8_t *)((0x14) + 0x20)))) = 0;
die im cdecl.org in allen Varianten zu einem Syntaxfahler führt -- auch 
ohne die Zuweisung und mit unsigned short für uint16_t etc. 
(Ersetzungen, die für avr-gcc nichtmal zutreffen. Was da an Text 
raussprudeln würde ... naja.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
** Lötlackl schrieb:

> sind dann natürlich nicht sonderlich hilfreich, selbst in
> Kernighan&Ritchie werden solch verschachtelten Konstrukte nicht
> unbedingt aufgelöst.

Was ist da drann verschachtelt?

Wenn

   int*  pI;

pI ein Pointer auf einen int ist, dann bekommt man mit

   *pI

den Wert, also den Integer, auf den pI zeigt. Stink normale Pointer 
Dereferenzierung. Steht in jedem Buch.

Jetzt haben wir keinen Pointer sondern eine Variable.

   int a;

mittels

   &a

bekommt man die Adresse der Variablen, vulgo einen Pointer auf a.
Steht auch in jedem Lehrbuch.

   *&a;

liefert daher den Inhalt von a. Denn wortwörtlich steht da

     a              nimmm a
    &a              die Adresse von a
   *&a              hol den Wert, der sich an der Adresse von a
                    verbirgt.

Nun, der Wert der an der Adresse von a steht, das ist der Wert von a.

Das steht so vielleicht nicht in einem Lehrbuch, wenn man aber die 
beiden Konzepte des Derefernzierungs-* und des Adressoperators 
verstanden hat, sollte man eigentlich keine Schwierigkeiten haben, die 
beiden Konzepte zu verbinden.

Das ist ungefähr so, wie jedem Volksschüler relativ bald klar ist, dass

     9 * 5 / 5

wieder 9 ergibt, weil / die Umkehrung der Multiplikation ist.

Das einzige was man sich in C angewöhnen muss, ist: solche Ausdrücke 
immer beim Variablennamen anfangen auseinanderzunehmen. Das steht so 
vielleicht nicht in deinem Lehrbuch.
Und das '*&irgendwas' ein sinnvolles Konstrukt ist und gleichwertig zu 
'irgendwas' ist, während '&*irgendwas' kein sinnvolles Konstrukt ist, 
weil ein Wert per se erst mal keine Speicheradresse hat.

Bleibt noch der Mittelteil. Das ist ein Datentypausdruck, der in ( ) 
eingeschlossen ist. Und das ist gemein hin bekannt als ein Cast. Mit 
einem Cast kann man einen Datentypwechsel erzwingen. In die Klammern 
schreibt man den Datentyp, auf den der rechts vom Cast stehende Ausdruck 
gewzungen werden soll. Steht auch in jedem Lehrbuch.

     (double)a

erzwingt, dass der Wert von a auf den Datentyp double gebracht wird. a 
wird ausgelesen und ergibt irgendeinen Wert. Dieser Wert wird zu einem 
double gemacht und mit diesem double wird weitergearbeitet.


     (int*) &a

erwzingt also, dass die Adresse von a als vom Datentyp 'Pointer auf int' 
aufgefasst wird.
Das ist in diesem Fall natürlich sinnlos, weil &a ja sowieso schon ein 
Pointer auf int ist, aber seis drum. Wir hätten auch schreiben können

     (double*) &a

jetzt wird veranlasst, dass die Adresse von a auf einen 'Pointer auf 
double' umgecastet wird. Wird dieser neue Pointer dereferenziert


    * (double*) &a

so zwinge ich den Compiler dadurch, so zu tun, als ob dort wo die 
Variable a im Speicher liegt, die Bytes wie ein double Wert aufgefasst 
werden. Der Zahlenwert wird nicht konvertiert oder sonst irgendwie 
umgeformt, sondern ich tu einfach so, als ob dort im Speicher die Bytes 
für einen double Wert vorliegen würden und lese sie als double Wert, was 
auch immer das ergibt.

Es ist im Grunde fast so, als ob ich auf eine Bierkiste deute und zu dir 
sage: Jetzt tun wir mal so, als ob an der Stelle an der die Bierkiste 
steht ein Sessel wäre, auf den du dich setzen kannst.

      * (Sessel*) &Bierkiste

Die Bierkiste ist immer noch eine Bierkiste, aber durch den Cast sehen 
wir den Platz auf dem die Bierkiste steht so an, als ob dort ein Sessel 
stünde.

Auch das steht in jedem Lehrbuch. Vielleicht nicht ganz in dieser Form, 
aber irgendwo kommt das mit Sicherheit vor.


Aber Achtung:

      (double)a

und

      *(double*)&a

sind 2 verschiedene Dinge!
Das eine mal wird a in seiner ganzen Pracht ausgelesen und das 
Ausgelesene in einen double umgeformt, während man im zweiten Fall nur 
so tut, als ob dort wo a im Speicher liegt, ein double Wert vorliegen 
würde. Da wird kein Zahlenwert in irgendeiner Form umgeformt, es werden 
lediglich die Bytes im Speicher anders intepretiert.


> ansonsten immer hilfsbereiten Karl heinz Buchegger geht mir dann schon
> irgendwie auf die Eier.

Was glaubst du wie es mir mitlerweile auf die Eier geht, jeden Tag immer 
wieder dieselben Fragen zu beantworten, die in jeden, aber auch wirklich 
jedem, Lehrbuch beantwortet werden?

Wenn jemand ein Buch liest und mit einem Konzept Schwierigkeiten hat und 
eine nähere Erläuterung dazu braucht: Super, gerne!

Aber wenn man zum hundertausendstenmal erklären muss warum bei

     double i = 5 / 9;

null herauskommt, dann wird man irgendwann müde.
Dein Problem fällt in die gleiche Kategorie. Es ist einfach nur das 
Verbinden der Konzepte
AdressOf
Casten
Dereferenzieren
zu einer Einheit, mehr steckt da nicht dahinter. Aber eine Aussage ala 
'Mich bringen die viele * durcheinander' zeigt mir, dass schon die 
Einzelkonzepte Schwierigkeiten machen. Und die sind in jedem Lehrbuch 
enthalten. Oder was würdest du zu jemandem sagen, der auf die 
Aufgabenstellung

    Differential( 2 * x + 7, dx )

mit 'Ähm was bedeutet der * da drinnen' antwortet. Ich wette du würdest 
ihm auch erst einmal ein Grundlagenlehrbuch über Grundschulmathematik in 
die Hand drücken und nicht damit anfangen ihm die Feinheiten der 
Differentatiation zu erklären.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> Konkret scheint das cdecl für das obige Konstrukt etwas überfordert.

Was dadran liegen könnte, dass cdecl nur Deklarationen und Casts kann, 
keine kompletten Ausdrücke ;-)

cdecl war nicht als "Allheilmittel" gemeint, nur als Beispiel für ein 
mögliches Hilfsmittel. Im konkreten Fall hilft es nicht, richtig, aber 
der Fall ist ja auch nicht "haarig" ;-)

Andreas

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.