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.
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
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.
Und zum Code für Bitbanding siehe https://www.mikrocontroller.net/articles/ARM_Bitbanding#Makros
:
Bearbeitet durch User
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.
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.
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.
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.
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
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.