Forum: Mikrocontroller und Digitale Elektronik STM32F4 Timer interrupt


von Simon Richter (Gast)


Lesenswert?

Guten Abend zusammen,

ich habe hier ein STM32F411RE (Nucleo Board) und verzweifle grade an der 
Einstellung der Timer.

Es soll einfach 2 mal pro Sekunde der TIM2_IRQ Handler aufgerufen 
werden, der dann die LED toggelt.

Wahrscheinlich fehlt nur eine kleine Einstellung ...


Ich habe jetzt folgenden Code:

int
main (int argc, char* argv[])
{
  UNUSED(argc);
  UNUSED(argv);
  trace_printf("System clock: %u Hz\n", SystemCoreClock);

  // enable clock on GPIO A
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
  // set as output
  GPIOA->MODER |= GPIO_MODER_MODER5_0;
  // set to low speed (2MHz)
  GPIOA->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR5);
  //GPIOA->AFR[0] |= (GPIO_AF1_TIM2 << (5*4));
  GPIOA->BSRR |= GPIO_BSRR_BS_5;

  /**
   * initialize the timer
   */
  // enable clock to timer 2
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;

  // set prescaler value
  TIM2->PSC = 10000 -1; // clock = 100.000.000 Hz -> CK_PSK = 10.000 Hz

  // count to 5000
  TIM2->ARR = 5000 -1; // 10.000 Hz / 5000 = 2 Hz

  TIM2->DIER |= TIM_DIER_UIE; // enable update interrupt

  // enable counter
  TIM2->CR1 |= TIM_CR1_CEN;

  while (1);
}

void
TIM2_IRQHandler(void)
{
  // clear interrupt flag
  TIM2->SR &= ~(TIM_SR_UIF);

  // toggle Pin
  GPIOA->ODR ^= GPIO_ODR_ODR_5;
}


Kann mir jemand hierbei helfen?
Vielen Dank schonmal,

Simon

PS: Reference Manual habe ich gelesen, aber vermutlich irgendwas 
übersehen ...

von Christopher J. (christopher_j23)


Lesenswert?

Du musst dem Interrupt Controller noch sagen, dass er auch den Interrupt 
für Timer 2 benutzen soll. Einfach nur eine Funktion TIM2_IRQHandler 
definieren reicht leider nicht.
1
  // set priority for TIM2 interrupt
2
  NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 6, 0));
3
4
  // enable interrupt for timer 2
5
  NVIC_EnableIRQ(TIM2_IRQn);

Sämtliche NVIC_* Funktionen stammen aus dem core_cm4.h Header, der über 
den entsprechenden stm32f*.h automatisch mit eingebunden wird.

Wenn du das noch in deine main() packst sollte es funktionieren.

Wunder dich allerdings nicht, wenn die LED anfangs nur ganz kurz 
aufblitzt bevor sie anfängt zu blinken. Das Update Interrupt Flag wird 
schon mit starten des Timers gesetzt (TIM2->CR1 = TIM_CR1_CEN). Ist ja 
quasi auch ein Update. Jedenfalls feuert der Interrupt sofort los und 
nicht erst nachdem ARR=4999 ist.

Ob das mit der von dir angepeilten Interruptfrequenz hinhaut hängt 
allerdings davon ab ob du irgendwo noch die Konfiguration für die PLL 
versteckt hast. Ansonsten läuft der F411RE mit 16Mhz HSI und aus den 2Hz 
werden ca 0,3Hz.

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


Lesenswert?

Bist du sicher, das der ClockTree des STM32 schon konfiguriert ist? Ohne 
alles sollte der STM32, wimre, mit dem internen RC Oszillator laufen 
(8MHz)?

: Bearbeitet durch User
von Little B. (lil-b)


Lesenswert?

Ich würde den NVIC vorher noch initialisieren, sonst funktioniert er 
manchmal nicht richtig
1
  // initialize interrupt controller
2
  NVIC_SetPriorityGrouping(3);

Desweiteren solltest du deinen Prescaler nochmal nachrechnen. Ich glaube 
nicht, dass dein APB1 mit 100MHz takt. Laut ClockConfigurationTool darf 
er nur mit maximal 42MHz takten.

Die TIMs laufen nicht mit HCLK, sondern mit PCLK1 oder PCLK2.

von Uwe B. (Firma: TU Darmstadt) (uwebonnes)


Lesenswert?

Wo schaltest Du RCC_APB1ENR_TIM2EN an?
Und beim F411 is APB1 max 50 MHz.

von Simon Richter (Gast)


Lesenswert?

Danke ihr beiden für die Antworten.

Ich nutze ein Template des "GNU ARM Eclipse Plugin", das kümmert sich um 
die PLL (Das Template musste ich allerdings ein bisschen anpassen, damit 
der Chip auch mit 100MHz taktet, und nicht "nur" mit 84MHz (wie z.B. 
STM32F401), da es für den F411RE kein fertiges Template gibt). Das 
heißt, der Chip ist schon initialisiert und taktet zum Start von main() 
schon mit 100MHz.

Das mit dem NVIC hatte ich überhaupt nicht auf dem Schirm. Das werde ich 
heute Abend direkt einbauen und berichten.

Nun habe ich aber (nach weiterlesen der Doku) noch ein paar Fragen:

1. Es sollte doch auch möglich sein, die LED direkt (ohne zutun der CPU) 
vom Timer zu schalten, oder? (Ich denke hier an einen der PWM Modi + 
Alternate Funktion des Output Ports)

2. Wo ist der Unterschied zwischen PWM Modus 1 und 2?

Viele Grüße und danke schonmal,
Simon

von Simon Richter (Gast)


Lesenswert?

Oh, da war ich zu langsam..

@Uwe:
Das wird nach der GPIO Konfiguration und vor der Timer Konfiguration 
gemacht. ( "RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;" sollte doch richtig 
sein, oder? )

@lil-b:
Das mit dem NVIC werde ich dann auch mal noch einbauen.
ABP1 taktet laut hier 
(http://www.st.com/content/ccc/resource/technical/document/datasheet/b3/a5/46/3b/b4/e5/4c/85/DM00115249.pdf/files/DM00115249.pdf/jcr:content/translations/en.DM00115249.pdf 
- Seite 15) mit 50MHz. 42MHz sollten es beim F401 sein.

@all:
Danke für den Hinweiß mit dem Takt von ABP1!

Demnach müsste mit dem Code oben die LED immer eine Sekunde an und eine 
Sekunde aus sein, nicht jeweils eine halbe Sekunde?

Kann ich aus versehen APB1 auf 100MHz getaktet haben und den Chip 
beschädigen? Die PLL kann ich heute Abend hier auch noch posten, wenn 
das relevant sein sollte?

von Simon Richter (Gast)


Lesenswert?

So, und noch einmal ich:

Ich habe im Bild nun einmal meine aktuelle Konfiguration eingestellt.
Im Bild sieht man aber auch, dass sich dort der APB1 Timer Clock von dem 
APB1 Periperial Clock unterscheidet.
Heißt das nun, dass die Timer, die APB1 nutzen (TIM2,3,4,5) mit 100MHz 
getaktet sind, die restliche Peripherie wie USART, IC2, ... am APB1 aber 
nur mit 50MHz?
Dann würde es ja stimmen, so wie es ist, oder?

Und dann noch eine Frage: macht es einen Unterschied (Takt "unsauberer" 
oder so etwas), wie ich die PLL konfiguriere um von den 8MHz HSE auf 
100MHz SYSCLK zu kommen, oder ist das egal?

Also als Beispiel:
PLL_M = 8
PLL_N = 400
PLL_P = 4

oder

PLL_M = 4
PLL_N = 100
PLL_P = 2


Grüße und nochmal allen, die sich meinen vielen Fragen stellen, vielen 
Dank :-)

Simon

von Nico W. (nico_w)


Lesenswert?

PLLM sollte auf 2MHz laufen.

> The software has to set these bits correctly to ensure that the VCO input
> frequency ranges from 1 to 2 MHz. It is recommended to select a frequency
> of 2 MHz to limit PLL jitter.

Ich habe für 100MHz:
1
PLLM 4    -> 2MHz (8MHz/4)
2
PLLN 200  -> 400MHz (2MHz * 200)
3
PLLP 4    -> 100MHz (400MHz/ 4) APB2
4
PLLQ 8    -> 50MHz (400MHz / 8) APB1

APB1 sollte für USB auf 48MHz laufen.

Edit hat es dann doch gefunden.

RM0383 Seite 91/836:
> The maximum allowed frequency of the low-speed APB1 domain is 50 MHz

: Bearbeitet durch User
von Nico W. (nico_w)


Lesenswert?

Jetzt muss ich auch mal Fragen. Ich habe jetzt im Reference Manual nix 
gefunden, vielleicht versteckt es sich hinter einem der Bilder?!?

Aber kann es sein, dass der TIM2 bis TIM5 mit Systemtakt läuft und nicht 
mit APB1 (50MHz)? Also mit 100MHz, wenn denn so zurecht gebastelt?!?

von Simon Richter (Gast)


Lesenswert?

Ich glaube, die Antwort habe ich eine halbe Seite unter der von dir 
zitierten Stelle im Reference Manual (RM0383, S.91) gefunden:

>The timer clock frequencies for STM32F411xC/E are automatically set by hardware.
>There are two cases:
> 1. If the APB prescaler is 1, the timer clock frequencies are set to the  same
>    frequency as that of the APB domain to which the timers are connected.
> 2. Otherwise, they are set to twice (×2) the frequency of the APB domain
>    to which the timers are connected.

Demnach wäre es so, dass wenn der APB1 Prescaler auf /2 steht (was er ja 
müsste, bei 100MHz HCLK und 50MHz APB1 Peripherial Clock), die Timer, 
die an APB1 verbunden sind, mit 100MHz takten.


Wenn mir das nochmal jemand so bestätigen kann, wäre ich aber trotzdem 
dankbar.

von Christopher J. (christopher_j23)


Lesenswert?

Simon Richter schrieb:
> um von den 8MHz HSE auf
> 100MHz SYSCLK

Hast du denn einen externen Quarz auf dein Nucleo gelötet? Die HSI läuft 
über einen internen 16Mhz Oszillator (Ch. 6.2.2 RefMan).

Simon Richter schrieb:
> Ich habe im Bild nun einmal meine aktuelle Konfiguration eingestellt.
> Im Bild sieht man aber auch, dass sich dort der APB1 Timer Clock von dem
> APB1 Periperial Clock unterscheidet.
> Heißt das nun, dass die Timer, die APB1 nutzen (TIM2,3,4,5) mit 100MHz
> getaktet sind, die restliche Peripherie wie USART, IC2, ... am APB1 aber
> nur mit 50MHz?

Ich sehe zwar das Bild nicht, aber wenn der APB1 Prescaler auf 
mindestens zwei gesetzt ist (was ja sein muss bei max.50Mhz), dann 
laufen die Timer an APB1 mit der doppelten Frequenz von APB1. Es sollte 
also so sein wie du beschrieben hast.

Simon Richter schrieb:
> 1. Es sollte doch auch möglich sein, die LED direkt (ohne zutun der CPU)
> vom Timer zu schalten, oder? (Ich denke hier an einen der PWM Modi +
> Alternate Funktion des Output Ports)

Ja, das geht auch direkt und auch ohne Interrupts:

GPIO Setup:
1
// clock einschalten
2
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
3
4
// als alternate function konfigurieren
5
GPIOA->MODER |= GPIO_MODER_MODER5_1;
6
7
// passende AF Konfiguration in AFR schreiben  
8
GPIOA->AFR[0] |= (GPIO_AF1_TIM2 << (5*4));

Timer Setup:
1
// Wie schon zuvor
2
// enable clock to timer 2
3
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
4
5
// set prescaler value
6
TIM2->PSC = 10000 -1; // clock = 100.000.000 Hz -> CK_PSK = 10.000 Hz
7
8
// count to 5000
9
TIM2->ARR = 5000 -1; // 10.000 Hz / 5000 = 2 Hz
10
11
12
// Ab hier dann capture compare setup
13
14
// set capture compare mode to "pwm mode 1", i.e. output active if CNT<CCR
15
TIM2->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; 
16
17
// enable the capture compare output
18
TIM2->CCER = TIM_CCER_CC1E;
19
20
// enable counter
21
TIM2->CR1 |= TIM_CR1_CEN;

Also PWM mode 1 bedeutet "output active" wenn TIMx->CNT < TIMx->CCR und 
bei PWM mode 2 ist es genau anders herum. D.h. du drehst die Polarität 
für den gesamten Timer um.

Die Polaritäten kannst du aber auch für die einzelnen 
Capture/Compare-Kanäle einstellen, hiermit verdrehst du z.B. für CC1 die 
Polarität:
1
TIM2->CCER |= TIM_CCER_CC1P;

von Nico W. (nico_w)


Lesenswert?

Christopher J. schrieb:
> Hast du denn einen externen Quarz auf dein Nucleo gelötet? Die HSI läuft
> über einen internen 16Mhz Oszillator (Ch. 6.2.2 RefMan).

Jupp, der NucleoF411RE hat nen Externen 8MHz.

Christopher J. schrieb:
> GPIOA->MODER |= GPIO_MODER_MODER5_1;

Je nach Pin sollte man den vorher Resetten. Nicht jeder Pin ist am 
Anfang auf 0. Darauf bin ich zwischendurch auch einmal reingefallen.

> Reset values:
> • 0x0C00 0000 for port A
> • 0x0000 0280 for port B
> • 0x0000 0000 for other ports

: Bearbeitet durch User
von Christopher J. (christopher_j23)


Lesenswert?

Nico W. schrieb:
> Christopher J. schrieb:
>> GPIOA->MODER |= GPIO_MODER_MODER5_1;
>
> Je nach Pin sollte man den vorher Resetten. Nicht jeder Pin ist am
> Anfang auf 0. Darauf bin ich zwischendurch auch einmal reingefallen.

Ja das stimmt, da muss man aufpassen. Für den PA5 sollte es aber so 
passen.

Nico W. schrieb:
> Christopher J. schrieb:
>> Hast du denn einen externen Quarz auf dein Nucleo gelötet? Die HSI läuft
>> über einen internen 16Mhz Oszillator (Ch. 6.2.2 RefMan).
>
> Jupp, der NucleoF411RE hat nen Externen 8MHz.

Die Frage war eigentlich an Simon gerichtet :D Musste grade selber mal 
nachschauen ob neuere Revisionen den X3 standardmäßig bestückt haben, 
weil bei meinem ist es (leider) nicht so.

Aber um auf deine Frage zurück zu kommen:

Nico W. schrieb:
> Aber kann es sein, dass der TIM2 bis TIM5 mit Systemtakt läuft und nicht
> mit APB1 (50MHz)? Also mit 100MHz, wenn denn so zurecht gebastelt?!?

Ja, die Timer an APB1 (TIM2 bis TIM5) laufen standardmäßig mit doppeltem 
APB1 Takt, wenn der Prescaler für APB1 >= 2 ist. Wenn der Prescaler 
gleich zwei ist entspricht das dem Systemtakt. Es gibt noch die 
Möglichkeit die Timer mit vierfachem Takt laufen zu lassen, wenn der 
Prescaler von APB1 >= 4 ist. Das ist auf Seite S.132 alles relativ kurz 
und knapp beschrieben.

Das gleiche gilt auch für APB2, wobei man den ja auch direkt mit 
Systemtakt, also 100 Mhz laufen lassen kann, also den Prescaler auf 1 
belassen kann.

Übrigens ist Q soweit ich weiß für USB und SDIO zuständig und darf dafür 
maximal 48 Mhz sein bzw. muss exakt 48 Mhz sein.
Nico W. schrieb:
> PLLQ 8    -> 50MHz (400MHz / 8) APB1

Wenn man PLLN auf 192 reduziert passt aber alles, wobei der Prozzi dann 
eben "nur" mit 96 Mhz rennt und APB1 eben auch 48 Mhz hat.

von Nico W. (nico_w)


Lesenswert?

Christopher J. schrieb:
> Das ist auf Seite S.132 alles relativ kurz
> und knapp beschrieben.

Danke, guck ich mir nochmal genauer an.

Christopher J. schrieb:
> Nico W. schrieb:
>> PLLQ 8    -> 50MHz (400MHz / 8) APB1
>
> Wenn man PLLN auf 192 reduziert passt aber alles, wobei der Prozzi dann
> eben "nur" mit 96 Mhz rennt und APB1 eben auch 48 Mhz hat.

Wenn man etwas mutig ist, kann man den STM auch auf 108MHz laufen 
lassen. Läuft bei meinem sehr stabil.
1
PLLM 2 -> 2MHz
2
PLLN 216 -> 432MHz
3
PLLP 4 -> 108MHz
4
PLLQ 9 -> 48MHz

Wobei dann TIM2 wohl immer noch auf 'nur' 96MHz läuft, der Prozessor 
aber auf 108MHz.

von Christopher J. (christopher_j23)


Angehängte Dateien:

Lesenswert?

Nico W. schrieb:
> PLLM 2 -> 2MHz
> PLLN 216 -> 432MHz
> PLLP 4 -> 108MHz
> PLLQ 9 -> 48MHz

> Wobei dann TIM2 wohl immer noch auf 'nur' 96MHz läuft, der Prozessor
> aber auf 108MHz.

Ich glaube du verwechselst da was. Die beiden APBs werden aus dem Takt 
des AHB versorgt und dieser wiederum aus der SYSCLK, was in deinem Fall 
die PLLCLK ist.

Das einzige was über den Teiler PLLQ versorgt wird sind USB und SDIO.

Bei deiner Konfiguration sollte also TIM2 mit 108Mhz laufen und der APB1 
mit 54Mhz. Das kann funktionieren, ist aber definitiv außerhalb der 
Specs.

Hab dir mal einen Screenshot aus der Konfiguration in CubeMX angehängt 
(finde ich für PLL Konfiguration sehr übersichtlich, auch wenn ich den 
sonstigen HAL-Kram nicht mag). Das gleiche bekommst du aber auch wenn du 
einen Blick auf "clock tree" auf S.90 wirfst.

von Nico W. (nico_w)


Lesenswert?

In der Tat verrafft. Nicht selbst zusammenreimen sondern lesen würde 
dagegen helfen.
Merci!

von Christopher J. (christopher_j23)


Lesenswert?

Null Problemo ;)
Sag mal Nico, nutzt du eigentlich den 8 Mhz Quarz vom ST-Link oder hast 
du X3 separat bestückt?

von Nico W. (nico_w)


Lesenswert?

Ich habe ein 08/15 Nucleo F411RE.

X3 habe ich noch nicht im Einsatz. Muss mal mein Board eh genauer 
ansehen, was da drauf ist. Auf manchen soll ja sogar ein 32k drauf sein.

: Bearbeitet durch User
von Simon R. (nixname1)


Lesenswert?

So, guten Morgen.

Gestern kamen mir leider ein paar Dinge dazwischen, deswegen melde ich 
mich jetzt erst wieder.

Das mit dem NVIC hat das anfängliche Problem gelöst. Auch das mit den 
verschiedenen PWM Modi ist nun klar - danke dafür.

Die Konfiguration der PLL habe ich jetzt noch nicht geändert, werde ich 
aber noch tun, um dem hier:
> The software has to set these bits correctly to ensure that the VCO input
> frequency ranges from 1 to 2 MHz. It is recommended to select a frequency
> of 2 MHz to limit PLL jitter.
gerecht zu werden.

@Christopher:
In deinem Beispiel zum PWM fehlt noch das beschreiben von TIM2->CCR1 um 
den duty cycle zu bestimmen :-)


@all
Vielen Dank für die ausführlichen Erklärungen, auch wenn ihr mich 
anfangs etwas geschockt habt mit dem Takt von den Timern :-P

von Christopher J. (christopher_j23)


Lesenswert?

Simon R. schrieb:
> @Christopher:
> In deinem Beispiel zum PWM fehlt noch das beschreiben von TIM2->CCR1 um
> den duty cycle zu bestimmen :-)

Oh stimmt, ist wohl irgendwo zwischen Strg-C und Strg-V verloren 
gegangen ;)
Ohne Wert im CCRx tut sich natürlich genau gar nichts.

Nico W. schrieb:
> X3 habe ich noch nicht im Einsatz. Muss mal mein Board eh genauer
> ansehen, was da drauf ist. Auf manchen soll ja sogar ein 32k drauf sein.

Ich hab auch echt bis gestern geglaubt man müsste den X3 separat 
bestücken um das Ding mit HSE betreiben zu können. Es gab hier auch 
irgendwo mal einen Artikel dazu wie man das genau anstellt und den habe 
ich dann leider nicht mehr gefunden. Naja, im User Manual zu den 
Nucleo64 steht es jedenfalls drin und da war dann auch der Hinweis auf 
den Quarz vom ST-Link. Oh man...

Bei mir ist jedenfalls auch so ein 32k Quarz verlötet. Laut dem Manual 
ist das bei Boards ab Revision C-02 der Fall.

von Nico W. (nico_w)


Lesenswert?

Christopher J. schrieb:
> Bei mir ist jedenfalls auch so ein 32k Quarz verlötet. Laut dem Manual
> ist das bei Boards ab Revision C-02 der Fall.

Jetzt ist nur die Frage ab wann C-02 kam. Ich habe mein Board jetzt ca. 
ein Jahr.

Christopher J. schrieb:
> Ich hab auch echt bis gestern geglaubt man müsste den X3 separat
> bestücken um das Ding mit HSE betreiben zu können.

Ich hatte bisher keine Ahnung, dass da X3 für nen Quarz vorgesehen ist 
:)

Ich bin aber auch ganz naiv in den STM reingestolpert und hatte mich 
damals durch das GCC4MBED durchgequält und den kompletten Ballast von 
Bord geschmissen, bis mein µC lief.

von Christopher J. (christopher_j23)


Lesenswert?

Ich habe das Nucleo auch in etwa seit einem Jahr. Die Revision steht 
aber auch auf einem kleinen weißen Aufkleber drauf. Den X2 kann man aber 
auch leicht erkennen. Ist ein schwarzes SMD-Teil links unten im Eck 
(wenn der ST-Link oben ist).

von Nico W. (nico_w)


Lesenswert?

Gestern mal geguckt. Ich hab nen C-03. Also mit Quarz. Jetzt muss ich 
mir nur noch überlegen wie warum und wieso er gut in ein Projekt von mir 
passen könnte. :)

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.