Forum: Mikrocontroller und Digitale Elektronik Timer Interrupt STM32F4


von Bert S. (kautschuck)


Lesenswert?

Hallo,

Ich verstehe nicht, warum das folgende Programm auf meinem STM32F4 
Discovery Board keinen Interrupt auslöst? Die APB1 Clock ist 45Mhz und 
daher müsste ich am Ausgang PD12 ein 9Hz Signal empfangen, doch 
anscheinden wird TIM2_IRQHandler nie aufgerufen.

Grüsse
1
#include "stm32f4xx.h"
2
#include "stm32f4xx_tim.h"
3
#include "stm32f4xx_gpio.h"
4
#include "stm32f4xx_rcc.h"
5
6
void InitializeLEDs()
7
{
8
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
9
10
    GPIO_InitTypeDef gpioStructure;
11
    gpioStructure.GPIO_Pin = GPIO_Pin_12;
12
    gpioStructure.GPIO_Mode = GPIO_Mode_OUT;
13
    gpioStructure.GPIO_Speed = GPIO_Speed_50MHz;
14
    GPIO_Init(GPIOD, &gpioStructure);
15
16
    GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
17
}
18
19
void InitializeTimer()
20
{
21
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
22
23
    TIM_TimeBaseInitTypeDef timerInitStructure;
24
    timerInitStructure.TIM_Prescaler = 10000;
25
    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
26
    timerInitStructure.TIM_Period = 500;
27
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
28
    timerInitStructure.TIM_RepetitionCounter = 0;
29
    TIM_TimeBaseInit(TIM2, &timerInitStructure);
30
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
31
    TIM_Cmd(TIM2, ENABLE);
32
33
}
34
35
void EnableTimerInterrupt()
36
{
37
    NVIC_InitTypeDef nvicStructure;
38
    nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
39
    nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
40
    nvicStructure.NVIC_IRQChannelSubPriority = 1;
41
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;
42
    NVIC_Init(&nvicStructure);
43
}
44
45
void TIM2_IRQHandler()
46
{
47
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
48
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
49
        GPIO_ToggleBits(GPIOD, GPIO_Pin_12);   //should see a frequency of 9Hz at the Output PD12
50
    }
51
}
52
53
int main()
54
{
55
    InitializeLEDs();
56
    InitializeTimer();
57
  EnableTimerInterrupt();
58
59
60
  for(;;);
61
}

von Bert S. (kautschuck)


Lesenswert?

Anscheinend stürzt der STM32F4 bei folgender Instruktion ab:

TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //Enable Tim2 Interrupt

bzw. bei diesen:

nvicStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvicStructure);

Anscheinend sobald also der Interrupt aktiviert wird, crasht der STM32F4 
Discovery, warum auch immer.

: Bearbeitet durch User
von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Am Anfang der main() vermisse ich SystemInit()
1
#include "stm32f4xx_syscfg.h"
2
int main(void) {
3
SystemInit(); 
4
// und die Konfiguration des Systick
5
if (SysTick_Config(SystemCoreClock / 1000))
6
 {
7
   /* Capture error */
8
   while (1);
9
 }
10
// du kannst ausserdem das Prioritätsschema des NVIC ändern, aber nur
11
// wenn du weisst, was du tust
12
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);    //4 bits for preemp priority 0 bit for sub priority

Probier das mal. Ansonsten sieht das nämlich alles recht gut aus.

: Bearbeitet durch User
von Bert S. (kautschuck)


Lesenswert?

Hallo Matthias,

Ich habe das in main eingefügt, leider ohne erfolg.

So gibt mir der PD12 ein High aus:
1
int main()
2
{
3
  SystemInit();
4
5
  InitializeLEDs();
6
  //InitializeTimer();
7
  //EnableTimerInterrupt();
8
  GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
9
10
11
  // und die Konfiguration des Systick
12
  if (SysTick_Config(SystemCoreClock / 1000))
13
   {
14
15
       /* Capture error */
16
    while (1);
17
   }
18
}

So hingegen ein Low:
1
int main()
2
{
3
  SystemInit();
4
5
  // und die Konfiguration des Systick
6
  if (SysTick_Config(SystemCoreClock / 1000))
7
   {
8
  InitializeLEDs();
9
  //InitializeTimer();
10
  //EnableTimerInterrupt();
11
  GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
12
       /* Capture error */
13
    while (1);
14
   }
15
}

Damit scheint was mit der SystemInit() gar nicht hinzuhauen.

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


Lesenswert?

Bert S. schrieb:
> Damit scheint was mit der SystemInit() gar nicht hinzuhauen.

Da hast du was missverstanden. Das 'while (1)' nach 'SysTick_Config()' 
wird nur im Fehlerfall angesprungen und sorgt bei misslungenen Versuchen 
für eine Endlosschleife.
Dein Programm sollte dahinter ganz normal weitergehen.
Also:
1
int main()
2
{
3
  SystemInit();
4
  // und die Konfiguration des Systick auf 1ms 
5
  if (SysTick_Config(SystemCoreClock / 1000))
6
   {
7
       /* Capture error */
8
    while (1);
9
   }
10
// hier gehts weiter mit main()
11
  InitializeLEDs();
12
  //InitializeTimer();
13
  //EnableTimerInterrupt();
14
  GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
15
// usw. usf.
16
// jetzt die Hauptschleife
17
  while (1) {
18
// hauptschleifen dinge
19
20
  } // ende while
21
} // ende main

: Bearbeitet durch User
von Bert S. (kautschuck)


Lesenswert?

So bekomme ich ein High an PD12, der Timer löst aber leider immer noch 
keinen Interrupt aus.

von Bert S. (kautschuck)


Lesenswert?

Ich verstehe das einfach nicht, sobald ich den Interrupt durch
1
IM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //Enable Tim2 Interrupt

bzw. so
1
nvicStructure.NVIC_IRQChannelCmd = ENABLE;

einschalte, dann scheint das Hauptprogramm zu hängen, also als würde es 
durch dauernd neue Interrupt gestoppt. Ich habe dies mit dem Debugger 
überprüft.

von Bert S. (kautschuck)


Lesenswert?

Ok, ich habe nun herausgefunden, dass der Timer läuft. Das Programm 
scheint sich erst aufzuhängen, wenn ich irgendwo die Funktion
GPIO_WriteBit(GPIOA, GPIO_Pin_6, Bit_SET); bzw.
GPIO_ToggleBits(GPIOA, GPIO_Pin_6); aufrufe, warum auch immer das nicht 
mit dem Timer verträglich ist.

1
#include "stm32f4xx.h"
2
#include "stm32f4xx_tim.h"
3
#include "stm32f4xx_gpio.h"
4
#include "stm32f4xx_rcc.h"
5
#include "stm32f4xx_syscfg.h"
6
7
void GPIO_Configuration(void)
8
{
9
  GPIO_InitTypeDef GPIO_InitStructure;
10
11
  /* GPIOA clock enable */
12
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
13
14
  /*  pin configuration */
15
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
16
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
17
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
18
  GPIO_Init(GPIOA, &GPIO_InitStructure);
19
20
}
21
22
23
void TIM2_Configuration(void)
24
{
25
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
26
  int i;
27
28
  /* Enable TIM2 Peripheral clock */
29
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
30
31
  TIM_TimeBaseStructure.TIM_Prescaler = 60000;
32
  TIM_TimeBaseStructure.TIM_Period = 750;    //1Hz Interrupt frequency
33
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
34
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
35
36
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
37
38
  TIM_Cmd(TIM2, ENABLE);
39
40
  // Likely will interrupt initially unless we clear it
41
42
  for(i=0; i<3; i++)
43
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
44
      TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
45
46
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
47
}
48
49
//****************************************************************************
50
51
void TIM2_IRQHandler(void)
52
{
53
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
54
  {
55
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
56
57
    //GPIO_ToggleBits(GPIOA, GPIO_Pin_6);
58
  }
59
}
60
61
//****************************************************************************
62
63
void NVIC_Configuration(void)
64
{
65
  NVIC_InitTypeDef NVIC_InitStructure;
66
67
  /* Enable the TIM2 global Interrupt */
68
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
69
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
70
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
71
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
72
  NVIC_Init(&NVIC_InitStructure);
73
}
74
75
//****************************************************************************
76
77
int main(void)
78
{
79
  SystemInit();
80
81
  if (SysTick_Config(SystemCoreClock / 1000))
82
  {
83
    /* Capture error */
84
    while (1);
85
  }
86
87
  NVIC_Configuration();
88
89
  GPIO_Configuration();
90
91
  TIM2_Configuration();
92
93
  //GPIO_WriteBit(GPIOA, GPIO_Pin_6, Bit_SET);
94
95
  int i=0;
96
  while(1) {
97
    i=TIM2->CNT;
98
  }
99
}

: Bearbeitet durch User
von Bert S. (kautschuck)


Angehängte Dateien:

Lesenswert?

Ich habe hier mal ein Debug Bild, der Wert in GPIOC->BSRRL bleibt immer 
0, irgendwie kann ich also den Ausgang nicht mehr setzen. Am Anfang 
bleibt der Ausgang PC6 ganz kurz auf high, dann fällt er auf low und 
bleibt für immer dort. Hat Jemand schon mal so etwas gehabt? Finde im 
Netz nichts dazu.

Edit: es muss natürlich BSRRL sein, nicht BSRRH, doch der Effekt ist der 
selbe. irgendwie werden also gleich zu Beginn alle Ausgänge 
zurückgesetzt, nachdem der Timer Interrupt aktiv wird, ohne das der 
Counter bereits einen Interrupt auslösen würde.

: Bearbeitet durch User
von Bert S. (kautschuck)


Lesenswert?

Die Funktion
1
void TIM2_IRQHandler(void)

wird nie aufgerufen, obwohl der Timer normal läuft und auch resetet 
wird.

von Bert S. (kautschuck)


Lesenswert?

Ich habe hier noch einen STM32F3 Discovery und mal folgenden Code 
probiert:
1
/**
2
  ******************************************************************************
3
  * @file    main.c
4
  * @author  Ac6
5
  * @version V1.0
6
  * @date    01-December-2013
7
  * @brief   Default main function.
8
  ******************************************************************************
9
*/
10
11
12
#include "stm32f3xx.h"
13
#include "stm32f3_discovery.h"
14
      
15
volatile int b=0;
16
17
void initTimerTIM2() {
18
19
    RCC->AHBENR = RCC_AHBENR_GPIOCEN;
20
    GPIOC->MODER = GPIO_MODER_MODER6_0;
21
    GPIOC->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR6);
22
    GPIOC->BSRR = GPIO_BSRR_BS_6;
23
24
    NVIC_SetPriorityGrouping(3);
25
    NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 6, 0));
26
    NVIC_EnableIRQ(TIM2_IRQn);
27
28
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
29
    TIM2->PSC = 10000 -1;
30
    TIM2->ARR = 750 -1;
31
    TIM2->DIER |= TIM_DIER_UIE; // enable update interrupt
32
    TIM2->CR1 |= TIM_CR1_CEN;
33
34
}
35
36
void TIM2_IRQHandler(void)
37
{
38
  // toggle Pin
39
  if(b) {
40
    b=0;
41
    GPIOC->BSRR = GPIO_BSRR_BR_6;
42
  } else {
43
    GPIOC->BSRR = GPIO_BSRR_BS_6;
44
    b=1;
45
  }
46
47
  // clear interrupt flag
48
  TIM2->SR &= ~(TIM_SR_UIF);
49
}
50
51
52
int main(void)
53
{
54
  initTimerTIM2();
55
  for(;;) {
56
57
  }
58
}

Das läuft wunderbar auf dem STM32F3, doch auf dem STM32F4 passiert 
nichts. Kann es sein, dass ich einen defekten bekommen habe?

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


Lesenswert?

Habe gerade mal hier durchgesucht, aber keiner meiner Codes benutzt 
Timer 2 sondern Timer 4. Was mir aber auffällt, das ich aus irgendeinem 
Grund vor der Freigabe von Timer Interrupts das IT_Update Flag lösche:
1
// configure the TIM4 interrupt line
2
  TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
3
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
4
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
5
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0b;
6
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
7
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
8
  NVIC_Init(&NVIC_InitStructure);

Das hat sicher einen Grund - könnte sich lohnen, das mal auszuprobieren.

Das hier ist sicher ein Tippfehler:
> void TIM2_IRQHandler(void)
> {
>   // toggle Pin
>   if(b) {
>     b=0;
>     GPIOC->BSRR = GPIO_BSRR_BR_6;  // tut beide Male das gleiche
>   } else {
>     GPIOC->BSRR = GPIO_BSRR_BS_6;
>     b=1;
>   }
Du meinst vermutlich
1
GPIOC->BRR = GPIO_BSRR_BS_6;
bei einer der beiden Zeilen. Es reicht aber auch ein
1
GPIOC->ODR ^= GPIO_Pin_6;

Damit toggelt es. Und nicht vergessen , in der ISR das Flag zu löschen, 
wie oben schon von dir geschrieben. Sonst wars das mit der ISR.

: Bearbeitet durch User
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.