Forum: Mikrocontroller und Digitale Elektronik STM32: Timer funktioniert nicht


von Pete K. (pete77)


Lesenswert?

Hallo,

ich möchte gerne Timer-gesteuert eine LED blinken lassen (STM32F107RC 
mit CoIDE und winarm 4.6.

Aber irgendwie passt meine Timer-Routine nicht, der Interrupt-Handler 
wird nicht aufgerufen.
Stimmt die Initialisierung des Timers oder fehlt das noch etwas?

(Muss ja falsch sein, sonst würde es funktionieren :-)
1
#include "stm32f10x.h"
2
#include "stm32f10x_conf.h"
3
#include "stm32f10x_gpio.h"
4
#include "stm32f10x_rcc.h"
5
#include "stm32f10x_usart.h"
6
#include "stm32f10x_tim.h"
7
//#include "stm32f10x_spi.h"
8
//#include "stm32f10x_i2c.h"
9
//#include <stdio.h>
10
11
/***************************************************************************//**
12
 * Declare function prototypes
13
 ******************************************************************************/
14
void SetupClock(void);
15
void SetupUSART(void);
16
void SetupTimer(void);
17
void USART1_SendString(char* data);
18
19
20
21
// *************** main *************
22
23
int main(void)
24
{
25
  volatile int i;
26
27
28
  SetupClock();
29
  SetupUSART();
30
  SetupTimer();
31
32
  GPIO_InitTypeDef GPIO_InitStructure;
33
  /* Initialize LED which connected to PB11, Enable the Clock*/
34
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
35
  /* Configure the GPIO_LED pin */
36
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
37
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
38
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
39
  GPIO_Init(GPIOB, &GPIO_InitStructure);
40
41
  while (1) {
42
43
    //GPIOB->ODR ^= GPIO_Pin_10;
44
    /* delay */
45
    //for(i=0;i<0x300000;i++);
46
47
    //USART1_SendString("in while\n\r");
48
49
50
  }
51
}
52
53
void USART1_SendString(char* data)
54
{
55
  while (*data)
56
  {
57
    USART_SendData(USART1, (uint16_t) *data);
58
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC)==RESET);
59
    data++;
60
  }
61
}
62
63
void SetupTimer(void)
64
{
65
66
  TIM_TimeBaseInitTypeDef  TIM_TimeBase_InitStructure;
67
68
  /* Enable TIM2 clock */
69
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // sollten 72Mhz sein
70
71
  TIM_TimeBase_InitStructure.TIM_Prescaler = 7200; // (72Mhz/7200 = 10khz)
72
  TIM_TimeBase_InitStructure.TIM_ClockDivision = 10;  // nach Prescaler=1kHz
73
  TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Down;
74
  TIM_TimeBase_InitStructure.TIM_Period = 1000; // Eine Sekunde
75
76
  TIM_TimeBaseInit(TIM2, &TIM_TimeBase_InitStructure);
77
78
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);
79
80
81
82
  TIM_Cmd(TIM2, ENABLE);
83
  USART1_SendString("in SetupTimer\n\r");
84
}
85
86
//timer 2 interrupt
87
void TIM2_IRQHandler(void)
88
{
89
  USART1_SendString("in TIM1\n\r");
90
  //if interrupt happens the do this
91
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
92
  {
93
    //clear interrupt and start counting again to get precise freq
94
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
95
96
    //toggle led
97
    GPIOB->ODR ^= GPIO_Pin_10;
98
    USART1_SendString("in TIM2\n\r");
99
  }
100
}
101
102
/***************************************************************************//**
103
 * @brief Setup clocks
104
 ******************************************************************************/
105
void SetupClock()
106
{
107
      RCC_DeInit ();                    /* RCC system reset(for debug purpose)*/
108
      RCC_HSEConfig (RCC_HSE_ON);       /* Enable HSE (external Quarz)        */
109
110
      while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // Wait till HSE is ready
111
112
      /* Enable USART1 and GPIOA clock                                        */
113
      RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
114
115
      /* Configure PLLs *********/
116
      /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
117
      RCC_PREDIV2Config(RCC_PREDIV2_Div5);
118
      RCC_PLL2Config(RCC_PLL2Mul_8);
119
      RCC_PLL2Cmd(ENABLE);  // Enable PLL2
120
      while (RCC_GetFlagStatus(RCC_FLAG_PLL2RDY) == RESET); // Wait till PLL2 is ready
121
122
      /* PLL1 configuration: PLLCLK = (PLL2 / 5) * 9 = 72 MHz */
123
      RCC_PREDIV1Config(RCC_PREDIV1_Source_PLL2, RCC_PREDIV1_Div5);
124
      RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
125
      RCC_PLLCmd (ENABLE);
126
      while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // Wait till PLL is ready
127
128
}
129
/***************************************************************************//**
130
 * @brief Init USART1
131
 ******************************************************************************/
132
void SetupUSART()
133
{
134
      GPIO_InitTypeDef  GPIO_InitStructure;
135
      USART_InitTypeDef USART_InitStructure;
136
137
      /* Enable GPIOA clock                                                   */
138
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
139
140
      /* Configure USART1 Rx (PA10) as input floating                         */
141
      GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;
142
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
143
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
144
      GPIO_Init(GPIOA, &GPIO_InitStructure);
145
146
      /* Configure USART1 Tx (PA9) as alternate function push-pull            */
147
      GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;
148
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
149
      GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
150
      GPIO_Init(GPIOA, &GPIO_InitStructure);
151
152
      /* USART1 configured as follow:
153
            - BaudRate = 115200 baud
154
            - Word Length = 8 Bits
155
            - One Stop Bit
156
            - No parity
157
            - Hardware flow control disabled (RTS and CTS signals)
158
            - Receive and transmit enabled
159
            - USART Clock disabled
160
            - USART CPOL: Clock is active low
161
            - USART CPHA: Data is captured on the middle
162
            - USART LastBit: The clock pulse of the last data bit is not output to
163
                             the SCLK pin
164
      */
165
      USART_InitStructure.USART_BaudRate            = 115200;
166
      USART_InitStructure.USART_WordLength          = USART_WordLength_8b;
167
      USART_InitStructure.USART_StopBits            = USART_StopBits_1;
168
      USART_InitStructure.USART_Parity              = USART_Parity_No ;
169
      USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
170
      USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;
171
      USART_Init(USART1, &USART_InitStructure);
172
      USART_Cmd(USART1, ENABLE);
173
}

von (prx) A. K. (prx)


Lesenswert?

Timer-Interrupt konfigurieren. Also Priorität definieren und 
einschalten.

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


Lesenswert?

Pete K. schrieb:
> void TIM2_IRQHandler(void)
> {
>   USART1_SendString("in TIM1\n\r");

Keine gute Idee. Lass ihn lieber nur die LED toggeln. Immerhin möchtest 
du diesen String mit 10kHz aus der UART rausdrücken, das kann nicht gut 
gehen.

So könnte die Interruptfreigabe für Timer 1 aussehen, kannst du leicht 
für Timer 2 anpassen:
1
// Timer interrupt
2
/* TIM Interrupts enable */
3
NVIC_InitTypeDef NVIC_InitStructure;
4
//
5
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
6
/* Enable and set TIM1 Interrupt to the lowest priority */
7
/* Enable the TIM1 global Interrupt */
8
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM16_IRQn;
9
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
10
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
11
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
12
NVIC_Init(&NVIC_InitStructure);
13
TIM_Cmd(TIM1, ENABLE);
14
TIM_ClearITPendingBit(TIM1,TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3);

von Pete K. (pete77)


Lesenswert?

Habe das jetzt hinzugefügt (inkl. "misc.h") , funtktioniert aber immer 
noch nicht. D.h. der Timer-Interrupt wird nicht aufgerufen.
1
/* TIM Interrupts enable */
2
  NVIC_InitTypeDef NVIC_InitStructure;
3
  //
4
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
5
  /* Enable and set TIM1 Interrupt to the lowest priority */
6
  /* Enable the TIM1 global Interrupt */
7
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
8
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
9
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0;
10
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
11
  NVIC_Init(&NVIC_InitStructure);
12
  TIM_Cmd(TIM2, ENABLE);
13
  TIM_ClearITPendingBit(TIM2,TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | TIM_IT_CC3);

von (prx) A. K. (prx)


Lesenswert?

Dürfte nichts an der (Nicht-) Funktion ändern, aber NVIC sollte man per 
CMSIS Initialisieren, nicht mit den veralteten Funktionen der ST-Lib.

von Pete K. (pete77)


Lesenswert?

Funktionieren die mitgelieferten Funktionen der ST-Lib nicht?
Der Compiler/Linker wirft keine Fehlermeldungen.

von (prx) A. K. (prx)


Lesenswert?

Doch, sie funktionieren. Sie sind aber nur noch drin, damit Altprogramme 
aus der Zeit vor CMSIS übersetzbar bleiben.

von Pete K. (pete77)


Lesenswert?

Ich kann es drehen und wenden, wie ich will, der IRQ-Handler wird nicht 
angesprungen.

von Martin Beuttenmüller (Gast)


Lesenswert?

Ich kann mich irren, doch ich verstehe Deine PLL-Init so, dass Du
einen 25MHz Quarz verwendest. "Normal" sind doch eher 8MHz.
Mein Denkfehler oder eine Spezialanwendung ?

Dessweiteren hab' ich schon öfter gelesen, dass -gerade bei STM-
die gewünschten Peripherien eingeschaltet werden müssen.
GPIO und UART kann ich erkennen, doch bei den Timern bin ich
unsicher ...

Sind nur "Denkanstöße", bin selber (noch) am Lernen ...

Gruß
Martin

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


Lesenswert?

A. K. schrieb:
> Doch, sie funktionieren. Sie sind aber nur noch drin, damit Altprogramme
> aus der Zeit vor CMSIS übersetzbar bleiben.

So wie CMSIS aussieht, sind das nur marginale Unterschiede. Aber zeig 
uns doch mal bitte, wie das mit CMSIS aussehen würde.

Pete K. schrieb:
> RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // sollten 72Mhz sein

Das sieht verdächtig aus. Ich habe Timer2 noch nicht benutzt, aber der 
Timer1 wird so gestartet:
1
RCC_APB2PeriphClockCmd(TIM1_CLK, ENABLE);
Wenn du dir allerdings sicher bist, das APB1 für Timer2 zuständig ist, 
will ich nichts gesagt haben. Du solltest mal in der Hauptschleife 
checken, ob der Timer überhaupt rennt.

Pete K. schrieb:
> TIM_ClearITPendingBit(TIM2,TIM_IT_Update | TIM_IT_CC1 | TIM_IT_CC2 | 
TIM_IT_CC3);

Bei Timer2 brauchst du m.W. die CC Interrupts nicht zu löschen, da er 
sie gar nicht hat.

von Pete K. (pete77)


Lesenswert?

So, jetzt funktioniert es. Timer2 liegt bei dem STM32F107C auf AHB1, das 
stimmt soweit.

Die 25Mhz als externen Qaarz habe ich gewählt, weil ich noch Ethernet 
anschließen will (später :-). Anbei ein paar Folien, die ich zum Thema 
PLL gefunden habe.

Die PLL-Initialisierung habe ich herausgenommen und als Compiler-Symbol 
HSE_VALUE=25000000 übergeben.

Hier nun der funktionierende Code für einen 1 Sek. Timer:
1
void SetupTimer(void)
2
{
3
4
  TIM_TimeBaseInitTypeDef  TIM_TimeBase_InitStructure;
5
  NVIC_InitTypeDef  NVIC_InitStructure;
6
  uint16_t PrescalerValue;
7
8
  USART1_SendString("in SetupTimer1\n");
9
10
  /* Enable TIM2 clock */
11
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);  // sollten 36Mhz sein
12
13
  PrescalerValue = (uint16_t) 36000 - 1;   // Vorteiler berechnen  (36Mhz/36000 = 1khz)
14
  TIM_TimeBase_InitStructure.TIM_Prescaler = PrescalerValue; //
15
  TIM_TimeBase_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // nach Prescaler=1kHz
16
  TIM_TimeBase_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;
17
  TIM_TimeBase_InitStructure.TIM_Period = 1000; // Eine Sekunde (=1000*1kHz=1s)
18
19
  TIM_TimeBaseInit(TIM2, &TIM_TimeBase_InitStructure);
20
21
  //Timer Vorteiler-Taktkonfiguration
22
  TIM_PrescalerConfig(TIM2, PrescalerValue, TIM_PSCReloadMode_Immediate); // Auto-Reload
23
24
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
25
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
26
  NVIC_Init(&NVIC_InitStructure);
27
28
  // Timer Interruptkonfiguration
29
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                        // Interrupt bei Überlauf  
30
31
  TIM_ClearFlag(TIM2, TIM_FLAG_Update);
32
33
  // Enable and set TIM1 Interrupt to the lowest priority
34
  // Enable the TIM1 global Interrupt
35
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
36
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
37
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
38
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
39
  NVIC_Init(&NVIC_InitStructure);
40
41
  TIM_Cmd(TIM2, ENABLE);
42
  TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
43
44
  USART1_SendString("in SetupTimer2\n");
45
}
46
47
//timer 2 interrupt
48
extern  void TIM2_IRQHandler(void)
49
{  
50
  //if interrupt happens the do this
51
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
52
  {
53
    //clear interrupt and start counting again to get precise freq
54
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
55
    //toggle led
56
    GPIOB->ODR ^= GPIO_Pin_10;
57
  }
58
59
}

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


Lesenswert?

Na, das sind doch gute Nachrichten.
Pete K. schrieb:
> So, jetzt funktioniert es. Timer2 liegt bei dem STM32F107C auf AHB1, das
> stimmt soweit.
Ahh, ok. Ich fummele hier auch am 103RB des VL Discovery rum.
Pete K. schrieb:
1
> NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
2
>     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
3
>   NVIC_Init(&NVIC_InitStructure);
4
> 
5
>   // Timer Interruptkonfiguration
6
>   TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);                        // Interrupt bei Überlauf  
7
> 
8
>   TIM_ClearFlag(TIM2, TIM_FLAG_Update);
9
> 
10
>   // Enable and set TIM1 Interrupt to the lowest priority
11
>   // Enable the TIM1 global Interrupt
12
>   NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
13
>   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;
14
>   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;
15
>   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
16
>   NVIC_Init(&NVIC_InitStructure);
Öh, gehts erst, wenn man es zweimal macht? Wars das? War bei mir bis 
jetzt nicht nötig, aber kann ja sein. Bei der STM Doku weiss man ja 
immer nicht, wo man nachschauen muss.

von Pete K. (pete77)


Angehängte Dateien:

Lesenswert?

Bei der STM32 Perip. Lib ist ja auch ein chm-File als Hilfe enthalten. 
leider funktioniert das bei mir nach der Umstellung der ST-Seite nicht 
mehr. Die erste Seite wird so aufgerufen:
mk:@MSITStore:C:\winarm\STM32F10x_StdPeriph_Lib_V3.5.0\stm32f10x_stdperi 
ph_lib_um.chm::/index.html

??

Anbei noch die Folien, hatte ich im obigen Post vergessen.

Was es war, kann ich nicht mehr so genau sagen.

von Martin Beutenmüller (Gast)


Lesenswert?

Wow!

Die 25MHz sind erklärter Maßen beabsichtigt,
das Problem scheint gelöst zu sein ...

... meine Anerkennung hast Du!
Martin

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.