Forum: Mikrocontroller und Digitale Elektronik STM32 Frequenz Messung (>10MHz)


von Mark W. (mark_wer)


Angehängte Dateien:

Lesenswert?

Hallo Leute :)

Bin seit kurzem im Besitz eines STM32F4 Discovery Boards. Hab nun 
versucht - mit Hilfe von Beiträge hier - mit Capture Interrupt 
Frequenzen zu messen. Leider funktioniert mein Programm nur bis 
Frequenzen <700KHz und sonderlich genau ist es auch noch nicht. Habe 
jetzt schon seit Stunden alles mögliche im Internet durchforstet, aber 
komme auf keine Lösung. Ich würde mich freuen, wenn jemand von euch 
einen Tipp hat oder mir sagen könnte, was ich ändern müsste. Durch den 
Prescaler von 1 sollten Frequenzen bis 10MHz ja kein Problem sein und 
Frequenzen unter 1kHz brauche ich auch nicht. Würde es Sinn machen einen 
anderen Timer+Channel zu nutzen? Habe es schon mal mit Tim2 ausprobiert, 
aber da funktioniert dann gar nichts.. Vielen Dank schon mal im Vorraus 
und noch einen schönen Abend.
1
#include "stm32f4xx_conf.h"
2
3
static uint32_t messwert=0;
4
static float frequenz=0;
5
6
void init(void)
7
{
8
  GPIO_InitTypeDef GPIO_InitStructure;
9
  TIM_ICInitTypeDef TIM_ICInitStructure;
10
  NVIC_InitTypeDef NVIC_InitStructure;
11
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
12
13
  // Clock Enable
14
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
15
16
  // Clock enable
17
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
18
19
  // Config des Pins als AF-Input
20
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
21
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
22
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
23
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
24
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
25
  GPIO_Init(GPIOC, &GPIO_InitStructure);
26
27
  // Alternative-Funktion mit dem IO-Pin verbinden
28
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_TIM3);
29
30
  TIM_TimeBaseStructure.TIM_Period = 65535;
31
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
32
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
33
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
34
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
35
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
36
37
  // Vorteiler einstellen (83 => 1MHz)
38
  TIM_PrescalerConfig(TIM3, 1, TIM_PSCReloadMode_Immediate);
39
40
  // Channel 4
41
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
42
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
43
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
44
  TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
45
  TIM_ICInitStructure.TIM_ICFilter = 0x0;
46
  TIM_ICInit(TIM3, &TIM_ICInitStructure);
47
48
  // Timer enable
49
  TIM_Cmd(TIM3, ENABLE);
50
51
  NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
52
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
53
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
54
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
55
  NVIC_Init(&NVIC_InitStructure);
56
57
  TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);
58
}
59
60
void TIM3_IRQHandler(void)
61
{
62
  static uint16_t pos=0;
63
  static uint32_t t1=0;
64
  static uint32_t t2=0;
65
66
67
  if(TIM_GetITStatus(TIM3, TIM_IT_CC4) == SET) {
68
    // Interrupt Flags loeschen
69
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC4);
70
71
    if(pos==0) {
72
      pos=1;
73
      t1=TIM_GetCapture4(TIM3);
74
    }
75
    else {
76
      t2=TIM_GetCapture4(TIM3);
77
78
      if(t2>=t1) {
79
        messwert=t2-t1;
80
81
      }
82
      else {
83
        messwert=(0xFFFF - t1) + t2;
84
      }
85
      t1 = t2;
86
    }
87
  }
88
}
89
90
int main(void)
91
{
92
  init();
93
  SystemInit();
94
95
    while(1)
96
    {
97
      frequenz = 42000000/messwert;
98
    }
99
}

von Jim M. (turboj)


Lesenswert?

Ich würde da mal spontan DMA in den Raum werfen...

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


Lesenswert?

Das ist auch schon eine Menge (relativ) in der ISR. Stutz die mal 
zusammen und sauge nur den Capturewert, setze ein Flag und mach den Rest 
ausserhalb.

von Lurchi (Gast)


Lesenswert?

Die Frequenzmessung mit der Capture-funktion ist zu hohen Frequenzen 
begrenzt durch die Laufzeit der ISR. Ein wenig code könnte man da ggf. 
noch kürzen (beim Löschen der Flags), ganz viel aber nicht. Je nach Takt 
für den µC ist da halt irgendwo Schluss. Ich hätte etwas mehr erwartet 
bei 42 MHz Takt. Per DMA könnte es auch schneller gehen die Daten 
auszulesen. Wenn man will kann man da auch Werte Überspringen / 
ignorieren, wenn sie sehr schnell kommen.

Für eine bessere Auflösung kann man die Zeit für mehr als eine Periode 
messen. Dazu werden neben der Zeitmessung auch noch die Interrupts 
gezählt und eine passende Zahl von Perioden ausgewählt.

Für deutlich höhere Frequenzen sollte man das Signal vor dem µC Teilen, 
ggf. geht das auch mit der µC internen Hardware, etwa indem nicht jede 
Flanke an capture event auslöst, sondern nur etwa jede 8. oder so. Wenn 
man keine niedrigen Frequenzen braucht kann der Teiler (z.B. 128) auch 
immer drin bleiben.

von Mark W. (mark_wer)


Lesenswert?

Erstmal schon mal Danke, für eure Hilfe. Habe die ISR jetzt gekürzt, 
aber es gab leider keine merkbare Verbesserung. Ich würde gern jede 
Flanke erkennen, deshalb fällt diese Möglichkeit leider weg.. Das mit 
dem DMA hört sich nicht schlecht an, hab mich auch schon ein bisschen 
eingelesen, aber so richtig drauf gekommen, wie ich das mit DMA lösen 
kann, bin ich noch nicht.  Würde mich über Tipps freuen.

von Norbert (Gast)


Lesenswert?

Löst jetzt nicht das Problem, aber ich fand schon immer das ein volatile 
bei bestimmten Variablen gut kommt. Besonders wenn sie in einer ISR 
modifiziert werden.

Ein STM32F4 kann 168MHz, use the force Luke!

von Jonas B. (jibi)


Lesenswert?

>Ein STM32F4 kann 168MHz, use the force Luke!

Jo aber nicht auf den IO's soviel zur force junge...

Gruß J

von m.n. (Gast)


Lesenswert?

Es gibt hier Beiträge im Forum "Projekte & Code". Allerdings ist die 
Suchfunktion gestört, sodaß ich diese nicht finden kann.

Ein Beispiel mit QVGA-Display findest Du hier: 
http://mino-elektronik.de/fmeter/neue_versionen.htm#a13
Die direkte Messung geht bis 2,5 MHz und mit internem Vorteiler bis 20 
MHz.
Dann gibt es noch eine fertige Lösung für das STM32F429 Discovery Board: 
http://mino-elektronik.de/FM_407/fmeter_407.htm#c1
Hier wird ein interner Timer als Vorteiler für die automatische 
Bereichsumschaltung benutzt.

von Norbert (Gast)


Lesenswert?

Jonas B. schrieb:
>>Ein STM32F4 kann 168MHz, use the force Luke!
>
> Jo aber nicht auf den IO's soviel zur force junge...


Ja, aber wenn man sich über evtl. zu lange Sequenzen in der ISR 
unterhält, könnte der vierfache Takt zu einer Laufzeitverringerung 
beitragen.
Habe nur noch nicht berechnet um wieviel Prozent. ;-)

von m.n. (Gast)


Lesenswert?


von dasrotemopped (Gast)


Lesenswert?

>>Ein STM32F4 kann 168MHz, use the force Luke!
>Jo aber nicht auf den IO's soviel zur force junge...

Aber auf den externen Timer Eingängen. Ein paar 16bit-Timer kaskadieren, 
ein Zähler mit absoluter Genauigkeit ...

Gruß,

dasrotemopped.

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.