Forum: Mikrocontroller und Digitale Elektronik [STM32F4] Port mit Zählereingang ETR verbinden


von timertick_t (Gast)


Lesenswert?

Problem: Timer3, als Zähler für externe Impulse geschaltet, zählt nicht.
Dazu muß z.B. der Porteingang Port A3 mit Timer3 verbunden werden (siehe 
Bild).
Die elektrische Seite ist ok, als normaler Eingang funktioniert der 
Port.

Es gibt einige Beispiele im Netz, allerdings sind diese nicht für die 
HAL-Bibliothek geschrieben. Insofern nutzen sie mir eigentlich nichts.

Mutmaßung:
Um externe Impulse zählen zu können, kann z.B. Port A3 auf den TIMx_ETR 
Eingang gelegt werden. Dazu gibt es die 'alternative-function' Register 
TIM3->AFR[0] und TIM3->AFR[1]. AFR[0] habe ich mit
1
    GPIOA->AFR[0] &= ~0x0000F000; // clean bitfield first
2
    GPIOA->AFR[0] |= (GPIO_AF2_TIM3) << (3*4); //alternative function Timer/Counter3 input. Shift 4 bits to bit3 pos
3
    /* 3) set port properties*/
4
5
6
    /* Configure PA3 pin as input floating */
7
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT; 
8
    //GPIO_InitStructure.Mode = GPIO_AF2_TIM3; // 2) set Alternative function
9
    GPIO_InitStructure.Pull = GPIO_PULLUP;
10
    GPIO_InitStructure.Pin = GPIO_PIN_3;
11
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
beschrieben.

Stimmt das denn? Irritierend ist, daß es zwar für die 
Ausgangsbeschaltung Alternativfunktionen gibt, aber offensichtlich NICHT 
für die Eingänge.


Nach Angabe des Kochrezepts würde das ausreichen:
For example, to configure the upcounter to count each 2 rising edges on 
ETR, use the following procedure:
1. As no filter is needed in this example, write ETF[3:0]=0000 in the 
TIMx_SMCR register.
2. Set the prescaler by writing ETPS[1:0]=01 in the TIMx_SMCR register
3. Select rising edge detection on the ETR pin by writing ETP=0 in the 
TIMx_SMCR
register
4. Enable external clock mode 2 by writing ECE=1 in the TIMx_SMCR 
register.
5. Enable the counter by writing CEN=1 in the TIMx_CR1 register.
The counter counts once each 2 ETR rising edges.


Im Register TIM3->SMCR ist somit lediglich
Bit 14 ECE: External clock enable und ein Vorteiler-Bit (Bit 13 gesetzt.
  TIM3->SMCR = 0x00005000;
Ich habe noch andere Varianten mit:
Bits 6:4 TS: Trigger selection
This bit-field selects the trigger input to be used to synchronize the 
counter.
111: External Trigger input (ETRF)
getestet, bin aber auch nicht weiter gekommen.



Der Code:
1
void port_counter_init(void){
2
    /* 1) First and foremost: Enable GPIOA clock */
3
    COUNTER_TEST_GPIO_CLK_ENABLE();
4
5
    /* 2) set Alternative function */
6
    //Obviously there is no function available which sets the AF bits. So we do this by hand-
7
    GPIOA->AFR[0] &= ~0x0000F000; // clean bitfield first
8
    GPIOA->AFR[0] |= (GPIO_AF2_TIM3) << (3*4); //alternative function Timer/Counter3 input. Shift 4 bits to bit3 pos
9
    /* 3) set port properties*/
10
11
12
    /* Configure PA3 pin as input floating */
13
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
14
    //GPIO_InitStructure.Mode = GPIO_AF2_TIM3; // 2) set Alternative function
15
    GPIO_InitStructure.Pull = GPIO_PULLUP;
16
    GPIO_InitStructure.Pin = GPIO_PIN_3;
17
    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
18
19
    /* 4) First and foremost: Enable TIM3 clock */
20
    COUNTER_TEST_CLK_ENABLE();
21
22
    /* 5) set timer/counter properties */
23
    //TIM_HandleTypeDef TimHandle; //already defined;
24
25
    /* Set TIMx instance */
26
    TimHandle.Instance = TIMx;
27
28
    TimHandle.Init.Period = 1000;
29
    TimHandle.Init.Prescaler = 0;
30
    TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
31
    TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
32
    HAL_TIM_Base_Init(&TimHandle);
33
34
35
    sSlaveConfig.InputTrigger = TIM_TS_ETRF;
36
    sSlaveConfig.SlaveMode = TIM_SLAVEMODE_EXTERNAL1;
37
    sSlaveConfig.TriggerFilter = 0;
38
    sSlaveConfig.TriggerPolarity = TIM_TRIGGERPOLARITY_NONINVERTED;
39
    sSlaveConfig.TriggerPrescaler = TIM_TRIGGERPRESCALER_DIV1;
40
    HAL_TIM_SlaveConfigSynchronization(&TimHandle, &sSlaveConfig);
41
42
}
43
44
in main:
45
46
  TIM3->CNT = 0x0;
47
48
 // TIM3->SMCR = 0x00005070; //Bits 6:4 TS: Trigger selection => '7'
49
  TIM3->SMCR = 0x00005000;
50
51
  HAL_TIM_Base_Start(&TimHandle); // = TIM3->CR1 |= TIM_CR1_CEN; //enable
52
  //Zähler ist gestartet...
53
54
55
  debug_viewRegister(&TIM3->SMCR,
56
                 "TIM3->SMCR");
57
58
  GPIOA->MODER |= 0x80;
59
60
  debug_viewRegister(&GPIOA->MODER,
61
                   "GPIOA->MODER");
62
63
  debug_viewRegister(&GPIOA->AFR[0],
64
                   "GPIOA->AFR[0]");
65
66
  //Anzeige der gezählten Impulse
67
  while (!BSP_PB_GetState(BUTTON_KEY));
68
  BSP_LED_On(LED6);
69
70
   //hier sollte das Zählergebnis zu sehen sein.
71
   debug_viewRegister(&TIM3->CNT,
72
                 "TIM3->CNT");
73
74
   while (1);  //END

Ich sitze jetzt schon viele Stunden dran und komme nicht weiter. Hat 
jemand eine Idee?

von timertick_t (Gast)


Angehängte Dateien:

Lesenswert?

Bild vergessen...

von Little B. (lil-b)


Lesenswert?

timertick_t schrieb:
> /* Configure PA3 pin as input floating */
>     GPIO_InitStructure.Mode = GPIO_MODE_INPUT;

NOOOO! WRONG!!!

timertick_t schrieb:
> Irritierend ist, daß es zwar für die
> Ausgangsbeschaltung Alternativfunktionen gibt, aber offensichtlich NICHT
> für die Eingänge.


Alternate function ist alternate function. ob das dann ein Eingang oder 
ein Ausgang ist, liegt bei der gemappten hardware.
Im Fall von Tim3 ist das dann ein Eingang

also:
1
GPIO_InitStructure.Mode = GPIO_MODE_AF;

von timertick_t (Gast)


Lesenswert?

>GPIO_InitStructure.Mode = GPIO_MODE_AF;
Das geht gleich aus mehreren Gründen nicht.
Wie ich oben schrieb:
Es gibt einige Beispiele im Netz, allerdings sind diese nicht für die
HAL-Bibliothek geschrieben.
GPIO_MODE_AF gibt's in der HAL lib nicht. Aber selbst wenn es es gäbe, 
mutzt es nichts, der Zahlenwert der dahinter steht bezieht sich nur auf 
mögliche OUTPUT-Funktionen:
1
#define  GPIO_MODE_AF_PP                        ((uint32_t)0x00000002)   /*!< Alternate Function Push Pull Mode     */
2
#define  GPIO_MODE_AF_OD                        ((uint32_t)0x00000012)   /*!< Alternate Function Open Drain Mode    */

OUTPUT also.
Nicht Input.


Auch wird in
HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
nur eine der beiden Output-Möglichkeiten in die Alternative-Function 
Register eingetragen:
1
void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
2
{
3
   .
4
   .
5
   .
6
      /*--------------------- GPIO Mode Configuration ------------------------*/
7
      /* In case of Alternate function mode selection */
8
      if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
9
      {
10
        /* Check the Alternate function parameter */
11
        assert_param(IS_GPIO_AF(GPIO_Init->Alternate));
12
        /* Configure Alternate function mapped with the current IO */
13
        temp = GPIOx->AFR[position >> 3];
14
        temp &= ~((uint32_t)0xF << ((uint32_t)(position & (uint32_t)0x07) * 4)) ;
15
        temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & (uint32_t)0x07) * 4));
16
        GPIOx->AFR[position >> 3] = temp;
17
      }
18
   .
19
   .
20
   .
21
}

von Little B. (lil-b)


Lesenswert?

Ich wiederhole:
Alternate function ist Alternate function.
Liest du das Reference Manual, siehst du, dass das Mode-Register 4 Modi 
kennst:
00: input
01: output
10: AF
11: Analog

Dieses Register MUSS auf AF stehen, damit der Timer den Pin verwenden 
kann.

Um auf deinen Post einzugehen:
Es gibt ein weiteres Register, das OTYPER (output type register), wo man 
entscheiden kann, ob der output Treiber PP oder OD verwenden soll. Will 
nun die Alternate Function Hardware den Pin aktiv treiben, so wird diese 
Einstellung verwendet. Nutzt die Alternate Function den Pin jedoch als 
Input, so ist dieses Register völlig egal.

Schreibe
1
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
und es wird funktionieren.

von timertick_t (Gast)


Lesenswert?

Ich kann in das entsprechende Register TIM3->AFR[0] den Wert für die 
Alternativ-Funktion AF2 (TIM3..5) eintragen. Aber das alleine scheint 
nicht auszureichen.

Meine Vermutung:
Für einen verknüpften Ausgang des Timers macht
1
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
im Prinzip Sinn, für den Trigger-Eingang TIMxETR nicht. Vielleicht geht 
meine ganze Denke in die falsche Richtung und der Eingang TIMxETR wird 
ganz anders angesprochen.

von timertick_t (Gast)


Lesenswert?

>GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
Hab's jezt mal eingetragen. Alle Register sind soweit glaubwürdig:

GPIO->MODER = 0xA80000A0
A8000000 =  Reset, dazu kommen die unteren Bits für A0 = bit6 + bit7 = 
Alternative function aktiv.

GPIO->AFR[0] = 0x00002700
"2" für Alternative function TIM3..5, die wilde "7" für den UART der 
nebenher werkelt.

TIM3->SMCR = 0x00005000
Bit 14 ECE: External clock enable und Bit13 für den Vorteiler.

TIM3->CR1 = 0x00000001
Bit 0 CEN: Counter enable.

Wenn ich nun den Taster betätige sollten eigentlich der Zähler auf 
Impulse reagieren. Macht er aber nicht...

von Dieter Graef (Gast)


Lesenswert?

Grad mal mit der freien Software STM32CubeMx geschaut. Danach ist der 
Port PA3 gar nicht mit TIM3 verbunden sondern z.B. PA6 mit Kanal 1 vom 
Timer 3. Die von der Software generierte Portinitialisierung sieht dann 
so aus:
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

von timertick_t (Gast)


Lesenswert?

>GPIO_InitStruct.Pin = GPIO_PIN_6;
Eigentlich ist der gewählte Pin egal, damit wirbt ST ja sogar im 
Datenblatt irgendwo.

>GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
Die Zeile hier ist komfortabel, ich hatte die entsprechenden Bits von 
Hand eingetragen...

- - -

Hab eben mal die Konfiguration mit Pin 6, also Port A6 ausprobiert - 
ändert im Prinzip aber nicht an meinem Ergebnis. Ich sehe wie die 
Konfigurationsbits brav mitwandern, aber TIM3->CNT verändert bei 
Impulsen an PORT A6 nicht den Zählerstand.

Als ob der Zähler nicht aktiv wäre oder die Impulse nicht durchgereicht 
werden... oder... könnte es sein, daß das Auto-Reload Register den 
Counter blockiert? Das wär ja n Ding. Gleich mal guggen.

von Little B. (lil-b)


Lesenswert?

Falsches Pinmapping, darauf hab ich an der Stelle noch gar nicht 
geachtet...

Ja, der Einwand ist richtig:
PA3 ist auf Tim5_Ch4 gemappt
PA6 ist auf Tim3_Ch1 gemappt

Du benötigst aber Tim3_ETR, und der hängt an PD2 (und leider auch NUR 
da)

Dass ein Mikrocontroller JEDE peripherie auf JEDEN pin legen kann, hab 
ich noch nie gesehen. Das ist auch gar nicht machbar von seiten des 
Chipetwicklers.

Tatsache ist, dass der STM32F4 sehr flexibel ist, was die Pins angeht. 
Sind die Pins von Timer3 alle schon belegt, kannst du evtl alternative 
Pins nehmen, wenns denn solche gibt. Ansonsten wechselst du auf einen 
anderen Timer, der das selbe kann, aber andere Pins verwendet.

von timertick_t (Gast)


Lesenswert?

Danke für die Unterstützung.


>Du benötigst aber Tim3_ETR, und der hängt an PD2 (und leider auch NUR
>da)
Uiii.
Das erklärt vieles...
Wo finde ich diesen Hinweis im Datenblatt eigentlich?

von timertick_t (Gast)


Lesenswert?

HURRA!

Die Zuweisung war's das Problem. Ich war ganz am Anfang unsicher ob der 
Port auch angesprochen wird, weil ich im Datenblatt nichts 
ausdrückliches über PORT D6 und TIM3_ETR fand. Dann vermutete ich, daß 
die Ports "highly flexible" zugewiesen werden können...


Uff. Nu läuft das Ding. Ein großes Danke an alle Beteiligten.

von timertick_t (Gast)


Lesenswert?

>ausdrückliches über PORT D6 und TIM3_ETR fand.
D2, nicht D6.

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.