Forum: Mikrocontroller und Digitale Elektronik STM32F4-Discovery: Timereinstellung passt nicht zur Frequenz


von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Hallöchen,

nachdem ich mich seit zwei Wochen gemütlich in die STM32-Reihe 
einarbeite und dachte, ich hätte die Timer-Einstellung verstanden, gibt 
es nun ein Problem:

Ziel: PA6 per Timer-Update-Interrupt von TIM3 zu toggeln

Das Problem: er toggelt zwar wunderbar, allerdings entspricht die 
Frequenz (7,92Hz) nicht der von mir erwarteten Frequenz von 50Hz.

Übersetzt wurde mit -DHSE_VALUE=8000000, den Rest der 
PLL-Initialisierung überlasse ich ohne weitere Veränderungen 
SystemInit(). Der Systemtakt sollte also 168MHz betragen. Externer Quarz 
läuft auch mit 8MHz (gemesen).

Was mich besonders wundert ist der "krumme" Wert - man vergisst ja gerne 
mal einen Vorteiler oder so etwas - aber hier bin ich ratlos.

Dasselbe Ergebnis gibt es übrigens mit einem zweiten Discovery-Kit.

Hier der relevante Code (wie gesagt: er macht, was er soll - nur eben 
nicht mit gewünschter Frequenz):

1
void TIM3_Config (void)
2
{
3
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
4
5
  // Takt freigeben
6
  RCC_APB1PeriphClockCmd (RCC_APB1Periph_TIM3, ENABLE);
7
8
  // Time Base configuration
9
  TIM_TimeBaseStructInit (&TIM_TimeBaseStructure);
10
  TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 10000) - 1; // Taktung: 10000Hz
11
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
12
  TIM_TimeBaseStructure.TIM_Period = 100;
13
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
14
  TIM_TimeBaseInit (TIM3, &TIM_TimeBaseStructure);
15
16
  // Timer Interruptkonfiguration = Interrupt bei Überlauf
17
  TIM_ITConfig (TIM3, TIM_IT_Update, ENABLE);
18
19
  TIM_Cmd (TIM3, ENABLE);
20
}
21
22
23
// ISR für Timer 3 Interrupt
24
void TIM3_IRQHandler (void)
25
{
26
  // Überlauf des Zählregisters
27
  if (TIM_GetITStatus (TIM3, TIM_IT_Update) != RESET)
28
  {
29
    // Interruptgrund löschen
30
    TIM_ClearITPendingBit (TIM3, TIM_IT_Update);
31
    // Und Bit wechseln
32
    GPIO_ToggleBits (GPIOA, GPIO_Pin_6);
33
  }
34
}

Wo liegt mein Denkfehler?

Chris D.

von Thomas W. (ratos)


Lesenswert?

Hallo,

ich musste in system_stm32f4xx.c PLL_M von 25 auf 8 stellen (weil der 
Quarz auf dem Discovery 8 MHz hat).
Dann stellst du noch Period auf 99 (glaube ich).
Danach sollte PA6 mit 50 Hz getoggelt werden (25 mal pro Sekunde high 
und low).
Ich hoffe, das hilft dir weiter.

Thomas

von AVerr (Gast)


Lesenswert?

Wie sieht denn der APB1 Prescaler aus (steht wahrscheinlich in den 
Comments der system_stm32f4xx.c) ? Der Timer wird ja von APB1 mit seinem 
Takt versorgt.
Bei mir war er standardmäßig auf 4 gesetzt, sodass du mit diesen 
Einstellungen auf 12.5 Hz kommen müsstest.
Das wäre schonmal etwas näher am gemessenen Wert.

von Uwe (Gast)


Lesenswert?

> den Rest der PLL-Initialisierung überlasse ich ohne weitere Veränderungen
> SystemInit()

Dann guck da doch mal rein und setz nen Haltepunkt rein beim debuggen.
Dann überprüfst du einfach mal was in die ganzen PLL Register 
reingeschrieben wird bzw. was drin steht und schaust mal inst Datenblatt 
und rechnest aus mit wieviel er nun läuft.

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Thomas W. schrieb:
> Hallo,
>
> ich musste in system_stm32f4xx.c PLL_M von 25 auf 8 stellen (weil der
> Quarz auf dem Discovery 8 MHz hat).

In der stm32f4xx.h findet sich das hier. Daher dachte ich, mit HSE_VALUE 
wäre alles erschlagen.
1
/**
2
 * @brief In the following line adjust the value of External High Speed oscillator (HSE)
3
   used in your application 
4
   
5
   Tip: To avoid modifying this file each time you need to use different HSE, you
6
        can define the HSE value in your toolchain compiler preprocessor.
7
  */           
8
9
#if !defined  (HSE_VALUE) 
10
  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
11
#endif /* HSE_VALUE */

AVerr schrieb:
> Wie sieht denn der APB1 Prescaler aus (steht wahrscheinlich in den
> Comments der system_stm32f4xx.c) ? Der Timer wird ja von APB1 mit seinem
> Takt versorgt.
> Bei mir war er standardmäßig auf 4 gesetzt, sodass du mit diesen
> Einstellungen auf 12.5 Hz kommen müsstest.
> Das wäre schonmal etwas näher am gemessenen Wert.

Ja, hier steht auch eine 4.

Also ist der APB1 (42MHz) wirklich der Takt, mit dem der Timer zählt. In 
der Referenz steht in den Schaubildern nämlich immer nur etwas von 
"CK_INT", wobei nirgends erklärt wird, woher der genau kommt (oder ich 
habs übersehen - die Referenz ist ja nicht gerade klein ;-).
Ich hatte schon vermutet, dass APB1 nur für den Bus zuständig ist und 
der Zähler direkt die Systemclock erhält.

Ok, dann müsste ich bei 12,5Hz landen. Bleibt nur noch eine "winzige 
Differenz" ;-)

Chris D.

von Uwe (Gast)


Lesenswert?

Steht im Datenblatt im Block Diagramm auf Seite 18 (mußt halt gucken an 
welchem Bus die komponente hängt und am Bus steht noch die Maximale 
Taktfrequenz die du einhalten mußt).
oder auf Seite 85 in der Referenz
Setz doch mal nen Haltepunkt in die Funktion und guck was wirklich drin 
steht bzw. ob die Funktion überhaupt aufgerufen wird.

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Das Problem ist zumindest teilweise gelöst.

Also:

Taktquelle für den Zähler ist die Frequenz von APB1 (42MHz).

Diese schicke ich durch den Vorteiler, um auf die 10kHz Zählfrequenz zu 
gelangen.

Zusätzlich muss - wie Thomas oben anmerkte - tatsächlich PLL_M von 25 
auf 8 geändert werden. Also Pustekuchen mit "nur HSE_VALUE" ändern ...

Meine 7,92Hz ergaben sich aus dem fehlenden Faktor 4 (168->42MHz) mal 
dem Faktor 25/8 und meiner etwas zu hoch gesetzten Timer period - er 
zählt ja von 0 an, also ist 99 korrekt, nicht 100.

Immerhin gibt er jetzt exakt 100Hz raus.

Jetzt muss ich nur noch irgendwo einen Faktor 1/2 finden, um auf meine 
erwarteten 50Hz zu kommen ;-)

Es hilft nichts, ich muss mir wohl doch erstmal die genauen Abläufe zur 
Takterzeugung reinziehen.

Ich dachte eigentlich, die Standard-Lib wäre dazu da, Einsteigern genau 
das abzunehmen ... falsch gedacht ;-)

Chris D.

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Uwe schrieb:
> Steht im Datenblatt im Block Diagramm auf Seite 18 (mußt halt gucken an
> welchem Bus die komponente hängt und am Bus steht noch die Maximale
> Taktfrequenz die du einhalten mußt).
> oder auf Seite 85 in der Referenz

Ja, genau, so ein Schema hab ich gesucht - danke :-)
Am Anfang sieht man den Wald vor lauter Bäumen nicht.

> Setz doch mal nen Haltepunkt in die Funktion und guck was wirklich drin
> steht bzw. ob die Funktion überhaupt aufgerufen wird.

Ja, aufgerufen wird sie (habe da gerade PLL_M geändert).

Der Debugger läuft hier leider noch nicht (ich hab hier CodeSourcery), 
das kommt als nächstes :-/

Chris D.

von Gnubbel (Gast)


Lesenswert?

TIM_TimeBaseStructure.TIM_ClockDivision = 1;

Was wenn du das mal machst?

von Thomas W. (ratos)


Lesenswert?

Chris D. schrieb:
> Also ist der APB1 (42MHz) wirklich der Takt, mit dem der Timer zählt.

Nein, das ist laut Datenblatt der maximale Interfacetakt. Der maximale 
Timertakt entspricht dem Doppelten (84 MHz).
Nur die Timer 1,8,9,10 und 11 zählen mit 168 MHz.

von Uwe (Gast)


Lesenswert?

Im kästchen auf Seite 85 in der Referenz ist noch einmal eine extra 
Verzweigung drin für APBx Komponenten und APBx Timer bei den Timern 
steht drin
if APB Prescaler=1 dann Clock x 1
ansonsten Clock x 2
Das heist wenn du 4 als Prescaler hast wird der Takt nur für die Timer 
noch mal verdoppelt ! Also 84MHz statt 42.

von Uwe (Gast)


Lesenswert?

Also kein Fehler der Timer ist halt nur Doppelt so schnell durch eine 
Taktverdopplung sozusagen.

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Uwe schrieb:
> Im kästchen auf Seite 85 in der Referenz ist noch einmal eine extra
> Verzweigung drin für APBx Komponenten und APBx Timer bei den Timern
> steht drin
> if APB Prescaler=1 dann Clock x 1
> ansonsten Clock x 2
> Das heist wenn du 4 als Prescaler hast wird der Takt nur für die Timer
> noch mal verdoppelt ! Also 84MHz statt 42.

Ja, vielen Dank.

Ich hab's gerade auch im Schaubild festgestellt - das erklärt dann auch 
die 100Hz anstatt der 50Hz :-)

Problem ist also gelöst - vielen Dank an alle!

Ach, eins fällt mir noch ein (bevor ich mich durch die Takterzeugung 
wühle):
Es gibt nicht zufällig irgendwo diese Takte als fertig berechnete 
Defines/Variablen in der Standard-Lib?

Chris D.

von Uwe (Gast)


Lesenswert?

CooCox CoIDE da ist nen Debugger bei und funzt mit CodeSourcery.

von ReinerL (Gast)


Lesenswert?

Chris D. schrieb:
> Es gibt nicht zufällig irgendwo diese Takte als fertig berechnete
> Defines/Variablen in der Standard-Lib?

Bei ST.com gibt es ein Excelfile zur ClocK-Konfiguration, das erzeugt 
auch die system_stm32f4xx.c.
Ist schick gemacht und visualisiert auch schön die Clocks.

ReinerL

von Matthias K. (matthiask)


Lesenswert?

Chris D. schrieb:
> Zusätzlich muss - wie Thomas oben anmerkte - tatsächlich PLL_M von 25
> auf 8 geändert werden. Also Pustekuchen mit "nur HSE_VALUE" ändern ...

HSE_VALUE definiert nur die vorhandene Quarzfrequenz. Aber woher soll 
die system_init wissen, wie schnell Dein µC wirklich rennen soll. Die 
168MHz sind nur das Maximum, ist aber nicht immer notwendig. Also nimmt 
man dafür die PLL_ Werte zur Einstellung.

Das Excelfile vomn STM ist gut, wenn man es einmal verstanden hat.

von Chris D. (myfairtux) (Moderator) Benutzerseite


Lesenswert?

Danke für den Hinweis auf die Excel-Datei - das erleichtert es doch 
sehr.

Aber jetzt blicke ich schon ganz gut durch die Takterzeugung durch :-)

Wenn heute ich mal Leerlauf habe, werde ich mal den Debugger einrichten 
(unter Ubuntu). Da gibt es dann sicher auch wieder Fragen ;-)

Chris D.

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.