Forum: Mikrocontroller und Digitale Elektronik STM32 Datenrichtung (GPIOx_CRL/CRH)


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,
ich steige (seit Monaten) vom AVR auf STM32 um. Was ich beim AVR toll 
finde ist, wie einfach man beim GPIO-Pins zwischen Ein- und Ausgang 
umschalten kann (Datenrichtungsregister DDR). Beim STM32F10x ist es ja 
etwas komplizierter, da die Konfiguration von Ein- und Ausgängen etwas 
unhandlich in den Registern GPIOx_CRL und GPIOx_CRH verteilt ist. Die 
CMSIS-Library führt diese Berechnungen zur Laufzeit durch, was mir nicht 
gefällt, weil ich eigentlich nur zwei Pins ständig umschalten will, um 
Statusflags zu lesen.

Hat sich schon jemand die Mühe gemacht, Präprozessormagie mit Bitbanding 
zu betreiben, daß das ähnlich einfach wie beim AVR geht?

Ich weiß: "Selbst ist der Mann". Aber insbesondere in Präprozessormagie 
bin ich nicht besonders fit und es dauert lange zu testen.

Viele Grüße
W.T.

von (prx) A. K. (prx)


Lesenswert?

Wozu brauchst du die Umschaltung? Die wird beim STM32 nicht annähernd so 
oft benötigt, weil die Pins von Haus aus über eine Open Drain 
Konfiguration verfügen. Während AVRs für O.D. die Richtungsumschaltung 
bemühen müssen, z.B. bei 1-Wire.

Soll heissen: Ein Open Drain Output auf 1 ist effektiv ein Input.

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Hallo A.K.,
open drain kann der kleine AVR auch prima, für meinen Anwendungsfall 
(bidirektionaler Datenbus) wäre mir allerdings ein schnelles Umschalten 
zwischen push-pull und floating input lieber

Open drain wäre hier allenfalls eine Notlösung - bevor ich das 
akzeptiere, schließe ich mich lieber das ganze nächste Wochenende mit 
einem C-Buch und einem karierten Block im Badezimmer ein :-)

Viele Grüße
W.T.

von (prx) A. K. (prx)


Lesenswert?


: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

Ja, den habe ich schon gelesen. Insbesonder "__builtin_clz(mask)" sieht 
so aus, als könnte es das Wochenende etwas verkürzen.

Aber noch gebe ich die Hoffnung nicht auf, daß es das schon in fertig 
gibt - seltenheitswert hat die Problemstellung ja vermutlich eher nicht.

von (prx) A. K. (prx)


Lesenswert?

Walter Tarpan schrieb:
> Ja, den habe ich schon gelesen. Insbesonder "__builtin_clz(mask)" sieht
> so aus, als könnte es das Wochenende etwas verkürzen.

Nur wenn du die Nummer des Pins nicht kennst und mit der Maske arbeiten 
musst. Bei I/O-Pins wäre das etwas merkwürdig.

von Walter T. (nicolas)


Lesenswert?

A. K. schrieb:
> [...] und mit der Maske arbeiten
> musst [...]

Mit der Maske werde ich arbeiten müssen - schließlich will ich ja nicht 
nur einen Pin umschalten. Aber nicht mehr heute. Erst nächstes 
Wochenende.

von (prx) A. K. (prx)


Lesenswert?

Bitbanding wird dir beim F10x auch nicht so arg viel helfen, da die 
CNF/MODE Bits das nicht in einem einzelnen Bit hergeben. Bei den etwas 
sinnigere definierten Ports vom F4xx hingegen geht das.

Aber wenn du damit trotzdem rumspielen willst: Die Aufteilung der CNF 
Register in Lo/Hi braucht dich beim Bitbanding nicht zu stören. Denn mit
  BBPeriphBit(GPIOA->CRL, 11*4) /* Pin 11 */
erreichst du automatisch das eigentlich zuständige CRH.

von (prx) A. K. (prx)


Lesenswert?

Walter Tarpan schrieb:
> Mit der Maske werde ich arbeiten müssen - schließlich will ich ja nicht
> nur einen Pin umschalten.

Das geht mit Bitbanding nicht. Damit kannst du nur 1 Bit ansprechen.

PS: Viel Spass im Bad. Also dann bis Montag. ;-)

: Bearbeitet durch User
von Walter T. (nicolas)


Lesenswert?

A. K. schrieb:
> Das geht mit Bitbanding nicht. Damit kannst du nur 1 Bit ansprechen.

Oh, der STM32 ist aber eine Mimose.

Naja, was solls. Ganz so knifflig war es dann doch nicht, einen ganzen 
(8-Bit) Port umzuschalten, wobei ich mich allerdings auch nicht auf 
Präprozessormagie verlassen habe:
1
#define BITMASK_OUTPUT 0x33333333
2
#define BITMASK_INPUT  0x88888888
3
#define DATA_OFFSET 7
4
5
static inline void setByteIoBitmask(GPIO_TypeDef * const GPIOx,const uint32_t mask) { {
6
  #if(DATA_OFFSET==0)
7
    GPIOx->CRL = mask;
8
  #elif(DATA_OFFSET==8)
9
    GPIOx->CRH = mask;
10
  #else
11
    #warning "not tested yet"
12
    GPIOx->CRL |= mask<<4*DATA_OFFSET;
13
    GPIOx->CRL &= mask<<4*DATA_OFFSET | \
14
                   (0xFFFFFFFF >> (32-4*DATA_OFFSET) );
15
16
    GPIOx->CRH |= mask>>4*(8-DATA_OFFSET);
17
    GPIOx->CRL &= mask>>4*(8-DATA_OFFSET) | \
18
                   (0xFFFFFFFF << (DATA_OFFSET*4) );
19
  #endif
20
}
21
22
static inline void setIoInput(void) {
23
  setByteIoBitmask(GPIOB,BITMASK_INPUT);
24
}
25
26
static inline void setIoOutput(void) {
27
  setByteIoBitmask(GPIOB,BITMASK_OUTPUT);
28
}


Im Fall DATA_OFFSET = 7 macht der Compiler daraus:
1
800221c <L_LOOPUS_127>:
2
 800221c:  3a01        subs  r2, #1
3
 800221e:  f47f affd   bne.w  800221c <L_LOOPUS_127>
4
    GPIOx->CRL = mask;
5
  #elif(DATA_OFFSET==8)
6
    GPIOx->CRH = mask;
7
  #else
8
    #warning "not tested/implemented yet"
9
    GPIOx->CRL |= mask<<4*DATA_OFFSET;
10
 8002222:  4b13        ldr  r3, [pc, #76]  ; (8002270 <L_LOOPUS_127+0x54>)
11
 8002224:  681a        ldr  r2, [r3, #0]
12
 8002226:  f042 4100   orr.w  r1, r2, #2147483648  ; 0x80000000
13
 800222a:  6019        str  r1, [r3, #0]
14
    GPIOx->CRL &= mask<<4*DATA_OFFSET | \
15
 800222c:  6818        ldr  r0, [r3, #0]
16
 800222e:  f020 42e0   bic.w  r2, r0, #1879048192  ; 0x70000000
17
 8002232:  601a        str  r2, [r3, #0]
18
                   (0xFFFFFFFF >> (32-4*DATA_OFFSET) );
19
20
    GPIOx->CRH |= mask>>4*(8-DATA_OFFSET);
21
 8002234:  6859        ldr  r1, [r3, #4]
22
 8002236:  480f        ldr  r0, [pc, #60]  ; (8002274 <L_LOOPUS_127+0x58>)
23
 8002238:  ea41 0200   orr.w  r2, r1, r0
24
 800223c:  605a        str  r2, [r3, #4]
25
    GPIOx->CRL &= mask>>4*(8-DATA_OFFSET) | \
26
 800223e:  6819        ldr  r1, [r3, #0]
27
 8002240:  480d        ldr  r0, [pc, #52]  ; (8002278 <L_LOOPUS_127+0x5c>)
28
 8002242:  4008        ands  r0, r1
29
 8002244:  6018        str  r0, [r3, #0]
30
    GPIOx->CRL = mask;
31
  #elif(DATA_OFFSET==8)
32
    GPIOx->CRH = mask;
33
  #else
34
    #warning "not tested/implemented yet"
35
    GPIOx->CRL |= mask<<4*DATA_OFFSET;
36
 8002246:  681a        ldr  r2, [r3, #0]
37
 8002248:  f042 5140   orr.w  r1, r2, #805306368  ; 0x30000000
38
 800224c:  6019        str  r1, [r3, #0]
39
    GPIOx->CRL &= mask<<4*DATA_OFFSET | \
40
 800224e:  6818        ldr  r0, [r3, #0]
41
 8002250:  f020 4240   bic.w  r2, r0, #3221225472  ; 0xc0000000
42
 8002254:  601a        str  r2, [r3, #0]
43
                   (0xFFFFFFFF >> (32-4*DATA_OFFSET) );
44
45
    GPIOx->CRH |= mask>>4*(8-DATA_OFFSET);
46
 8002256:  6859        ldr  r1, [r3, #4]
47
 8002258:  4808        ldr  r0, [pc, #32]  ; (800227c <L_LOOPUS_127+0x60>)
48
 800225a:  ea41 0200   orr.w  r2, r1, r0
49
 800225e:  605a        str  r2, [r3, #4]
50
    GPIOx->CRL &= mask>>4*(8-DATA_OFFSET) | \
51
 8002260:  6819        ldr  r1, [r3, #0]
52
 8002262:  4807        ldr  r0, [pc, #28]  ; (8002280 <L_LOOPUS_127+0x64>)
53
 8002264:  4008        ands  r0, r1
54
 8002266:  6018        str  r0, [r3, #0]
55
 8002268:  4770        bx  lr
56
 800226a:  bf00        nop
57
 800226c:  40011000   .word  0x40011000
58
 8002270:  40010c00   .word  0x40010c00
59
 8002274:  08888888   .word  0x08888888
60
 8002278:  f8888888   .word  0xf8888888
61
 800227c:  03333333   .word  0x03333333
62
 8002280:  f3333333   .word  0xf3333333
Aber ich wüßte auch nicht, daß es noch schneller gehen könnte (?)

Wahlfrei einen ganzen Port umschalten geht noch nicht, aber fürs erste 
reicht's.

Viele Grüße
W.T.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Walter Tarpan schrieb:
> Oh, der STM32 ist aber eine Mimose.

Für Bitbanding ist ARM verantwortlich, nicht ST. Du bräuchtest 
Bitfeld-Operationen im Speicher und das bieten ARM Prozessoren nicht 
(MCUA: dein Einsatz ;-).

> Naja, was solls. Ganz so knifflig war es dann doch nicht, einen ganzen
> (8-Bit) Port umzuschalten

Davon war bisher ja auch nicht die Rede. Die unteren oder oberen 8 Bit 
geschlossen umzuschalten ist trivial.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Walter Tarpan schrieb:
>     #warning "not tested yet"

Es scheint mir sinnvoller, CRL/CRH in Vars zu laden, dort zu verändern 
und dann zurück zu speichern. Das wird einerseits etwas effizienter 
sein. Insbesondere vermeidet es aber jene falschen Zwischenzustände bei 
der Portkonfiguration, die bei dir auftreten werden.

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.