STM32 Frequenz Messung (>10MHz)

OP #4716840
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
}
Angehängte Dateien:
Gast #4717010
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.
OP #4717510
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.
Gast #4717533
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.
Gast #4717535
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. ;-)
Gast #4717891
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren