Servus Im Rahmen eines Projektlabors an meiner FH bin ich gerade dabei mich in den STM32F103 einzuarbeiten, was mir schwerer fällt als gedacht. Bis jetzt hatte ich hauptsächlich mit dem C166 zu tun, mit dem man Register einfach à la RegisterXYZ |= 0x0101010101 maskieren kann. Beim STM32 spreche ich die Register über structs an, also GPIOx->ODR = 0x010101101;. Gibt es dafür grundsätzlich noch eine andere Methode, oder übersehe ich noch etwas? Bis jetzt hab ich mir damit beholfen, die unrelevanten Bits mit 0 oder der Reset Value zu beschreiben. Auf Dauer aber doch recht unschön. In die FirmwareLib will ich mich nur ungern einarbeiten, weil die Zeit so schon recht knapp ist.
LBubble schrieb: > mit dem man > Register einfach à la RegisterXYZ |= 0x0101010101 maskieren kann. > Beim STM32 spreche ich die Register über structs an, also GPIOx->ODR = > 0x010101101;. Hi, allgemein:
1 | GPIOx->ODR |= 0x010101101; |
2 | GPIOx_ODR |= 0x010101101; |
ist "das gleiche". In beiden Fällen steckt eine Adresse dahinter, nur die Adressbildung ist anders. Im ersten Fall berechnet der Compiler die Adresse aus BASE+OFFSET, im zweiten Fall hat der Vendor das im Headerfile selbst addiert. Im Zuge der Standardisierung unter CMSIS wurde das für alle Cortex-M Devices vereinheitlicht. Zum Einen erhöht es die Übersichtlichkeit (struct TIMER_type und #define-Mapping auf TIMER0,1,2,3,n), und zum Anderen ermöglicht es Tools mit IntelliSense Feature das automatische Einsehen der Member (Register).
1 | /*------------------------ General Purpose and Alternate Function IO ---------*/
|
2 | typedef struct { |
3 | __IO uint32_t CRL; |
4 | __IO uint32_t CRH; |
5 | __IO uint32_t IDR; |
6 | __IO uint32_t ODR; |
7 | __IO uint32_t BSRR; |
8 | __IO uint32_t BRR; |
9 | __IO uint32_t LCKR; |
10 | } GPIO_TypeDef; |
11 | |
12 | #define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
|
13 | #define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
|
14 | #define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
|
15 | #define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
|
16 | #define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
|
17 | #define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
|
18 | #define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
|
STM32 speziell: Im Gegensatz zu einigen anderen Controllern (AVR, LMI CM3, NXP) hat STM die PortPin-Konfigurationsmöglichkeiten in 2x 2Bits verpackt: MODE und CONF. Hintergrund ist das Glitchfreie Umschalten zwischen den Modes. VG, /th.
LBubble schrieb: > Gibt es dafür grundsätzlich noch eine andere Methode, oder übersehe ich > noch etwas? Bis jetzt hab ich mir damit beholfen, die unrelevanten Bits > mit 0 oder der Reset Value zu beschreiben. Auf Dauer aber doch recht > unschön. Bei den Portpins arbeitet man meist nicht mit dem ODR, sondern mit BSRR oder BRR. Manche Steuerregister anderer Komponenten besitzt ebenfalls separate Register, die nur Bits setzen oder löschen. Einzelne Bits kann man via ARM Bitbanding ansprechen.
LBubble schrieb: > Beim STM32 spreche ich die Register über structs an, also GPIOx->ODR = > 0x010101101;. Abgesehen davon, dass es optisch kaum einen Unterschied ergibt, ob man GPIOA_ODR oder GPIO->ODR schreibt, hat die Methode mit Strukturen den entscheidenden Vorteil, allgemeine Funktionen für Peripheriekomponenten zu ermöglichen, die mehrfach vorliegen. Wie etwa eine Funktion usart_init(USART1), die gleichermassen für alle USARTs einsetzbar ist und die Adresse der Struct zum Parameter hat.
GPIOA_ODR erzeugt bei mir einen "identifier 'GPIOA_ODR' is undefined"-Fehler. Dass ich mit dem Pfeiloperator ganz normal maskieren kann wusste ich nicht, da ich es zuerst mit GPIOA->CRL probiert habe, und da führte es zu keinem funktionierenden Ergebnis, mit RCC->APB2ENR und GPIOA->ODR allerdings schon. Auf jeden Fall hat mich das schon einiges weiter gebracht. Vielen Dank an Random.. für die ausführliche Antwort und A. K für den Tipp mit BSRR. Und an alle anderen für die Mühe. Gruß
> GPIOA_ODR erzeugt bei mir einen "identifier 'GPIOA_ODR' is > undefined"-Fehler. Stimmt, da muss ich dem Compiler rechtgeben. Ich sagte ja, wir haben dem Wildwuchs ein Ende gemacht :-) Gibt im Wesentlichen nur noch
1 | Peripheral->Register |
für Cortex-M. Willst du
1 | Peripheral_Register
|
verwenden, musst du es dir selbst definieren. > Dass ich mit dem Pfeiloperator ganz normal maskieren kann wusste ich > nicht, da ich es zuerst mit GPIOA->CRL probiert habe, und da führte es > zu keinem funktionierenden Ergebnis, mit RCC->APB2ENR und GPIOA->ODR > allerdings schon. CRL ist das Control Register Low. Die Konfiguration für die unteren 8Bit eines Ports sind im CRL zu 8 Portpins mal 2Bit MODE + 2Bit CONF organisiert, beim CRH (High) sind es gleichermaßen die Portpins 16...31 Was zum Abgucken, passend für die LEDs an Port B.8 bis B.15
1 | #ifndef __GPIO_H__
|
2 | #define __GPIO_H__
|
3 | |
4 | // AF enable
|
5 | #define AFIO_EN 0 // Alternate Function Enable
|
6 | |
7 | // GPIO enable
|
8 | #define IOPA_EN 2 // GPIO A enable
|
9 | #define IOPB_EN 3 // GPIO B enable
|
10 | #define IOPC_EN 4 // GPIO C enable
|
11 | #define IOPD_EN 5 // GPIO D enable
|
12 | #define IOPE_EN 6 // GPIO E enable
|
13 | #define IOPF_EN 7 // GPIO F enable
|
14 | #define IOPG_EN 8 // GPIO G enable
|
15 | |
16 | // DAC Enable
|
17 | #define DAC_EN 29
|
18 | |
19 | #define GPIO_CONF_BIT(BIT) ((BIT>7? BIT-8 : BIT) << 2) // 4Bits per port pin
|
20 | |
21 | // Mode and Conf Bits
|
22 | #define MODE0 (unsigned int)0
|
23 | #define MODE1 (unsigned int)1
|
24 | #define CONF0 (unsigned int)2
|
25 | #define CONF1 (unsigned int)3
|
26 | |
27 | // Port Mode
|
28 | #define GPIO_MODE_INPUT (((unsigned int)0<<MODE0) | ((unsigned int)0<<MODE1)) // GPIO is input
|
29 | #define GPIO_SPEED_2MHZ (((unsigned int)0<<MODE0) | ((unsigned int)1<<MODE1)) // Max output Speed 2MHz
|
30 | #define GPIO_SPEED_10MHZ (((unsigned int)1<<MODE0) | ((unsigned int)0<<MODE1)) // Max output Speed 10MHz
|
31 | #define GPIO_SPEED_50MHZ (((unsigned int)1<<MODE0) | ((unsigned int)1<<MODE1)) // Max output Speed 50MHz
|
32 | |
33 | // Port Conf
|
34 | #define GPIO_OUT_PUSH_PULL (((unsigned int)0<<CONF0) | ((unsigned int)0<<CONF1)) // general purpose output push-pull
|
35 | |
36 | #define GPIO_AF_PUSHPULL (((unsigned int)0<<CONF0) | ((unsigned int)1<<CONF1)) // alternate function push-pull
|
37 | |
38 | #define GPIO_IN_FLOATING (((unsigned int)1<<CONF0) | ((unsigned int)0<<CONF1)) // input floating
|
39 | #define GPIO_IN_ANALOG (((unsigned int)0<<CONF0) | ((unsigned int)0<<CONF1)) // input analog
|
40 | |
41 | #define GPIO_IN_PULL_DOWN (((unsigned int)0<<CONF0) | ((unsigned int)1<<CONF1)) // alternate function push-pull
|
42 | #define GPIO_IN_PULL_UP (((unsigned int)0<<CONF0) | ((unsigned int)1<<CONF1)) // alternate function push-pull
|
43 | |
44 | #endif
|
1 | #ifndef __led_h__
|
2 | #define __led_h__
|
3 | |
4 | #define LED_PORT GPIOB->ODR
|
5 | #define LED_PORT_MASK 0xFFFF00FF
|
6 | #define LED_PORT_SHIFT 8
|
7 | #define LED_PORT_SHIFT_MAX 15
|
8 | |
9 | int led_init(void); |
10 | void led_out(char out); |
11 | void running_light(void); |
12 | |
13 | #endif
|
14 | |
15 | |
16 | int ledCnt=0; |
17 | |
18 | int led_init(void) |
19 | {
|
20 | bit_on(RCC->APB2ENR, IOPB_EN); // enable PORT B |
21 | |
22 | GPIOB->CRH = |
23 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(8)) | \ |
24 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(9)) | \ |
25 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(10)) | \ |
26 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(11)) | \ |
27 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(12)) | \ |
28 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(13)) | \ |
29 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(14)) | \ |
30 | ((GPIO_OUT_PUSH_PULL | GPIO_SPEED_2MHZ) << GPIO_CONF_BIT(15)); |
31 | |
32 | return(0); |
33 | }
|
34 | |
35 | void led_out(char out){ |
36 | LED_PORT = (LED_PORT & LED_PORT_MASK) | (out << LED_PORT_SHIFT); |
37 | }
|
38 | |
39 | void running_light(void) |
40 | {
|
41 | static int count=0; |
42 | |
43 | count++; |
44 | |
45 | if(count > 0xffff){ |
46 | count=0; |
47 | led_out(1<<(ledCnt=++ledCnt<8?ledCnt:0)); // feed the running light |
48 | }
|
49 | }
|
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.