Forum: Compiler & IDEs AVR-GCC: Welchen Datentypen haben SFRs?


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
die Überschrift sagt eigentlich schon alles: Welchen Datentyp haben 
eigentlich die spezial function register, insbesondere für Ports?

In der iom32.h steht _SFR_IO8; gebe ich die Addressen mit   printf("addr 
= %i,%i\a",&DDRD,&PIND); auf einem Display aus ergibt sich 0x31,0x32 (im 
Gegensatz zur Definition in der iom32.h mit:
1
#define PIND    _SFR_IO8(0x10)
2
#define DDRD    _SFR_IO8(0x11)
3
#define PORTD   _SFR_IO8(0x12)

Kann ich eine Funktion/Präprozessormakro schreiben, die bei der Übergabe 
des Ports (PORTx) automatisch die beiden passenden anderen Register 
(PINx und DDRx) kennt? Und welchen Datentyp übergibt man 
sinnvollerweise?


Viele Grüße
W.T.

von Walter T. (nicolas)


Lesenswert?

OK, im Datenblatt werden alle Register zweimal mit jeweils 0x20 Offset 
angegeben - und ich finde jetzt auch keins, wo PINx, DDRx und PORTx 
nicht direkt hintereinanderliegen. Damit sollte es praktisch kein 
Problem sein, nur einen Wert zu übergeben.

Nur irgendwie will es nicht gelingen, mit dem Adressoperator dort 
hineinzuschreiben.

Was zu gehen scheint:
1
  #define ReadFromPort(PORT) (\
2
    (&PORT==&PORTA) ? (DDRA) :\
3
    ( (&PORT==&PORTB) ? (DDRB) :\
4
    ( (&PORT==&PORTC) ? (DDRC) :\
5
    ( (&PORT==&PORTD) ? (DDRD) :\
6
    0 ) ) )\
7
    )
wird zu:
1
    uint8_t a = ReadFromPort(PORTC);
2
    1f28:  84 b3         in  r24, 0x14  ; 20
3
    1f2a:  08 95         ret

: Bearbeitet durch User
von Horst (Gast)


Lesenswert?

volatile uint8_t

von Konrad S. (maybee)


Lesenswert?

Evtl. meinst du sowas:
1
#define fooPort(x) PORT ## x
2
#define barPort(x) PIN ## x
3
#define foobarPort(x) DDR ## x = 0x2a; PORT ## x = 0x2a

Damit wird aus diesem hier:
1
fooPort( A ) = barPort( B );
2
foobarPort( C );

jenes da:
1
PORTA = PINB;
2
DDRC = 0x2a; PORTC = 0x2a;

von (prx) A. K. (prx)


Lesenswert?

1
#define GLUE(a, b) a##b
2
#define PORT(x)    GLUE(PORT, x)
3
#define PIN(x)     GLUE(PIN, x)
4
#define DDR(x)     GLUE(DDR, x)
5
6
#define KEY_PORT   C
7
8
... DDR(KEY_PORT) ...

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Nö, paßt schon. Das, was ich oben gepostet habe macht genau das, was ich 
will. Ich hab's nur etwas erweitert:
1
 #define DDR(PORT) (\
2
    (&PORT==&PORTA) ? (DDRA) :\
3
    ( (&PORT==&PORTB) ? (DDRB) :\
4
    ( (&PORT==&PORTC) ? (DDRC) :\
5
    ( (&PORT==&PORTD) ? (DDRD) :\
6
    0 ) ) )\
7
    )
8
9
 #define PIN(PORT) (\
10
    (&PORT==&PORTA) ? (PINA) :\
11
    ( (&PORT==&PORTB) ? (PINB) :\
12
    ( (&PORT==&PORTC) ? (PINC) :\
13
    ( (&PORT==&PORTD) ? (PIND) :\
14
    0 ) ) )\
15
    )
Jetzt brauche ich pro Pin in die Pinbelegungstabelle nur noch zwei Werte 
zu hinterlegen (NAME_PORT und NAME_Pin) und habe die Sachen für AVR und 
ARM (NAME_GPIO und NAME_Pin) wieder komplett identisch.

Als static-inline-Funktion wäre mir noch etwas lieber gewesen als durch 
Präprozessormagie, weil AtmelStudio dann mit dem Auto-Vervollständigen 
sehr komfortabel ist, aber so ist es auch schon schön.

Vielen Dank für's Lesen
W.T.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Walter Tarpan schrieb:
> OK, im Datenblatt werden alle Register zweimal mit jeweils 0x20 Offset
> angegeben - und ich finde jetzt auch keins, wo PINx, DDRx und PORTx
> nicht direkt hintereinanderliegen. Damit sollte es praktisch kein
> Problem sein, nur einen Wert zu übergeben.

Beim ATMega 128 stimmt das fuer PORTF nicht
/* Input Pins, Port F */
#define PINF      _SFR_IO8(0x00)
/* Data Register, Port F */
#define PORTF     _SFR_MEM8(0x62)

/* Input Pins, Port G */
#define PING      _SFR_MEM8(0x63)

von Walter T. (nicolas)


Lesenswert?

Ich muß doch das alte Faß mal wieder aufmachen:

Ich habe folgendes Makro definiert:
1
        #define SetBit(PORT,BIT)   ( PORT |=   BIT)
Jetzt würde ich aus dem Makro gerne eine static-inline-Function machen, 
die sich genauso aufrufen läßt, also:
1
SetBit(PORTD,1<<PD3);
Ich würde auch gerne vermeiden, zu der auf AVR ungewohnten Schreibweise 
mit dem Adreßoperator zu greifen:
1
NSetBit(&PORTD,1<<PD3);

Ist das überhaupt möglich?

Viele Grüße
W.T.

von Fabian O. (xfr)


Lesenswert?

Wenn Du den C++-Compiler benutzt, mit einer Referenz:
1
static inline void SetBit(volatile uint8_t& reg, uint8_t bit)
2
{
3
  reg |= bit;
4
}
Mit C geht es nicht, weil bei der gewünschten Schreibweise ja sonst nur 
der Wert des Registers und nicht seine Adresse übergeben wird. Aus dem 
Wert lässt sich aber normalerweise nicht auf die Adresse schließen ...

Bei Makros mit Parametern solltest Du bei der Definition übrigens 
grundsätzlich Klammern um jeden Eingabewert machen. Ansonsten ist die 
Auswertungsreihenfolge unter Umständen nicht das, was Du erwartest, da 
das Makro ja praktisch nur eine Textersetung macht. Also besser:
1
#define SetBit(PORT, BIT) ((PORT) |= (BIT))

Und noch eine letzte Bemerkung: Der Name SetBit ist verwirrend, da das 
Makro nicht nur ein Bit, sondern eine ganze Bitmaske setzt. Ich hätte 
bei dem Namen eher diese Definition erwartet:
1
#define SetBit(PORT, BIT) ((PORT) |= 1 << (BIT))

Dein Makro wäre imo mit SetBits treffender benannt. Bzw. wenn man der 
üblichen Konvention folgt, dass Makros in Großbuchstaben geschrieben 
werden: SET_BITS.

: Bearbeitet durch User
von Simon K. (simon) Benutzerseite


Lesenswert?

Walter Tarpan schrieb:
> Ich würde auch gerne vermeiden, zu der auf AVR ungewohnten Schreibweise
> mit dem Adreßoperator zu greifen:

Wat?

von W.S. (Gast)


Lesenswert?

Walter Tarpan schrieb:
> und habe die Sachen für AVR und
> ARM (NAME_GPIO und NAME_Pin) wieder komplett identisch.

ach, und wie machst du das dann mit den unterschiedlichen Zugriffsarten 
bei ARM einschließlich dem ansonsten leistungsfähigen Bitbandung?

Ich verstehe nicht, warum du dir solche Mühen gibst, Zugriffe auf 
Portbits in derartiger Weise vereinheitlichen zu wollen. Mit diesem 
Bemühen blähst du deine Quellen nur derart auf, daß du irgendwann den 
Überblick verloren hast.

Mein Ratschlag: mach dir echte funktionelle Unterprogramme. Beispiel:
void Motor_Ein(void);
void Relais_Aus(void);
und so weiter. Für deinen logischen Firmwareinhalt kannst du dich auf 
solche lowlevel-Treiber verlassen und zum Umsetzen auf eine andere 
Architektur brauchst du bloß diese lowlevel-Funktionen anzupassen. Das 
ist wesentlich effektiver als ein unifizierter Ausdruck "SetBit(PORT, 
BIT)".

W.S.

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.