Timer Interrupt STM32F4

OP #4738022
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
}
(Firma: matzetronics) #4738213
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.
OP #4738226
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.
(Firma: matzetronics) #4738267
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
OP #4738469
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.
OP #4738735
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
}
OP #4738743
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.
Angehängte Dateien:
OP #4738808
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?
(Firma: matzetronics) #4739238
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.

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