Forum: Mikrocontroller und Digitale Elektronik STM32F4: Port Konfiguration überschreiben


von Christian J. (Gast)


Lesenswert?

Moin,

eigentlich ganz einfach: Ich möchte im Programm an mehreren Stellen Port 
Bits einstellen für die jeweilige Hardware und zwar dort, wo die HW auch 
verwendet wird und nicht einmal global und dann nie wieder.
1
/* Init des 7 Segment Treibers auf SPI 1 */
2
void Init_MAX7219() {
3
4
    GPIO_InitTypeDef GPIO_InitStruct;
5
    SPI_InitTypeDef SPI_InitStruct;
6
7
   /* ----- PE5 als CS konfigurieren -------- */
8
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE,ENABLE);
9
    GPIO_SetBits(GPIOE,SEG7_CS);                         // Glitch vermeiden CS = HIGH (DISABLE)
10
    GPIO_InitStruct.GPIO_Pin    = SEG7_CS;
11
    GPIO_InitStruct.GPIO_Mode   = GPIO_Mode_OUT;
12
    GPIO_InitStruct.GPIO_Speed  = GPIO_Speed_50MHz;
13
    GPIO_InitStruct.GPIO_OType  = GPIO_OType_PP;
14
    GPIO_InitStruct.GPIO_PuPd   = GPIO_PuPd_UP;
15
    GPIO_Init(GPIOE, &GPIO_InitStruct);
16
17
    [.......]

Trotz Debuggen lässt sich nicht herausfinden, wie ich es vermeide, dass 
ich eine alte Konfiguration auf PORTE überschreibe, die schon frueher 
gemacht wurde wo zb Bit 3,8.9,.. definiert wurden.

Es gibt die Funktion

GPIO_StructInit (&GPIO_InitStructure);

die mir den Struct auf Default stellt. Gibt es auch eine Funktion, die 
mir die bisherige Konfiguration einliest, dann schreibe ich etwas dazu 
und update den Port nur?

Zum Vergleich: Beim AVR lese ich das "Data Diretion Register" ein, model 
mein Bit dazu und schreibe es zurück.

Ich hoffe das war jetzt verständlich beschrieben :-)

Gruss,
Christian

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Christian J. schrieb:
> GPIO_InitTypeDef GPIO_InitStruct;

Das könntest du zur globalen Variablen machen, dann besser z.B. als
1
GPIO_InitTypeDef GPIOE_InitStruct;
Mit Ports habe ich das bisher nicht gebraucht, aber für z.B. Timer, die 
ich On-the-fly umkonfigurieren möchte, klappt das gut.
So hast du die Konfiguration immer vorrätig.

von Martin (Gast)


Lesenswert?

Die Structs Inits machen ein Read modify Write. Also einfach immer neu 
befüllen und wieder aufrufen.

von Christian J. (Gast)


Lesenswert?

Martin schrieb:

> Die Structs Inits machen ein Read modify Write. Also einfach immer neu
> befüllen und wieder aufrufen.

Hmmm.... ok. Ich probiere dann auch mal mit dem LOCK Bit aus, wie man 
das alles dann sperren kann, wenn es einmal richtig steht. Ganz so 
trivial sind die Ports ja nicht.

von Torsten C. (torsten_c) Benutzerseite


Lesenswert?

Matthias S. schrieb:
> Das könntest du zur globalen Variablen machen

Was soll das bringen?

von msx (Gast)


Lesenswert?

Christian J. schrieb:
> Ganz so trivial sind die Ports ja nicht.

Oh doch, man muß es nur machen. Ein Beispiel:

// Routinen zur Ausgabe auf LCD 2x16

uint8_t lcd_status(void)   // oberstes Bit ist busy-flag, Rest: Adresse
{
  uint8_t temp = 0;
// Datenleitungen auf Eingang
  GPIOD->MODER &= ~(3<<LCD_D4*2 | 3<<LCD_D5*2 | 3<<LCD_D6*2 | 
3<<LCD_D7*2);

  GPIOD->BSRRL = LCD_READ;              // setzen
  GPIOD->BSRRH = LCD_CMD;               // loeschen
  warte_1us();
  GPIOD->BSRRL = LCD_STROBE;            // setzen
  warte_1us();
  temp = (GPIOD->IDR >> 8) & 0xf0;      // oberes nibble zuerst
  GPIOD->BSRRH = LCD_STROBE;
  warte_1us();
  GPIOD->BSRRL = LCD_STROBE;
  warte_1us();
  temp |= (GPIOD->IDR >> 12) & 0x0f;    // unteres nibble zuletzt
  GPIOD->BSRRH = LCD_STROBE | LCD_READ;
  warte_1us();
// Datenleitungen wieder auf Ausgang
  GPIOD->MODER |= (1<<LCD_D4*2 | 1<<LCD_D5*2 | 1<<LCD_D6*2 | 
1<<LCD_D7*2);
  warte_1us();
  return(temp);                         // busy-flag + Adresse
}

von Christian J. (Gast)


Lesenswert?

msx schrieb:
> Oh doch, man muß es nur machen. Ein Beispiel:
>
> // Routinen zur Ausgabe auf LCD 2x16

Du benutzt aber Register, was ich konsequent nicht tue, um mich nicht an 
der StdPeriphLib vorbei zu mogeln und weil ich das total unüberschaubar 
finde. Die Zeiten erinnern mich noch an die Vor-Cortex Phase :-(

Inzwischen sehe ich da auch klarer, die Struct Funktionen ver-odern 
alles
nur, nachdem die es ver-unded haben. Was einmal gesetzt wurde muss 
explizit zurückgesetzt werden.

Da, erst wird das alte Bit gelöscht, dann das neue einmaskiert:
GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pinpos * 2));
GPIOx->OSPEEDR |= ((uint32_t)(GPIO_InitStruct->GPIO_Speed) << (pinpos * 
2));

1
/**
2
  * @brief  Initializes the GPIOx peripheral according to the specified parameters in the GPIO_InitStruct.
3
  * @param  GPIOx: where x can be (A..K) to select the GPIO peripheral for STM32F405xx/407xx and STM32F415xx/417xx devices
4
  *                      x can be (A..I) to select the GPIO peripheral for STM32F42xxx/43xxx devices.
5
  *                      x can be (A, B, C, D and H) to select the GPIO peripheral for STM32F401xx devices.
6
  * @param  GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that contains
7
  *         the configuration information for the specified GPIO peripheral.
8
  * @retval None
9
  */
10
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
11
{
12
  uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;
13
14
  /* Check the parameters */
15
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
16
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));
17
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
18
  assert_param(IS_GPIO_PUPD(GPIO_InitStruct->GPIO_PuPd));
19
20
  /* ------------------------- Configure the port pins ---------------- */
21
  /*-- GPIO Mode Configuration --*/
22
  for (pinpos = 0x00; pinpos < 0x10; pinpos++)
23
  {
24
    pos = ((uint32_t)0x01) << pinpos;
25
    /* Get the port pins position */
26
    currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
27
28
    if (currentpin == pos)
29
    {
30
      GPIOx->MODER  &= ~(GPIO_MODER_MODER0 << (pinpos * 2));
31
      GPIOx->MODER |= (((uint32_t)GPIO_InitStruct->GPIO_Mode) << (pinpos * 2));
32
33
      if ((GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT) || (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_AF))
34
      {
35
        /* Check Speed mode parameters */
36
        assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
37
38
        /* Speed mode configuration */
39
        GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pinpos * 2));
40
        GPIOx->OSPEEDR |= ((uint32_t)(GPIO_InitStruct->GPIO_Speed) << (pinpos * 2));
41
42
        /* Check Output mode parameters */
43
        assert_param(IS_GPIO_OTYPE(GPIO_InitStruct->GPIO_OType));
44
45
        /* Output mode configuration*/
46
        GPIOx->OTYPER  &= ~((GPIO_OTYPER_OT_0) << ((uint16_t)pinpos)) ;
47
        GPIOx->OTYPER |= (uint16_t)(((uint16_t)GPIO_InitStruct->GPIO_OType) << ((uint16_t)pinpos));
48
      }
49
50
      /* Pull-up Pull down resistor configuration*/
51
      GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << ((uint16_t)pinpos * 2));
52
      GPIOx->PUPDR |= (((uint32_t)GPIO_InitStruct->GPIO_PuPd) << (pinpos * 2));
53
    }
54
  }
55
}

von Christian J. (Gast)


Lesenswert?

Was ich noch nicht ganz kapiere ist bei der SPI, die auch funktioniert
was der Unterschied zwischen

SPI_Direction_Tx
und
SPI_Direction_1ine_Tx

ist. Ich gebe nur an einen Max7219 aus, diese billigen ebay 7 Segment 
Anzeigen vom Arduino, brauche keine MISO Leitung und schalte die auch 
nicht auf AF Mode um. Beides funktioniert aber.


/* Die SPI1 einstellen */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
    SPI_StructInit(&SPI_InitStruct);
    SPI_InitStruct.SPI_Direction = SPI_Direction_Tx;
    SPI_InitStruct.SPI_Mode      = SPI_Mode_Master;
    SPI_InitStruct.SPI_DataSize  = SPI_DataSize_16b;
    SPI_InitStruct.SPI_CPOL      = SPI_CPOL_Low;
    SPI_InitStruct.SPI_CPHA      = SPI_CPHA_1Edge;
    SPI_InitStruct.SPI_NSS       = SPI_NSS_Soft;
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
    SPI_Init(SPI1, &SPI_InitStruct);

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Torsten C. schrieb:
> Matthias S. schrieb:
>> Das könntest du zur globalen Variablen machen
>
> Was soll das bringen?

Du hast die Konfiguration immer parat und kannst sie On-the-Fly ändern, 
z.B. um im Betrieb mal einen Ausgang zum Eingang zu machen.
Da Christian jetzt aber von 'Lock' redet und sie anscheinend doch nicht 
mehr

Christian J. schrieb:
> an mehreren Stellen Port
> Bits einstellen für die jeweilige Hardware und zwar dort, wo die HW auch
> verwendet wird und nicht einmal global und dann nie wieder.
will, scheint sich das ja erledigt zu haben.
Ansonsten reicht es dann eben, wenn die Struct einmal fertig ist, sie 
nur zu ändern und dann wieder die GPIOInit() aufzurufen.

: Bearbeitet durch User
von msx (Gast)


Lesenswert?

Christian J. schrieb:
> Du benutzt aber Register, was ich konsequent nicht tue, um mich nicht an
> der StdPeriphLib vorbei zu mogeln und weil ich das total unüberschaubar
> finde. Die Zeiten erinnern mich noch an die Vor-Cortex Phase :-(

Anstelle der StdPeriphLib nehme ich gezielt genaue Warteschleifen, wie 
"warte_1us()"; ansonsten die ...Lib nur zur Initialisierung.

Nichts zeigt besser den Inhalt der PORT-Register an als diese selbst!

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.