Forum: Mikrocontroller und Digitale Elektronik STM32F4 TIM2


von Gabriel J. (nyquist)


Lesenswert?

Hallo,

stehe wieder vor einem Problem, bei dem ich nicht weiter weiß. Und zwar 
will ich mit dem Timer 2 nur raufzählen und beim Überlauf, soll eine LED 
toggeln. Irgendwie will das ganze nicht so recht bzw. das Programm geht 
nicht in die ISR.

Hier mal der Code
1
#include "ch.h"
2
#include "hal.h"
3
#include "test.h"
4
5
#define ARM_MATH_CM4
6
#include "arm_math.h"
7
8
#include "timconf.h"
9
10
static uint32_t tim_cnt = 0;
11
12
void TIM2_IRQHandler(void){
13
  if ((TIM2->SR & TIM_SR_UIF) != 0){
14
    palTogglePad(GPIOD, GPIOD_LED5);
15
    tim_cnt++;
16
    // Clear update interrupt flag
17
    TIM2->SR &= ~(TIM_SR_UIF);
18
  }
19
}
20
21
int main(void) {
22
  thread_t *shelltp = NULL;
23
24
  /*
25
   * System initializations.
26
   * - HAL initialization, this also initializes the configured device drivers
27
   *   and performs the board-specific initializations.
28
   * - Kernel initialization, the main() function becomes a thread and the
29
   *   RTOS is active.
30
   */
31
  halInit();
32
  chSysInit();
33
34
  tim_init();
35
36
  /*
37
   * Normal main() thread activity, in this demo it just performs
38
   * a shell respawn upon its termination.
39
   */
40
  while (true) {}
41
  }
42
}

In tim_conf.c ist folgender Code enthalten:
1
#include "ch.h"
2
#include "hal.h"
3
4
void tim_init(void)
5
{
6
  TIM2->CR1 &= ~(TIM_CR1_CEN);
7
  // TIM2 clock enable
8
  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
9
10
  // Auto-reload value
11
  TIM2->ARR = 42000;
12
  // Clear update interrupt flag
13
  TIM2->SR &= ~(TIM_SR_UIF);
14
  // Update interrupt enable
15
  TIM2->DIER |= TIM_DIER_UIE;
16
17
  // Enable TIM2 for IRQ
18
  NVIC_EnableIRQ(TIM2_IRQn);
19
20
  // Enable timer counter
21
  TIM2->CR1 |= TIM_CR1_CEN;
22
23
  //END OF IRQ STUFF
24
}

In timconf.h

1
#ifndef TIM_H
2
#define TIM_H
3
4
void tim_init(void);
5
6
#endif /* TIM_H */

Sieht da einer von Euch den Fehler? Der Timer läuft über und fängt 
wieder von 0 an, nur wird die ISR nicht aufgerufen. Bin über jede Hilfe 
dankbar.

Lg Gabriel

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


Lesenswert?

Und wieder einmal: Wo wird die Clock für GPIOD angeschaltet?

von Ingo (Gast)


Lesenswert?

PalTogglePad? Muss das evtl. HalTogglePad heissen? Keine den HAL nicht

von holger (Gast)


Lesenswert?

halInit();
  chSysInit();

  tim_init();

Pack   tim_init(); doch mal vor chSysInit();.

von Gabriel J. (nyquist)


Lesenswert?

Danke für die schnellen Rückmeldungen! Habe erst jetzt Zeit gefunden, 
die Vorschläge auszuprobieren.

Matthias S. schrieb:
> Und wieder einmal: Wo wird die Clock für GPIOD angeschaltet?

Hab den Code nun um folgende Zeile erweitert.
1
RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;

Kannst du mir bitte sagen, warum es nötig ist, den Clock etxra 
einzuschalten, wenn ich lediglich die on-board LED toggeln lasse? Was 
mich auch noch etwas irritiert ist, dass immer alle GPIO's (von A bis I) 
enabled sind, auch wenn ich es im Code nicht explizit angebe.

Ingo;
> PalTogglePad? Muss das evtl. HalTogglePad heissen?

Nein palTogglePad funktioniert einwandfrei (zumindest in einem anderern 
Programmcode).

holger:
> Pack   tim_init(); doch mal vor chSysInit();

Hat ebenso zu keiner Verbesserung geführt. Was mir durch diese Änderung 
aufgefallen ist, ist, dass das Upadate Interrupt Enable (UIE) bit im 
DIER Register nicht gesetzt ist, obwohl ich es im Code enable.

@all

Beim Überlauf wird das Update Interrupt Flag (UIF) bit im SR Register 
als auch das CC2, CC3 und CC4 Interrupt Flag bit gesetzt. Kann mir da 
jemand sagen, warum die gesetzt werden und warum das CC1IF bit nicht 
gesetzt wird?

Danke schonmal im Voraus! Lg

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


Lesenswert?

Gabriel J. schrieb:
> Kannst du mir bitte sagen, warum es nötig ist, den Clock etxra
> einzuschalten, wenn ich lediglich die on-board LED toggeln lasse?

Weil sonst die I/O Logik des Ports nicht angeschubst wird. Es handelt 
sich (vereinfacht gesagt) um getaktete Flipflops, die ohne Taktsignal 
nix machen. Das steht aber auch in der Referenz.

Kannst du mir umgekehrt mal sagen, warum du mit HAL arbeitest, aber dann 
alle Register zu Fuss beschreibst? Das ist am Sinn und Zweck von HAL 
vorbei. Wenn du HAL benutzt, ist es nur konsequent, auch die Funktionen 
zu benutzen, um mit der Peripherie zu sprechen.

Weiterhin solltest du mal schauen, ob der NVIC sinnvoll initialisiert 
ist. Das betrifft vor allem die Prioritätsgruppen und -level.

von Little B. (lil-b)


Lesenswert?

Ich sehe das ähnlich. Wenn du BareMetal arbeiten willst, solltest du 
auch konsequent keine HAL verwenden. (Oder umgekehrt, nur HAL verwenden)

Mit NVIC_EnableIRQ(TIM2_IRQn) schaltest du nur den Interrupt scharf, 
denke ich. Es fehlt noch die initialisierung der Priority Grouping und 
die Priorität deines Interrupts.

von Gabriel J. (nyquist)


Lesenswert?

Danke für die Rückmeldung. Ok, das mit dem Clock für die GPIO's ist mir 
jetzt klar. Danke

Matthias S. schrieb:
> Kannst du mir umgekehrt mal sagen, warum du mit HAL arbeitest, aber dann
> alle Register zu Fuss beschreibst? Das ist am Sinn und Zweck von HAL
> vorbei. Wenn du HAL benutzt, ist es nur konsequent, auch die Funktionen
> zu benutzen, um mit der Peripherie zu sprechen.

Weil ich irgendwie nicht so recht weiß, wie ich mit GPTD2 den Timer 
genauso konfigurieren kann, wie mit den Registern. Wie man den clock 
einstellt und die callback function alle x GPT clock cycles aufruft, 
sehe ich schon raus.
1
static GPTConfig gpt2cfg =
2
{
3
    200000, //timer clock
4
    callback  //Timer callback
5
};
6
 // Configure the GPT timer
7
 gptStart(&GPTD2, &gpt2cfg);
8
 gptStartContinuous(&GPTD2, 100);

Aber wie stelle ich da zB. das Prescaler, Auto-Reload Register ein? Wie 
kann ich sagen, ob er rauf oder runterzählen soll, im Center-aligned 
oder Capture/Compare mode arbeiten soll. Da hab ich irgendwie nicht so 
recht den Durchblick. Gibts da weitere Strukturen, um das alles 
einzustellen? Wenn ich die Register zu Fuß beschreibe, ist es für mich 
"etwas" übersichtlicher. Da spreche ich auch nur jene Register an, die 
ich wirklich brauche. Gibts da nicht einen Vorteil in Sachen 
Geschwindigkeit? In weiterer Folge soll nämlich eine Regelung mit 20kHz 
betrieben werden.

> Weiterhin solltest du mal schauen, ob der NVIC sinnvoll initialisiert
> ist. Das betrifft vor allem die Prioritätsgruppen und -level.

Werd den NVIC mal entsprechend initialisieren. Vllt klappt es ja 
anschließend.

Lg

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


Lesenswert?

Gabriel J. schrieb:
> Aber wie stelle ich da zB. das Prescaler, Auto-Reload Register ein? Wie
> kann ich sagen, ob er rauf oder runterzählen soll, im Center-aligned
> oder Capture/Compare mode arbeiten soll.

Schau einfach mal hier:
Beitrag "STM32 Timer Callback wird nicht aufgerufen?"

Dort hat der TE das alles mit HAL gemacht. Es gab nur ein kleines 
Problem mit dem NVIC.
Und es ist eigentlich immer so, das man die Dokumentation vergessen kann 
und sich einfach die Libraries durchliest, die man benutzen will. Dort 
haben die eigentlichen Programmierer der Sachen meistens auch schon 
Anleitungen reingeschrieben, die die Doku toppen.

von Gabriel J. (nyquist)


Lesenswert?

Matthias S. schrieb:

> Schau einfach mal hier:
> Beitrag "STM32 Timer Callback wird nicht aufgerufen?"
>
> Dort hat der TE das alles mit HAL gemacht. Es gab nur ein kleines
> Problem mit dem NVIC.
> Und es ist eigentlich immer so, das man die Dokumentation vergessen kann
> und sich einfach die Libraries durchliest, die man benutzen will. Dort
> haben die eigentlichen Programmierer der Sachen meistens auch schon
> Anleitungen reingeschrieben, die die Doku toppen.

Danke für die Information! Werd ich demnächst wirklich mit HAL machen. 
Hab meinen Fehler nun endlich gefunden. Es lag an den ST Driver System 
Settings. Anscheinend tretten mehrerer Interrupts gleichzeitig auf und 
irgendwie greift diese Struktur so auf den TIM2-Interrupt zu, dass bei 
meinem Code der Handler nicht aufgerufen wird.

Lösung:
In mcuconf.h:
1
#define STM32_ST_USE_TIMER        5// vorher 2

Da Timer 5 und 2 identisch sind.

In main.c:
1
void STM32_TIM2_HANDLER(void){
2
   if ((TIM2->SR & TIM_SR_UIF) != 0){
3
       palTogglePad(GPIOD, GPIOD_LED3);
4
       tim_cnt++;
5
     }
6
   // Clear update interrupt flag
7
   TIM2->SR &= ~(0xffff);
8
}

Danke für die sehr hilfreichen Antworten/Informationen. Hat für das 
Verständnis sehr geholfen!! Lg Gabriel

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.