mikrocontroller.net

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


Autor: domi_ (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...
void Timeout10usIntConfiguration(void) // wird in main ausgeführt
{
   NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
   NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
   NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStruct);
}
// initialisierung der delay funktion
void Timeout10usConfiguration(unsigned short Value)
/*~-*/
{
   TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
   /*~+:Configure TIM3 for clock generation*/
   TIM_DeInit(TIM3);
   /*~+:Time base configuration*/
   TIM_TimeBaseStructure.TIM_Period = 10*Value-1;
   TIM_TimeBaseStructure.TIM_Prescaler = 71;
   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;
   TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
   TIM_ClearFlag(TIM3, TIM_FLAG_Update);
   TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);

   TIM_ClearFlag(TIM3, TIM_FLAG_Update);
   TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE); // enable Update Interrupt

   TIM_ClearFlag(TIM3, TIM_FLAG_Update); /* clear int flag */
   TIM_Cmd(TIM3, ENABLE); /* start timer */
}

void TIM3_IRQHandler(void)
{
   TIM_Cmd(TIM3, DISABLE); /* stop timer */
   TIM_ClearFlag(TIM3, TIM_FLAG_Update); /* clear int flag */
   boTim3End = TRUE;
}
Timeout10usConfiguration wird mit entsprechendem Wert aufgerufen und 
danach wird auf das Flag gewartet:
 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:
 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_

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: domi_ (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
domi_ schrieb:

>
 while(boTim3End == FALSE); 

Ist diese Var volatile?

Autor: domi_ (Gast)
Datum:

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

Autor: domi_ (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
while(TIM_GetFlagStatus(TIM3, TIM_FLAG_Update) == SET); 
Gibt es da auch eine Möglichkeit das Flag nochmals einzulesen, wie das 
volatile?

Autor: A. K. (prx)
Datum:

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

Autor: domi_ (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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);

Autor: domi_ (Gast)
Datum:

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

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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) ;

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
domi_ schrieb:

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

Wohl kaum. Darf er nicht.

Autor: Arne (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?!

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Korrektur: SysTick stimmt, der gezeigte Code nicht.

Autor: domi_ (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Florian (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.