Forum: Mikrocontroller und Digitale Elektronik STM32 Delayfunktion mit Timer bzw. Timerflagabfrage Problem


von domi_ (Gast)


Lesenswert?

Hallo,

ich besitze ein Keil Cortex-M3 Eval-Board (MCBSTM32 Vers1.1) inkl. Keil 
uVision Compiler. Ich möchte gerne einen Timer (Tim3) nutzen um eine 
Delay-Funktion zu generieren. Doch scheint es mir so als ob der Timer 
nicht richtig läuft. Ich hoffe Ihr könnt mir weiterhelfen. Ich löse die 
Timerfunktion aus und warte auf das Setzen des TIM_FLAG_Update-Flags, es 
wird aber gar nicht auf die Flag-Änderung gewartet sondern mein 
restlicher nachfolgender Code ausgeführt...
1
void Timeout10usIntConfiguration(void) // wird in main ausgeführt
2
{
3
   NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
4
   NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
5
   NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
6
   NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
7
   NVIC_Init(&NVIC_InitStruct);
8
}
9
// initialisierung der delay funktion
10
void Timeout10usConfiguration(unsigned short Value)
11
/*~-*/
12
{
13
   TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
14
   /*~+:Configure TIM3 for clock generation*/
15
   TIM_DeInit(TIM3);
16
   /*~+:Time base configuration*/
17
   TIM_TimeBaseStructure.TIM_Period = 10*Value-1;
18
   TIM_TimeBaseStructure.TIM_Prescaler = 71;
19
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
20
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;
21
   TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
22
   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
23
   TIM_ClearFlag(TIM3, TIM_FLAG_Update);
24
   TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
25
26
   TIM_ClearFlag(TIM3, TIM_FLAG_Update);
27
   TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // enable Update Interrupt
28
29
   TIM_ClearFlag(TIM3, TIM_FLAG_Update); /* clear int flag */
30
   TIM_Cmd(TIM3, ENABLE); /* start timer */
31
}
32
33
void TIM3_IRQHandler(void)
34
{
35
   TIM_Cmd(TIM3, DISABLE); /* stop timer */
36
   TIM_ClearFlag(TIM3, TIM_FLAG_Update); /* clear int flag */
37
   boTim3End = TRUE;
38
}
Timeout10usConfiguration wird mit entsprechendem Wert aufgerufen und 
danach wird auf das Flag gewartet:
1
 while(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) == SET);
Da dies nicht half habe ich es mit dem Setzen von boTim3End versucht, 
was in einem Deadlock endet:
1
 while(boTim3End == FALSE);

Wie bereits geschrieben wird das Flag bei TIM_GetFlagStatus nicht 
beachtet und einfach der nachfolgende Code ausgeführt.

Woran könnte das liegen bzw. wo ist mein Fehler oder kann ich keine 
Flags/Variablen, die innerhalb der Interruptroutine gesetzt werden 
ausserhalb der abfragen?

Gruß domi_

von Arne (Gast)


Lesenswert?

Ich selbst benutze das BSP von ST nicht, aber wird Timer 3 bei Dir im 
RCC 'enabled'? RCC_APB1ENR: Bit TIM3EN muss gesetzt sein, sonst wird der 
Timer überhaupt nicht aktiviert.

von domi_ (Gast)


Lesenswert?

Also Timer 3 verfügt über Clock (72 Mhz) und wird auch enabled im 
RCC_APB1ENR. Der Interrupt scheint später zu kommen, nur mein "normaler" 
Applikationscode wartet nicht darauf sondern läuft nach dem Aufruf der 
Delayfunktion einfach weiter...

von (prx) A. K. (prx)


Lesenswert?

domi_ schrieb:

> Also Timer 3 verfügt über Clock (72 Mhz)

72MHz wohl kaum, denn bis auf die Timer1 und 8 sitzen die Dinger am APB1 
und der taktet mit maximal der Hälfte. Nur APB2 kann bei 72MHz die volle 
Ladung ab.

von (prx) A. K. (prx)


Lesenswert?

domi_ schrieb:

>
1
 while(boTim3End == FALSE);

Ist diese Var volatile?

von domi_ (Gast)


Lesenswert?

Nein war sie nicht, hat geholfen. Jetzt funzts :)
Vielen Dank!

von domi_ (Gast)


Lesenswert?

Jetzt habe ich noch eine kurze Frage. Kann es sein, dass die Abfrage der 
Flags ausserhalb der ISR nicht richtig funktioniert bzw. falsche Werte 
zurückliefert? Bspw. bei:
1
while(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) == SET);
Gibt es da auch eine Möglichkeit das Flag nochmals einzulesen, wie das 
volatile?

von (prx) A. K. (prx)


Lesenswert?

Sollte so funktionieren. Nur muss irgend jemand das Flag auch mal 
zurücksetzen. Wie sah der Code dieser Version aus?

von domi_ (Gast)


Lesenswert?

Fast genauso. Die ISR hat den Timer abgeschaltet (disable) und nach dem 
While wurde das Flag zurückgesetzt TIM_ClearFlag(TIM3, TIM_FLAG_Update);

von domi_ (Gast)


Lesenswert?

Ah, ich vermute der Compiler hat die While-Schleife wegoptimiert... 
Werde ich mal überprüfen.

von (prx) A. K. (prx)


Lesenswert?

Wenn du sowieso auf's Flag wartest, warum dann überhaupt ein Interrupt?

Aber weshalb du für sowas überhaupt einen der Timer verbrätst will mir 
nicht in den Sinn. Für sowas gibt's beim Cortex den SysTick. Prinzip:
  int t = (SysTick + 10*72) & 0x00FFFFFF;
  while ((int)(t - SysTick) > 0) ;

von (prx) A. K. (prx)


Lesenswert?

domi_ schrieb:

> Ah, ich vermute der Compiler hat die While-Schleife wegoptimiert...

Wohl kaum. Darf er nicht.

von Arne (Gast)


Lesenswert?

> Wohl kaum. Darf er nicht.
Richtig. Denn die Funktion in der while() bedingung kann Seiteneffekte 
aufweisen!
Für solche Warteaufgaben eignet sich der 24bit Systick doch deutlich 
besser?!

von (prx) A. K. (prx)


Lesenswert?

Korrektur: SysTick stimmt, der gezeigte Code nicht.

von domi_ (Gast)


Lesenswert?

Stimmt da benötige ich die ISR gar nicht mehr (jetzt kann ich auch das 
Flag richtig abfragen). Der Systick ist mir auch bekannt, aber einen 
Systick-Interrupt alle paar uS auszulösen finde ich auch nicht so 
prickelnd. Da habe ich ja "nur noch Interrupts". Diese Delay-Funktion 
benötige ich seltener und kann den Timer ja auch nach dem Einsatz 
wiederverwenden mit anderer Zeitdauer bzw. Funktionalität.

von (prx) A. K. (prx)


Lesenswert?

domi_ schrieb:

> Flag richtig abfragen). Der Systick ist mir auch bekannt, aber einen
> Systick-Interrupt alle paar uS auszulösen finde ich auch nicht so
> prickelnd. Da habe ich ja "nur noch Interrupts".

Nein. Du kannst für aktives Warten bei jedem Timer, dessen Periode 
deutlich grösser als die Wartezeit ist, direkt den Counter abfragen. 
Egal ob das einer der Peripherie-Timer oder der SysTick ist. Einen 
Compare-Channel benötigst du dafür nicht.

von Florian (Gast)


Lesenswert?

Hallo A. K.,

> 72MHz wohl kaum, denn bis auf die Timer1 und 8 sitzen die Dinger am APB1
> und der taktet mit maximal der Hälfte. Nur APB2 kann bei 72MHz die volle
> Ladung ab.

Mit Deiner Aussage bist Du leider auf dem Holzweg.
Timer3 kann sehr wohl mit 72 MHz getaktet werden.

Schau Dir mal den Clock Tree vom STM32 an:
Am ABP1 Prescaler dürfen max. 36 MHz rauskommen.
Die Timer am ABP1 werden aber nicht direkt von diesem Clock versorgt, 
sondern durchlaufen noch einen Block mit Taktvervielfachung, der 
folgenden Inhalt hat:
{
  TIM2,3,4
  If (APB1 prescaler = 1) x1
  else x2
}

Beispiel:
SYSCLK = 72 MHz
AHB Prescaler = 1
ABP1 Prescaler = 2
-> PCLK1 = 36 MHz
-> TIMXCLK = 36 MHz x 2 = 72 MHZ

P.S.: Über diese Spezialität bin ich auch erst gestolpert, als mein 
Timer3 immer nur halb so große Zeitintervalle wie geplant erzeugt hat...


Viele Grüsse,

Florian

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.