Forum: Mikrocontroller und Digitale Elektronik STM32 CMSIS Register setzen problem


von Paul G. (paul_g210) Benutzerseite


Lesenswert?

Hi

Ich stehe gerade völlig auf dem Schlauch beim setzten eines Registers 
des STM32F407VET.

Konkret geht es um GPIOB->AFR Register. In diesem möchte ich AF4 
(0b0100) für PIN 6 und 7 setzten (weil ich I2C aktivieren möchte).

Bisher habe ich bestimmte Sachen immer so aktiviert wie hier den Pullup 
für PB6:
1
GPIOB->PUPDR |= GPIO_PUPDR_PUPD6_1;

Wenn ich aber nun folgendes versuche
1
GPIOB->AFR |= GPIO_AFRL_AFRL6_2;
bekomme ich diese Fehlermeldung:
1
error: assignment to expression with array type

Kann mir jemand erhellen warum die erste zuweisung geht und die zweite 
nicht? GPIOB->AFR und GPIOB->PUPDR sind doch einfach nur zwei Register 
und GPIO_PUPDR_PUPD6_1 und GPIO_AFRL_AFRL6_2 sind doch nur bestimmte 
Bits in den Register...
1
#define GPIO_PUPDR_PUPD6_1               (0x2UL << GPIO_PUPDR_PUPD6_Pos)
2
#define GPIO_AFRL_AFRL6_2                GPIO_AFRL_AFSEL6_2
3
#define GPIO_AFRL_AFSEL6_2               (0x4UL << GPIO_AFRL_AFSEL6_Pos)

: Bearbeitet durch User
von Paul G. (paul_g210) Benutzerseite


Lesenswert?

Ahhhh, habs gerade selbst gesehen.

GPIOB->AFR ist ein Array weil es davon ein HIGH und LOW Register gibt.
So gehts:
1
GPIOB->AFR[0] |= GPIO_AFRL_AFRL6_2;

: Bearbeitet durch User
von A. B. (Gast)


Lesenswert?

Paul G. schrieb:
> GPIOB->AFR[0] |= GPIO_AFRL_AFRL6_2;

Das macht trotzdem sehr wenig Sinn. Es handelt sich um eine Kombination 
von 4 Bits, von denen manche 0, manche 1 sind. Das '|=' kann aber nur 
Bits setzen, nicht löschen. Und man sollte nicht stillschweigend 
voraussetzen, dass vorher alles nur Nullen waren ...

von John Doe (Gast)


Lesenswert?

A. B. schrieb:
> Paul G. schrieb:
>> GPIOB->AFR[0] |= GPIO_AFRL_AFRL6_2;
>
> Das macht trotzdem sehr wenig Sinn.

Doch, da man das meistens nur bei der Initialisierung des Controllers 
ändert und der Reset-Wert 0 ist.

von m.n. (Gast)


Lesenswert?

John Doe schrieb:
> Doch, da man das meistens nur bei der Initialisierung des Controllers
> ändert und der Reset-Wert 0 ist.

Aufpassen: bei den neueren STM32 ist GPIOx->MODER mit 0xffffffff 
initialisiert. Hier muß man die betreffenden Bits erst löschen, wenn man 
keinen Analog-Eingang haben möchte.

Beitrag #6570130 wurde von einem Moderator gelöscht.
von A. B. (Gast)


Lesenswert?

John Doe schrieb:
> Doch, da man das meistens nur bei der Initialisierung des Controllers
> ändert und der Reset-Wert 0 ist.

Ja, ja, das "meistens" spricht Bände ... das glaube ich nur demjenigen, 
der dann auch die Lock-Bits setzt.

von Planloser (Gast)


Lesenswert?

Paul G. schrieb:
> STM32F407VET

m.n. schrieb:
> John Doe schrieb:
>> Doch, da man das meistens nur bei der Initialisierung des Controllers
>> ändert und der Reset-Wert 0 ist.
>
> Aufpassen: bei den neueren STM32 ist GPIOx->MODER mit 0xffffffff
> initialisiert. Hier muß man die betreffenden Bits erst löschen, wenn man
> keinen Analog-Eingang haben möchte.


Es ist von einem STM32F407VET die Rede...

von Markus M. (adrock)


Lesenswert?

Ich habe mir angewöhnt, wenn ich schon nicht die "tollen" HAL-Funktionen 
verwende, dass ich Makros verwende, z.B.
1
#define SET_BIT(REG, BIT)     ((REG) |= (BIT))
2
#define CLEAR_BIT(REG, BIT)   ((REG) &= ~(BIT))
3
#define READ_BIT(REG, BIT)    ((REG) & (BIT))
4
#define CLEAR_REG(REG)        ((REG) = (0x0))
5
#define WRITE_REG(REG, VAL)   ((REG) = (VAL))
6
#define READ_REG(REG)         ((REG))
7
#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

Die sind offenbar bei den neueren STMs schon von Werk aus definiert in 
der stm32<modellreihe>.h

Finde ich ganz praktisch, auch wenn es etwas mehr Schreibarbeit ist. 
Insbesondere die MODIFY_REG Variante finde ich praktisch.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Markus M. schrieb:
> #define SET_BIT(REG, BIT)     ((REG) |= (BIT))

Da lauert für mich der Fehler, daß ich unter BIT eine Bit-Nummer 
verstehe, hier aber eine Bit-Maske erwartet wird. Für Setzen/Löschen 
eines Portpins eignet sich dieser Befehl nicht, da er nicht atomar 
ausgeführt wird.

Markus M. schrieb:
> #define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG),
> (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

Wie sieht der Code mit diesem Makro aus, wenn zum Beispiel bit0 - bit3 
eines Ports auf Ausgang gesetzt werden sollen?
Ich schreibe es lieber explizit hin; da sehe ich besser, wo etwas 
passiert.

Planloser schrieb:
> Es ist von einem STM32F407VET die Rede...

noch ...

von A. B. (Gast)


Lesenswert?

m.n. schrieb:
> Markus M. schrieb:
>> #define SET_BIT(REG, BIT)     ((REG) |= (BIT))
>
> Da lauert für mich der Fehler, daß ich unter BIT eine Bit-Nummer
> verstehe, hier aber eine Bit-Maske erwartet wird. Für Setzen/Löschen
> eines Portpins eignet sich dieser Befehl nicht, da er nicht atomar
> ausgeführt wird.

Hinsichtlich der möglichen Fehlinterpretation: SET_BIT*S* statt SET_BIT 
wär' vielleicht eine gute Idee.

Fürs atomare Setzen/Löschen sogar mehrerer(!) Port-Pins (von einem Port) 
gleichzeitig nimmt man auch das BSRR.

von Stefan F. (Gast)


Lesenswert?

m.n. schrieb:
>> #define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG),
>> (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

> Wie sieht der Code mit diesem Makro aus, wenn zum Beispiel bit0 - bit3
> eines Ports auf Ausgang gesetzt werden sollen?

Das ist eingentlich ganz einfach:

 * Der erste Parameter gibt das Register an, dass man ändern will.

 * Der zweite Parameter gibt die Bit-Gruppe an, die man ändern will.

 * Der dritte Parameter gibt die neuen Werte an.

Beispiel für den STM32F303:
1
// Select PLL as clock source
2
MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_CFGR_SW_PLL);
1
RCC_CFGR_SW     = 0x00000003 = 0b00000000000000000000000000000011
2
RCC_CFGR_SW_HSI = 0x00000000 = 0b00000000000000000000000000000000
3
RCC_CFGR_SW_HSE = 0x00000001 = 0b00000000000000000000000000000001
4
RCC_CFGR_SW_PLL = 0x00000002 = 0b00000000000000000000000000000010
5
                                                               ^^
6
                                                               SW


Bei dem MODER Register ist es leider anders, frage mich bitte nicht, 
warum:
1
// PA5 = Output (for status LED)
2
MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER5, GPIO_MODER_MODER5_0);
1
GPIO_MODER_MODER5   = 0x00000C00 = 0b00000000000000000000110000000000
2
GPIO_MODER_MODER5_0 = 0x00000400 = 0b00000000000000000000010000000000
3
GPIO_MODER_MODER5_1 = 0x00000400 = 0b00000000000000000000100000000000
4
                                                         ^^
5
                                                        MODER5

Hier gibt es keine Definitionen für die 4 Modi
 * 00: Input mode (reset state)
 * 01: General purpose output mode
 * 10: Alternate function mode
 * 11: Analog mode

Sondern nur zwei einzelne für die beiden Bits. Will man mehr als ein Bit 
setzen, muss man kombinieren:
1
// PA5 = Analog inpout
2
MODIFY_REG(GPIOA->MODER, GPIO_MODER_MODER5, GPIO_MODER_MODER5_1+GPIO_MODER_MODER5_0);

Um auf deine Frage zurück zu kommen:
> Wie sieht der Code mit diesem Makro aus, wenn zum Beispiel bit0 - bit3
> eines Ports auf Ausgang gesetzt werden sollen?
1
// PA0-3 = Output
2
MODIFY_REG(GPIOA->MODER,
3
    GPIO_MODER_MODER0+
4
    GPIO_MODER_MODER1+
5
    GPIO_MODER_MODER2+
6
    GPIO_MODER_MODER3,
7
        GPIO_MODER_MODER0_0+
8
        GPIO_MODER_MODER1_0+
9
        GPIO_MODER_MODER2_0+
10
        GPIO_MODER_MODER3_0);

Kann man schön finden, muss man nicht. Der darauf generierte Assembler 
Code sieht jedenfalls deutlich schlanker aus.

von Paul G. (paul_g210) Benutzerseite


Lesenswert?

Ben S. schrieb im Beitrag #6570130:
> Immer bei jedem Controller ins Datenblatt schauen, wie die Resetwerte
> wirklich sind. Oder ein Makro/Funktin schreiben, welches vorher die
> betreffenden Bits nullt.

Beim F407 ist der Reset Value des Registers GPIOB->AFR[] 0x00000000. Und 
da ich im Moment auch die Funktion des PINs nicht weiter ändere war mir 
das nicht wichtig das ich die restlichen drei Nullen nulle ;)

von m.n. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Um auf deine Frage zurück zu kommen:
>> Wie sieht der Code mit diesem Makro aus, wenn zum Beispiel bit0 - bit3
>> eines Ports auf Ausgang gesetzt werden sollen?// PA0-3 = Output
> MODIFY_REG(GPIOA->MODER,
>     GPIO_MODER_MODER0+
>     GPIO_MODER_MODER1+
>     GPIO_MODER_MODER2+
>     GPIO_MODER_MODER3,
>         GPIO_MODER_MODER0_0+
>         GPIO_MODER_MODER1_0+
>         GPIO_MODER_MODER2_0+
>         GPIO_MODER_MODER3_0);
>
> Kann man schön finden, muss man nicht. Der darauf generierte Assembler
> Code sieht jedenfalls deutlich schlanker aus.

Ich finde es auf keinen Fall schön, denn, was dort passieren soll, ist 
überhaupt nicht ersichtlich. Das ist doch mindestens genau so 
intransparent wie HAL.

von Stefan F. (Gast)


Lesenswert?

m.n. schrieb:
> Ich finde es auf keinen Fall schön, denn, was dort passieren soll, ist
> überhaupt nicht ersichtlich. Das ist doch mindestens genau so
> intransparent wie HAL.

Meiner Meinung nach fehlen da Definitionen mit sprechenden Namen, also 
so:
1
MODIFY_REG(GPIOA->MODER,
2
    GPIO_MODER_MODER0+
3
    GPIO_MODER_MODER1+
4
    GPIO_MODER_MODER2+
5
    GPIO_MODER_MODER3,
6
        GPIO_MODER_MODER0_OUTPUT+
7
        GPIO_MODER_MODER1_OUTPUT+
8
        GPIO_MODER_MODER2_OUTPUT+
9
        GPIO_MODER_MODER3_OUTPUT);

Bei den vielen Registern wird das ja auch so gemacht - warum nicht bei 
allen? Das müsste man wohl ST fragen.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Für jeden Pin an den Bits rumwackeln, egal ob mit Magic Numbers oder 
CMSIS oder Macros und CMSIS, ist doch etwas mühsam.

Da empfiehlt es sich einen kleinen "Treiber" zu schreiben.
Dieser bekommt ein struct mit sinnvollen enums.
Bei den STM32 und anderen größeren SoCs sind die Pinbetriebsarten doch 
ziemlich mächtig.
Dann ist ein Pin ausreichend beschrieben und daraus lässt sich auch ein 
Array bilden falls man mal einem Treiber den SPI austrauschen muss oder 
auch die alternativen Pins eines SPI nutzen will.

Damit meine ich jetzt nicht das aufgeblasene Teil der STM32 HAL, was so 
ziemlich garnicht abstrahiert.
Hier im Forum kam ja schonmal die Frage auf wieso man beim HAL 
Konfigstruct etwas auf output stellen muss für eine alternate function 
input.

Beispiel:
1
//! \brief enum of possible Pin Modes
2
enum gpio_mode {
3
  GPO_PP =    0b01000, //!< out pushpull
4
  GPO_PP_PU =    0b01001, //!< out pushpull + pullup
5
  GPO_PP_PD =    0b01010, //!< out pushpull + pulldown
6
  GPO_OD =    0b01100, //!< out opendrain
7
  GPO_OD_PU =    0b01101, //!< out opendrain + pullup
8
  GPO_OD_PD =    0b01110, //!< out opendrain + pulldown
9
  AF_PP =      0b10000, //!< altfunc pushpull
10
  AF_PP_PU =    0b10001, //!< altfunc pushpull + pullup
11
  AF_PP_PD =    0b10010, //!< altfunc pushpull + pulldown
12
  AF_OD =      0b10100, //!< altfunc opendrain  
13
  AF_OD_PU =    0b10101, //!< altfunc opendrain + pullup
14
  AF_OD_PD =    0b10110, //!< altfunc opendrain + pulldown
15
  GPI_FLOAT =    0b00000, //!< in floating
16
  GPI_PU =    0b00001, //!< in + pullup
17
  GPI_PD =    0b00010, //!< in + pulldown
18
  GP_ANALOG =    0b11000, //!< analog -> input is switched off
19
};
20
21
//! \brief enum of possible Pin Speeds
22
enum gpio_speed {
23
  GPIO_LS = 0b00, //!< low speed
24
  GPIO_MS = 0b01, //!< medium speed
25
  GPIO_FS = 0b10, //!< full speed
26
  GPIO_HS = 0b11, //!< high speed
27
};
28
29
//! \brief structure for one PIO pin 
30
struct pio_pin {
31
  GPIO_TypeDef* port;    //!< port of pin
32
  uint8_t nbr;      //!< pin Number (0 - 15)
33
  enum gpio_mode mode;  //!< pin mode @ref gpio_pin_mode
34
  enum gpio_speed speed;  //!< pin speed @ref PioPinSpeed
35
  uint8_t alt_func;    //!< alternate function, see datasheet
36
};

Das enum gpio_mode ist so mit Bits hinterlegt, dass die nurnoch 
auseinander gezogen werden müssen zum Register bespielen,

Bei der alt_func lässt sich leider nicht viel abstrahieren, das ist je 
nach STM32 Familie anders und bei den kleineren ist das sogar je nach 
Port anders belegt.
Das geht sicher besser, aber ist bisher ausreichend.

von m.n. (Gast)


Lesenswert?

Alles, was in Richtung Eierlegendewollmilchsau geht, ist letztlich für 
einen Außenstehenden schwer nachzuvollziehen.
Mein Beispiel für allgemeinen Bedarf:
1
enum gpio_modus {IN, OUT, AF, ANALOG};
2
enum gpio_speed {LOW_SPEED, MEDIUM_SPEED, HIGH_SPEED, V_HIGH_SPEED};
3
enum gpio_pullup {NO_PULL, PULL_UP, PULL_DOWN};
4
#define CLR_MODER     3         // Löschmaske
5
6
....
7
uint32_t temp;
8
  RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN;        // PortA aktivieren
9
// Ausgänge von PortA push-pull output*/
10
  temp = LCD_PORT->MODER &
11
              ~(CLR_MODER << LCD_CMD*2 | 
12
                CLR_MODER << LCD_READ*2 | 
13
                CLR_MODER << LCD_STROBE*2 |
14
                CLR_MODER << LCD_D4*2 | 
15
                CLR_MODER << LCD_D5*2 | 
16
                CLR_MODER << LCD_D6*2 | 
17
                CLR_MODER << LCD_D7*2);
18
  LCD_PORT->MODER = temp |
19
               (OUT << LCD_CMD*2 | 
20
                OUT << LCD_READ*2 | 
21
                OUT << LCD_STROBE*2 | 
22
                OUT << LCD_D4*2 | 
23
                OUT << LCD_D5*2 | 
24
                OUT << LCD_D6*2 | 
25
                OUT << LCD_D7*2);

'temp' dient der Lesbarkeit und wird vom Compiler ausradiert.
Wer keine Magie mag, definiert für die "2" meinetwegen ein 
MODER_SHIFT_W.

von W.S. (Gast)


Lesenswert?

John Doe schrieb:
> Doch, da man das meistens nur bei der Initialisierung des Controllers
> ändert und der Reset-Wert 0 ist.

Das ist ne Blindheit und es ist PFUSCH.
Sowas sollte man immer richtig machen, also derart, daß man sich eben 
nicht drauf verläßt, daß ja sowieso und meistens und überhaupt da der 
gewünschte Defaultwert drinsteht.

W.S.

von W.S. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Meiner Meinung nach fehlen da Definitionen mit sprechenden Namen, also
> so:
> MODIFY_REG(GPIOA->MODER,
>     GPIO_MODER_MODER0+
>     GPIO_MODER_MODER1+
>     GPIO_MODER_MODER2+...

Und was ist daran ein "sprechender" Name?

Nö, so eben nicht. Hier hat der Mw E. mal ausnahmsweise eine Idee in die 
richtige Richtung gehabt. Es ist nämlich vermutlich weitaus besser, wenn 
man gerade bei µC-Typen, die das Portvehalten in irgendwelchen 
Sammelregistern steuern, mit einer Initialisierungsroutine und 
geeigneten Makros arbeitet. Das testet man einmal gründlich aus und kann 
es dann ohne weitere Änderungen für alle auf dieser Plattform zu 
machenden Projekten verwenden. Und sowas ergibt einen schlanken Code.

Ich geb mal ein Beispiel zur Erläuterung:
1
/* Die Varianten der Pinfunktionen */
2
#define  noPin      4     /* für nicht vorhandene Pins */ 
3
#define  ANALOG     0     /* analoger Eingang (oder Ausgang?) */ 
4
#define  OUT_10     1     /* out, 10 MHz */ 
5
#define  OUT_2      2     /* out,  2 MHz */ 
6
#define  OUT_50     3     /* out, 50 MHz */ 
7
#define  IN         4     /* digitaler Eingang */ 
8
#define  OUT_10_OD  5     /* out, 10 MHz, OpenDrain */ 
9
#define  OUT_2_OD   6     /* out,  2 MHz, OpenDrain */ 
10
#define  OUT_50_OD  7     /* out, 50 MHz, OpenDrain */ 
11
#define  IN_PUPD    8     /* digitaler Eingang, Pullup/down je nach GPIOx_ODR */ 
12
#define  ALTF_10    9     /* Alternativ-Funktion, 10 MHz */ 
13
#define  ALTF_2     10    /* Alternativ-Funktion,  2 MHz */ 
14
#define  ALTF_50    11    /* Alternativ-Funktion, 50 MHz */ 
15
#define  verboten   12    /* nicht benutzen! */ 
16
#define  ALTF_10_OD 13    /* Alternativ-Funktion, 10 MHz, OpenDrain */ 
17
#define  ALTF_2_OD  14    /* Alternativ-Funktion,  2 MHz, OpenDrain */ 
18
#define  ALTF_50_OD 15    /* Alternativ-Funktion, 50 MHz, OpenDrain */

Mit sowas kann man arbeiten, um sich die Funktionalität der Ports lesbar 
einstellen zu können. Wieder ein Beispiel:
1
/* Port A: */
2
#define wf_PA0      ANALOG            /* an Vcc/2+JP3, usart2cts,adc,tim2,wkup*/
3
#define wf_PA1      IN_PUPD           /* an JP3, usart2rts,adc,tim2*/
4
#define wf_PA2      ALTF_50           /* STlink-TX, usart2tx,adc,tim2*/
5
#define wf_PA3      IN                /* STlink-RX usart2rx,adc,tim2*/
6
#define wf_PA4      IN_PUPD           /* an JP2, spi1nss,usart2ck,adc*/
7
#define wf_PA5      IN                /* T_JTCK auch an PB13, spi1sck,adc*/
8
#define wf_PA6      IN_PUPD           /* an JP2, spi1miso,adc,tim3,*/
9
#define wf_PA7      IN_PUPD           /* an JP2, spi1mosi,adc,tim3*/
10
#define wf_PA8      ALTF_50           /* MCO an JP2, usart1ck,tim1,mco*/
11
#define wf_PA9      ALTF_50           /* TX an XPRG, usart1tx,tim1*/
12
#define wf_PA10     IN                /* RX an XPRG, usart1rx,tim1*/
13
#define wf_PA11     ALTF_50           /* USB-,  usart1cts,canrx,tim1,usbdm*/
14
#define wf_PA12     ALTF_50           /* USB+, usart1rts,cantx,tim1,usbdp*/
15
#define wf_PA13     IN                /*  jtms,swdio*/
16
#define wf_PA14     IN                /*  jtck,swclk*/
17
#define wf_PA15     IN_PUPD           /* an JP3, jtdi*/

Das "wf_xxx" ist nur Konvention: "Wert Für" portbezeichnung.

Die o.g. Akrobatik sieht natürlich wüst aus:
1
#define wf_GPIOA_CRL  (wf_PA0 | (wf_PA1<<4) | (wf_PA2<<8)  | (wf_PA3<<12)  | (wf_PA4<<16)  | (wf_PA5<<20)  | (wf_PA6<<24)  | (((unsigned)wf_PA7)<<28))
2
#define wf_GPIOA_CRH  (wf_PA8 | (wf_PA9<<4) | (wf_PA10<<8) | (wf_PA11<<12) | (wf_PA12<<16) | (wf_PA13<<20) | (wf_PA14<<24) | (((unsigned)wf_PA15)<<28))
Aber dort muß man nach dem gründlichen Austesten nie wieder heran.
Ähnlich kann man es halten mit den Einstellungen für andere Zwecke wie 
AHB, APB1/2 usw. Zuerst ein rein optisch gut überschaubarer Teil mit 
Bezeichnern, die man gut erfassen kann und weiter hinten dann der 
Kruscht, den man nur einmal gründlich austesten muß und der dann immer 
gleich bleibt.

W.S.

von Stefan F. (Gast)


Lesenswert?

> MODIFY_REG(GPIOA->MODER,
>     GPIO_MODER_MODER0+
>     GPIO_MODER_MODER1+
>     GPIO_MODER_MODER2+...

W.S. schrieb:
> Und was ist daran ein "sprechender" Name?

So heißen die Register und Bitfelder halt auch im Referenzhandbuch.

> GPIOA->MODER

Ist das MODER Register vom Port GPIOA

> MODER0

Ist das MODER Feld für Pin 0

Dementsprechend ist GPIO_MODER_MODER0 die Bitmaske für das Feld MODER0 
im MODER Register von Port GPIOA. Ich finde das total logisch. Ist zwar 
anders als bei AVR, aber auch gut.

von W.S. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> W.S. schrieb:
>> Und was ist daran ein "sprechender" Name?
>
> So heißen die Register und Bitfelder halt auch im Referenzhandbuch.
>
>> GPIOA->MODER
>
> Ist das MODER Register vom Port GPIOA
>
>> MODER0
>
> Ist das MODER Feld für Pin 0

Grandios! Und warum rezitierst du dann in einer das Refman? Kein Mensch 
will da wissen, daß im GPIOA_MODER sowas wie die Elemente 
GPIO_MODER_MODER_0..x enthalten sind, das kann jeder (so er will) alles 
im RefManual nachlesen.

Was hingegen ein jeder gern mag, ist auf einfache und übersichtliche 
Weise angeben zu können, daß zum Beipiel
PA3 = analog
und PB4 = input
und PC2 = Alternativfunktion
sein sollen.
Das ist hilfreich.

Aber irgendwelche Funktionen a la
  MODIFY_REG(Register, Bit0+Bit1+Bit2+....+sonstwas)
sind überhaupt nicht hilfreich. Bei sowas muß man sich neben das RefMan 
seinen Notizblock legen und manuell den ganzen Parameter-Kruscht 
zusammenstellen. Unbequemer geht's garantiert nicht.

W.S.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> Was hingegen ein jeder gern mag, ist auf einfache und übersichtliche
> Weise angeben zu können, daß zum Beipiel
> PA3 = analog
> und PB4 = input
> und PC2 = Alternativfunktion
> sein sollen.
> Das ist hilfreich.

Kannst du haben, in Form der HAL. Jeder so wie er mag.

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.