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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Tobias P. (hubertus)


Bewertung
0 lesenswert
nicht 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. (lkmiller) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht 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:

Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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


Bewertung
-2 lesenswert
nicht 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)


Bewertung
-1 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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:

Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.