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
voidport_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
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:
>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:
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
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.
>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...
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);
>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.
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.
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?
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.