Forum: Compiler & IDEs AVR-gcc und Bitfelder


von Andreas K. (lowrider)


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?

von (prx) A. K. (prx)


Lesenswert?

Das kommt halt davon, wenn man sich vom C Standard wegbewegt, aber IAR 
wird übr Portierungsprobleme weg von IAR nicht wirklich unglücklich 
sein.

#define fastFlags (*(PMSMflags_t *)&GPIOR0)
oder
#define fastFlags (*(volatile PMSMflags_t *)&GPIOR0)

von Klaus W. (mfgkw)


Lesenswert?

Übersetzst du beim AVR mit -Os ?

von möööp (Gast)


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;

von Johann L. (gjlayde) Benutzerseite


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.

von manoh (Gast)


Lesenswert?

Andreas Klafft schrieb:
> Da ich unter SUSE Linux arbeite, möchte ich mir auch kein WinAVR
> installieren.

WinAVR ist doch AVR-GCC, das ändert doch nix...

Verstehe ich das eigentlich richtig, Du möchtes PMSMflags_t fastFlags 
ständig in einem Register stehen haben?

von Andreas K. (lowrider)


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.

von manoh (Gast)


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.

von (prx) A. K. (prx)


Lesenswert?

manoh schrieb:

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

GPIOR0/1/2 sind freie Register im bitadressierbaren I/O-Bereich einiger 
AVRs. Ideal geeignet für Flag-Bits.

von Andreas K. (lowrider)


Lesenswert?

Hallo manoh,

GPIOR0 ist nicht r0. GPIOR0 hat die Registeradresse 0x1e. Ich bin aber 
noch nicht dahintergestiegen welche Adresse r0-r32 haben?!

von (prx) A. K. (prx)


Lesenswert?

Andreas Klafft schrieb:

> Ich bin aber
> noch nicht dahintergestiegen welche Adresse r0-r32 haben?!

0..31, es sei denn man hat einen XMega oder einen 6-Pin Tiny.

Es ist aber dringend davon abzuraten, die Register per RAM-Adressen zu 
nutzen, jedenfalls wenn ein C Compiler mitmischt.

von Andreas K. (lowrider)


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.

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
Noch kein Account? Hier anmelden.