Forum: Mikrocontroller und Digitale Elektronik Präprozessormagie: GPIOs


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

ich "arbeite" mit dem ARM-GCC-none-Eabi. Folgende Definitionen sind 
vorhanden:
1
// Aus der STM424xx.h
2
#define GPIOC               ((GPIO_TypeDef *) GPIOC_BASE)
3
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /* Pin 5 selected */
4
5
6
// Mein Teil
7
#define GLCD_DATA_D0_GPIO GPIOC
8
#define GLCD_DATA_D0_Pin GPIO_Pin_5
9
10
#define GLCD_DATA_D0_GPIO GPIOC
11
#define GLCD_DATA_D0_Pin GPIO_Pin_5
12
...

Die folgende Funktion ist mit den obigen Definitionen ein konstanter 
Ausdruck:
1
/* Testen, ob alle GPIO-Pins in einer Reihe liegen. Sollte wegoptimiert werden. */
2
static inline bool isInline(void)
3
{
4
    if( ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D1_GPIO)) &&
5
        ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D2_GPIO)) &&
6
        ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D3_GPIO)) &&
7
        ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D4_GPIO)) &&
8
        ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D5_GPIO)) &&
9
        ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D6_GPIO)) &&
10
        ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D7_GPIO)) &&
11
        ((GLCD_DATA_D0_Pin)<<1 == (GLCD_DATA_D1_Pin)) &&
12
        ((GLCD_DATA_D0_Pin)<<2 == (GLCD_DATA_D2_Pin)) &&
13
        ((GLCD_DATA_D0_Pin)<<3 == (GLCD_DATA_D3_Pin)) &&
14
        ((GLCD_DATA_D0_Pin)<<4 == (GLCD_DATA_D4_Pin)) &&
15
        ((GLCD_DATA_D0_Pin)<<5 == (GLCD_DATA_D5_Pin)) &&
16
        ((GLCD_DATA_D0_Pin)<<6 == (GLCD_DATA_D6_Pin)) &&
17
        ((GLCD_DATA_D0_Pin)<<7 == (GLCD_DATA_D7_Pin)) )
18
19
        return true;
20
    else
21
        return false;
22
}

Gibt es einen Weg, aus dieser konstanten Funktion, die auch vom 
Optimizer völlig korrekt zu "#1" zusammengekürzt wird, einen konstanten 
Ausdruck zu machen, um zur Compilezeit zu warnen?

von g457 (Gast)


Lesenswert?

> Gibt es einen Weg, aus dieser konstanten Funktion [..] einen konstanten
> Ausdruck zu machen, um zur Compilezeit zu warnen?

Ja.

HTH

von Walter T. (nicolas)


Lesenswert?

g457 schrieb:
> HTH

WTF?

von qwerzuiopü+ (Gast)


Lesenswert?

Walter T. schrieb:
> Gibt es einen Weg, aus dieser konstanten Funktion, die auch vom
> Optimizer völlig korrekt zu "#1" zusammengekürzt wird, einen konstanten
> Ausdruck zu machen, um zur Compilezeit zu warnen?

Schau doch mal nach constexpr und static assert. Setzt allerdings 
voraus, dass dein Compiler C++11 kann. Dafür kannst du dann auch die 
#define-Befehle durch zeitgemäßes constexpr mit Typisierung ersetzen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> // Mein Teil
> #define GLCD_DATA_D0_GPIO GPIOC
> #define GLCD_DATA_D0_Pin GPIO_Pin_5
>
> #define GLCD_DATA_D0_GPIO GPIOC
> #define GLCD_DATA_D0_Pin GPIO_Pin_5
> ...

Da steht in beiden Blöcken dasselbe. Copy&Paste-Fehler? Wahrscheinlich 
meinstest Du im 2. Block:

> #define GLCD_DATA_D1_GPIO GPIOC
> #define GLCD_DATA_D1_Pin GPIO_Pin_6  // hier 6 statt 5.

Jetzt zu Deinem Problem:

>     if( ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D1_GPIO)) &&
>         ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D2_GPIO)) &&
> ...
>         ((GLCD_DATA_D0_Pin)<<1 == (GLCD_DATA_D1_Pin)) &&
>         ((GLCD_DATA_D0_Pin)<<2 == (GLCD_DATA_D2_Pin)) &&
> ...

Du könntest das so schreiben:
1
#if ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D1_GPIO)) &&     \
2
    ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D2_GPIO)) &&     \
3
    ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D3_GPIO)) &&     \
4
    ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D4_GPIO)) &&     \
5
    ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D5_GPIO)) &&     \
6
    ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D6_GPIO)) &&     \
7
    ((GLCD_DATA_D0_GPIO) == (GLCD_DATA_D7_GPIO)) &&     \
8
    ((GLCD_DATA_D0_Pin)<<1 == (GLCD_DATA_D1_Pin)) &&    \
9
    ((GLCD_DATA_D0_Pin)<<2 == (GLCD_DATA_D2_Pin)) &&    \
10
    ((GLCD_DATA_D0_Pin)<<3 == (GLCD_DATA_D3_Pin)) &&    \
11
    ((GLCD_DATA_D0_Pin)<<4 == (GLCD_DATA_D4_Pin)) &&    \
12
    ((GLCD_DATA_D0_Pin)<<5 == (GLCD_DATA_D5_Pin)) &&    \
13
    ((GLCD_DATA_D0_Pin)<<6 == (GLCD_DATA_D6_Pin)) &&    \
14
    ((GLCD_DATA_D0_Pin)<<7 == (GLCD_DATA_D7_Pin))
15
#else
16
#error Pins not adjusted
17
#endif

Dann wird der Fehler zur Compilezeit ausgegeben. Ja, der Preprozessor 
kann rechnen - jedenfalls in einem '#if'.

EDIT:
Vermutlich klappt das aber doch nur mit dem 2. Teil, wo die Pins 
verglichen werden. Denn das sind einfache numerische Masken. GPIOC wird 
aber keine einfache Zahl sein, daher wird das Vergleichen des Ports 
vermutlich fehlschlagen.

von Walter T. (nicolas)


Lesenswert?

Frank M. schrieb:
> Da steht in beiden Blöcken dasselbe. Copy&Paste-Fehler?

Ja, das ist ein Copy-Paste-Fehler.

Frank M. schrieb:
> Du könntest das so schreiben:

Das war auch mein erster Versuch. Das Problem: Aufgrund der Definition 
von GPIOC (siehe oben) bricht der Compiler/Präprozessor mit der 
folgenden Fehlermeldung ab:
1
.\src_3rd_party\src_stm32f4xx/stm32f4xx.h:2008:45: error: operator '*' has no right operand

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> .\src_3rd_party\src_stm32f4xx/stm32f4xx.h:2008:45: error: operator '*'
> has no right operand

Ja, ist mir eben auch aufgefallen, deshalb hatte ich meinen Beitrag 
nochmal editiert. Das hat sich jetzt mit Deinem Beitrag überschitten.

Der Pin-Vergleich im zweiten Teil wird funktionieren, da die Pins nur 
Zahlenwerte (Masken) sind.

Du kannst also wohl nur die Pins testen, aber nicht die Ports:
1
#if ((GLCD_DATA_D0_Pin)<<1 == (GLCD_DATA_D1_Pin)) &&    \
2
    ((GLCD_DATA_D0_Pin)<<2 == (GLCD_DATA_D2_Pin)) &&    \
3
    ((GLCD_DATA_D0_Pin)<<3 == (GLCD_DATA_D3_Pin)) &&    \
4
    ((GLCD_DATA_D0_Pin)<<4 == (GLCD_DATA_D4_Pin)) &&    \
5
    ((GLCD_DATA_D0_Pin)<<5 == (GLCD_DATA_D5_Pin)) &&    \
6
    ((GLCD_DATA_D0_Pin)<<6 == (GLCD_DATA_D6_Pin)) &&    \
7
    ((GLCD_DATA_D0_Pin)<<7 == (GLCD_DATA_D7_Pin))
8
#else
9
#error Pins not adjusted
10
#endif

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Definiere für Dein LCD als Port nur ein Makro:
1
#define GLCD_DATA_GPIO     GPIOC

Dann ist es unabhängig vom Pin und Du hast nur eine Definition für den 
Port. Dann kann man gar nicht auf die Idee kommen, verschiedene 
GPIO-Ports einzusetzen.

von Walter T. (nicolas)


Lesenswert?

Frank M. schrieb:
> Du kannst also wohl nur die Pins testen,

Das leider auch nicht.
1
.\src_3rd_party\src_stm32f4xx\SPL\inc\stm32f4xx_gpio.h|149|error: missing binary operator before token "0x0020"|

Frank M. schrieb:
> Definiere für Dein LCD als Port nur ein Makro

Das ist der alte Teil. Ich gehe gerade den Weg in die andere Richtung: 
Vorher war alles an einem Port, jetzt will ich beim Kompilieren eine 
Warnung ausgeben, daß das alles sehr langsam wird, wenn es an getrennten 
Ports liegt.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Walter T. schrieb:
> Das leider auch nicht.

Hm, das liegt wohl dann an dem Cast:
1
#define GPIO_Pin_5                 ((uint16_t)0x0020)

Ich hatte das mal schnell unter Linux mit
1
#define GLCD_DATA_D0_Pin 0x01
2
#define GLCD_DATA_D1_Pin 0x02
3
#define GLCD_DATA_D2_Pin 0x04
4
#define GLCD_DATA_D3_Pin 0x08
5
#define GLCD_DATA_D4_Pin 0x10
6
#define GLCD_DATA_D5_Pin 0x20
7
#define GLCD_DATA_D6_Pin 0x40
8
#define GLCD_DATA_D7_Pin 0x80
getestet. Wenn da also nur reine Zahlenwerte stehen, geht es.

von Walter T. (nicolas)


Lesenswert?

Frank M. schrieb:
> Hm, das liegt wohl dann an dem Cast:#define GPIO_Pin_5
> ((uint16_t)0x0020)

Ja, genau. Und ich kenne keinen Gegenzauber. Egal. Für den vorliegenden 
Fall ist es von rein akademischem Interesse.

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.