AVR-gcc und Bitfelder

OP #1777940
Lesenswert?

Hallo Leutz,

bin ein purer Einsteiger und versuche gerade einen Atmega168 mit dem 
AVR-gcc zu programmieren. Ziel ist es, Die TN AVR447, die ja in IAR-C 
geschrieben ist, auf einen 'Standard'-C-Compiler zu portieren. 
Anscheinend machen die Compiler aber unterschiedliches aus einem 
Bitfeld:

Teil aus der Headerdatei:
1
typedef struct PMSMflags
2
{
3
  unsigned motorStopped : 1;
4
  unsigned motorSynchronized: 1;
5
  unsigned actualDirection : 2;
6
  unsigned desiredDirection : 1;
7
  unsigned driveWaveform : 2;
8
} PMSMflags_t;

Normalerweise sollte das in ein Byte reinpassen (AVR-GCC-Tutorial). Bei 
Atmel ist das nur eine temporäre Variable, die die Struktur an andere 
Variablen mit den gleichen Bitnamen übergibt. So z.B. in main.c:
1
PMSMflags_t fastFlags;

Dummerweise weist Atmel der Variable fastFlags das Register GPIOR0 zu. 
Das scheint in IAR-C ganz einfach zu gehen:
1
__io volatile PMSMflags_t fastFlags                               @0x1e;

Mir fällt blos nichts dazu in GCC ein. Laut Herold/Arndt entsteht dabei 
auch eine Variable mit der Länge von 5 Bytes; dass die nicht in ein 
Register passen war mir dann auch klar. Was anscheinend funktioniert hat 
war ein:
1
#define fastFlags GPIOR0

direkt danach. Ich habe fastFlags damit aber anscheinend umdefiniert. 
Ich bekomme jedenfalls folgende Fehlermeldungen:
1
error: incompatible types in assignment  // wenn ich die Variable als ganzes anspreche

oder auch
1
error: request for member 'motorSynchronized' in something not a structure or union // wenn ich die einzelnen Bits der Variable anspreche

Da ich unter SUSE Linux arbeite, möchte ich mir auch kein WinAVR 
installieren. Ich weiss, ich mache was falsch. Ist einer so nett und 
kann mir das mal erklären?
Gast #1778083
Lesenswert?

der GCC is da etwas eigen ..

versuch mal
1
typedef union 
2
{
3
 unsigned char  register; 
4
 struct PMSMflags
5
 {
6
   unsigned char motorStopped : 1;
7
   unsigned char motorSynchronized: 1;
8
   unsigned char actualDirection : 2;
9
   unsigned char desiredDirection : 1;
10
   unsigned char driveWaveform : 2;
11
 };
12
} PMSMflags_t;
Persönliche Seite #1778096
Lesenswert?

möööp schrieb:
> versuch mal
>
>
1
> typedef union
2
> {
3
>  unsigned char  register;
4
>  struct PMSMflags
5
>  {
6
>    unsigned char motorStopped : 1;
7
>    unsigned char motorSynchronized: 1;
8
>    unsigned char actualDirection : 2;
9
>    unsigned char desiredDirection : 1;
10
>    unsigned char driveWaveform : 2;
11
>  };
12
> } PMSMflags_t;
13
> 
14
>

Nö. Register ist ein Schlüsselwort in C.

Klaus Wachtler schrieb:
> Übersetzst du beim AVR mit -Os ?

Typelayout hängt nicht von Optimierung ab.
OP #1778258
Lesenswert?

Wow, das ist mal 'ne schnelle Reaktion hier.
Ich werde die verschiedenen Tips mal austesten. Am sinnvollsten scheint 
mir die Version von A.K. (hallo Initialienvetter) zu sein. Ich werde 
darüber berichten. Hier noch ein paar Einzelantworten:

@Klaus:
Ja, ich übersetze mit der Optimierung -Os. Allerdings habe ich auch -O2 
schon ausprobiert, was scheinbar nicht wirklich was bringt.

@manoh:
Auch hier ein ja, ich möchte die Variable fastFlags mit der Struktur von 
PMSMflags_t im Register GPIOR0 fest unterbringen.
Leider lassen sich die GPIORx Register nur sehr umständlich in AVR-gcc 
ansprechen. Ich frage mich nur, wozu die sonst da sind? General Purpose 
heißt für mich 'Allgemeine Verwendung'. Der Vorteil ist ein recht 
schneller Zugriff und einfache Bitmanipulation mit nur wenigen 
Taktzüklen.
Gast #1778268
Lesenswert?

wenn mit GPIOR0 r0 gemeimt ist, geht das dann überhaupt?

aus nongnu avr libc: 
http://www.nongnu.org/avr-libc/user-manual/porting.html

Locking Registers

The IAR compiler allows a user to lock general registers from r15 and 
down by using compiler options and this keyword syntax:
1
__regvar __no_init volatile unsigned int filteredTimeSinceCommutation @14;

This line locks r14 for use only when explicitly referenced in your code 
thorugh the var name "filteredTimeSinceCommutation". This means that the 
compiler cannot dispose of it at its own will.

To do this in AVR GCC, do this:
1
register unsigned char counter asm("r3");

Typically, it should be possible to use r2 through r15 that way.

Note:
Do not reserve r0 or r1 as these are used internally by the compiler for 
a temporary register and for a zero value.
Locking registers is not recommended in AVR GCC as it removes this 
register from the control of the compiler, which may make code 
generation worse. Use at your own risk.
OP #1778296
Lesenswert?

Hallo Leutz,

habe da mal ein Bischen rumprobiert. Der Hinweis von A.K. scheint die 
Lösung zu sein:
1
#define fastFlags (*(volatile PMSMflags_t *)&GPIOR0)

Ich habe mir danach mal den *.lst - File angesehen. Es geschieht genau 
das, was ich erwartet habe: ein Zugriff auf GPIOR0 mit SBI und CBI:
1
    fastFlags = fastFlagsInitial;
2
 59e:  8e bb         out  0x1e, r24  ; 30

oder:
1
    fastFlags.desiredDirection = DIRECTION_FORWARD;
2
 5a8:  f4 98         cbi  0x1e, 4  ; 30

Wenn ich das richtig sehe, wird das Register mit der Adresse 0x1e 
angesprochen, das ist genau das GPIOR0.
Danke an alle, werd mich wieder melden.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren