Forum: Mikrocontroller und Digitale Elektronik STM32 Counter zählt falsch?!


von Tobias P. (hubertus)


Lesenswert?

Hallo

ich will grade mit einem STM32 Timer 2 Impulse zählen.
Und zwar habe ich ein Impulspaket, wo während ca. 2 Sekunden ein Takt 
von 4.5MHz anliegt, danach kommt eine Pause von einigen Sekunden, danach 
kommen wieder für 2 Sekunden die 4.5MHz und so weiter. Ich will die 
Anzahl der Zyklen während des 2 Sekunden-Fensters zählen.
Glucklicherweise habe ich ein externes Signal, welches ankündigt, wann 
das Zeitfenster beginnt, und wann es endet.

Daher dachte ich ich kann folgendes machen:
- den Timer 2 (hat 32 Bit) konfigurieren als Counter, welcher vom 
externen Taktsignal getaktet wird.
- das Hilfssignal wird mit einem GPIO abgefragt.
- Der Counter zählt die Impulse. Wenn das Hilfssignal logisch 0 wird, 
ist das Zeitfenster vorüber und es kommen keine Impulse mehr und ich 
kann den Zählerstand auswerten.
- Danach wird der Zähler zurückgesetzt und man wartet, bis das 
Hilfssignal wieder 0 wird.

Grundsätzlich funktioniert es, wie es soll, ABER mein Timer 2 zählt 
immer doppelt so viele Impulse wie er soll! :-)
Ich habe es mit einem HP 5315B Universalzähler verifiziert. Der HP zählt 
gut 9000000 Takte. Das wäre O.K. Der STM32 zählt aber 18000000 Takte! 
und ich kann mir nicht erklären wieso. Edge Detector habe ich geprüft, 
der ist auf 'rising' konfiguriert, müsste also passen.

Anmerken muss man, dass mein externes Signal ca. 5 V Amplitude hat, 
weshalb ich einen 1kOhm Seriewiderstand verbaut habe, um den STM32 nicht 
zu grillieren.
Momentan benutze ich das Discovery Board. Als Takt für den STM wird der 
8MHz Quarz verwendet, die PLL ist auf 160 MHz konfiguriert.

Hier mein Code:
1
RCC->AHB1ENR |= (1u << 0); // enable gpio a
2
GPIOA->MODER |= (2u << 0); // pa0 = alternate function
3
GPIOA->AFR[0] |= (1u << 0); // pa0 = tim2_ch1 input
4
5
RCC->APB1ENR |= (1u << 0); // enable timer2
6
7
// reset timer
8
TIM2->CR1 = 0;
9
TIM2->CR2 = 0;
10
11
TIM2->SMCR = (4u << 4) | (7u << 0); // select edge detector as trigger, count on TI1F_ED
12
TIM2->CCER = 0; // disable all channels (otherwise ccmr is not writable)
13
TIM2->CCMR1 = (2u << 0); // select TI1 input for channel 1
14
TIM2->CR1 = 1; // counter enable
15
16
while(1)
17
{
18
  uint32_t a;
19
20
  // led off, wait until trigger signal goes low
21
  GPIOD->BSRRH = 1<<12;
22
  do
23
  {
24
    a = GPIOD->IDR;
25
  } while(a & (1u << 11));
26
27
  // led on
28
  GPIOD->BSRRL = 1<<12;
29
30
  // read & reset counter
31
  static uint32_t cnt = 0;
32
  cnt = TIM2->CNT;
33
  TIM2->CR1 &= ~1;
34
  TIM2->CNT = 0;
35
  TIM2->CR1 |= 1;
36
37
  // wait until trigger signal goes high
38
  do
39
  {
40
    a = GPIOD->IDR;
41
  } while(!(a & (1u << 11)));
42
}

Das Triggersignal liegt am PD11 und das Signal, dessen Zyklen zu zählen 
sind liegt an PA0. Ich sehe grade den Fehler nicht. Ist Jahre her seit 
ich zum letzten mal mit einem STM was gemacht habe :-(

Wer sieht das Problem?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Tobias P. schrieb:
> Wer sieht das Problem?
Wie sieht das Signal am Pin mit dem Oszi aus? Klingelt da was? Schwingt 
da was über? Was ist die Triggerschwelle des HP?

von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

übrigens hätte ich gern den Timer direkt mit dem Triggersignal gestartet 
und gestoppt. Allerdings gefällt mir nicht, dass es diesen Delay gibt 
aufgrund der Synchronisationslogik. Ich denke, aufgrund dieses Delays 
kann man sich gut um einzelne Pulse verzählen :-(

von pegel (Gast)


Lesenswert?

Wenn du verkraften kannst, dass die erste Messung falsch ist, kannst du 
auch immer zählen und erst wenn das Triggersignal abschaltet mit einem 
Interrupt den Zähler auswerten und zurücksetzten.

von Ruediger A. (Firma: keine) (rac)


Lesenswert?

Vorsicht, beliebte Falle beim STM32: Der hat intern zwei Busse, von 
denen der eine nur halb so schnell getaktet ist. Manche Timer hängen auf 
dem einen Bus, manche auf dem Anderen. Studier mal das Datenblatt deines 
POD bzgl. clock tree (ich habe gerade keinen Zugang dazu, sorry).

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Und durch diesen Registerwust dürfen sich jetzt die Leser wühlen?
1
RCC->AHB1ENR |= (1u << 0); // enable gpio a
2
GPIOA->MODER |= (2u << 0); // pa0 = alternate function
3
GPIOA->AFR[0] |= (1u << 0); // pa0 = tim2_ch1 input
4
5
RCC->APB1ENR |= (1u << 0); // enable timer2
6
7
// reset timer
8
TIM2->CR1 = 0;
9
TIM2->CR2 = 0;
10
11
TIM2->SMCR = (4u << 4) | (7u << 0); // select edge detector as trigger, count on TI1F_ED
12
TIM2->CCER = 0; // disable all channels (otherwise ccmr is not writable)
13
TIM2->CCMR1 = (2u << 0); // select TI1 input for channel 1
14
TIM2->CR1 = 1; // counter enable

Verwende doch bitte die StdPeriphLibrary ... Dann ist es wenigstens 
leserlich ... ;-)

von Tobias P. (hubertus)


Lesenswert?

Mampf F. schrieb:
> Verwende doch bitte die StdPeriphLibrary ... Dann ist es wenigstens
> leserlich ... ;-)

Nein. Diese Lib finde ich unermesslich hässlich. Will ich nicht und 
werde ich nie einsetzen :-)
Wende doch du bitte die normalen Registerzugriffe an.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Tobias P. schrieb:
> Nein. Diese Lib finde ich unermesslich hässlich. Will ich nicht und
> werde ich nie einsetzen :-)

Wie du willst - reduziert halt die Hilfe, die du erwarten kannst xD

> Wende doch du bitte die normalen Registerzugriffe an.

Die StdPeriphLib ist doch nur ein Wrapper um die normalen 
Registerzugriffe herum und auf das Minimum reduziert - aber immerhin 
leserlich, bewährt und vielfach verwendet :)

Lass mich raten - du hast vorher AVRs programmiert? ;-)

So, ich hör schon auf mit meiner Lästerei ... :)

Ah noch ganz kurz ... Ich hab die Erfahrung gemacht, dass man öfters mal 
die STM32s wechseln muss, weil die nicht alle das gleiche können. Die 
Portierung mit StdPeriphLib war da immer nur minimal und ziemlich 
schmerzfrei ... Aber gut, musst du wissen.

*edit*: Wie sieht denn die Initialisierung deines Clock-Trees aus?

Auch zu Fuß erledigt oder fertigen Startup-Code verwendet?

: Bearbeitet durch User
von Nop (Gast)


Lesenswert?

Mampf F. schrieb:

> Die StdPeriphLib ist doch nur ein Wrapper um die normalen
> Registerzugriffe herum und auf das Minimum reduziert - aber immerhin
> leserlich, bewährt und vielfach verwendet :)

Direkte Registerzugriffe sind genauso leserlich, wenn man vernünftige 
defines für die Bitmasken verwendet - was der OP leider nicht getan hat.

von Nop (Gast)


Lesenswert?

Ich würde erstmal den externen Taktgenerator wegnehmen und stattdessen 
manuell den Takt schalten, mit einem entprellten Schalte natürlich. Also 
vorzugsweise elektronisch. Dann eine steigende Flanke, gucken was im 
Counter ist (1 oder 2), eine fallende und wieder nachsehen (1 oder 2).

von Tobias P. (hubertus)


Angehängte Dateien:

Lesenswert?

so sehen meine Signale aus, also nicht allzu schlimm. Wenn ich an PA0 
einen 1 Hz Clock vom Funktionsgenerator ran gebe, zählt der Timer meiner 
Meinung nach richtig.....

von Martin (Gast)


Lesenswert?

Hallo, du nutzt den TI1_ED, das ist wahrscheinlich Edge detector, daher 
zählt er jede Flanke.

Nutze doch den filtered input 1 oder 2, da kannst du einstellen, ob er 
rising oder falling triggert.

also 5<<4 oder 6<<4 im SMCR Register

von Tobias P. (hubertus)


Lesenswert?

Hi Martin,
ja genau den Edge Detector benutze ich.
Bist du sicher, dass er jede Flanke zählt? das würde die Sache 
allerdings erklären! :-) obwohl ich meine, dass man da 
rising/falling/both edges konfigurieren kann.
Aber ich probiers morgen aus. Danke für den Hinweis!

von Rene K. (xdraconix)


Lesenswert?

Ich weiß nicht welchen STM32 du benutzt... Aaaaber:

Tobias P. schrieb:
> Anmerken muss man, dass mein externes Signal ca. 5 V Amplitude hat,
> weshalb ich einen 1kOhm Seriewiderstand verbaut habe, um den STM32 nicht
> zu grillieren.

Bei den meisten STM32 sind fast alle IOs (außer die ADC Pins) 5V 
tolerant bei 3V3.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Rene K. schrieb:
> Bei den meisten STM32 sind fast alle IOs (außer die ADC Pins) 5V
> tolerant bei 3V3.

Die Angabe "fast alle" ist natürlich etwas sehr schwammig und sagt im 
Grunde nicht viel aus.

Genauer steht es hier ab Seite 47:

http://www.st.com/content/ccc/resource/technical/document/datasheet/ef/92/76/6d/bb/c2/4f/f7/DM00037051.pdf/files/DM00037051.pdf/jcr:content/translations/en.DM00037051.pdf

Die 5V-toleranten Pins sind alle mit FT gekennzeichnet.

Das STM32F04 Discovery sollte mit dem STM32F407VG ausgerüstet sein.

von m.n. (Gast)


Lesenswert?

Rene K. schrieb:
> Bei den meisten STM32 sind fast alle IOs (außer die ADC Pins) 5V
> tolerant bei 3V3.

Es geht hier nicht um die 5V-Toleranz, sondern darum, daß an diesen 
extrem schnellen Zählereingängen auch ganz steilflankige Signale 
erwartet werden.
Per Software kann man die Eingangsfilter der betreffenden Eingänge 
aktivieren und bekommt bei langsamen Signalen saubere Impulse.

Den Code oben tue ich mir nicht an. Es ist jedoch unnötig, irgendwelche 
Pakete zu schnüren. Es reicht, einfach den Zähler durchlaufen zu lassen 
und Zwischenergebnisse per Capture einzufangen.

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.