mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer Interrupt STM32F4


Autor: Bert S. (kautschuck)
Datum:

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

#include "stm32f4xx.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"

void InitializeLEDs()
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

    GPIO_InitTypeDef gpioStructure;
    gpioStructure.GPIO_Pin = GPIO_Pin_12;
    gpioStructure.GPIO_Mode = GPIO_Mode_OUT;
    gpioStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &gpioStructure);

    GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
}

void InitializeTimer()
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    TIM_TimeBaseInitTypeDef timerInitStructure;
    timerInitStructure.TIM_Prescaler = 10000;
    timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    timerInitStructure.TIM_Period = 500;
    timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    timerInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM2, &timerInitStructure);
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);

}

void EnableTimerInterrupt()
{
    NVIC_InitTypeDef nvicStructure;
    nvicStructure.NVIC_IRQChannel = TIM2_IRQn;
    nvicStructure.NVIC_IRQChannelPreemptionPriority = 0;
    nvicStructure.NVIC_IRQChannelSubPriority = 1;
    nvicStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&nvicStructure);
}

void TIM2_IRQHandler()
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        GPIO_ToggleBits(GPIOD, GPIO_Pin_12);   //should see a frequency of 9Hz at the Output PD12
    }
}

int main()
{
    InitializeLEDs();
    InitializeTimer();
  EnableTimerInterrupt();


  for(;;);
}


Autor: Bert S. (kautschuck)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Matthias S. (Firma: matzetronics) (mschoeldgen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Am Anfang der main() vermisse ich SystemInit()
#include "stm32f4xx_syscfg.h"
int main(void) {
SystemInit(); 
// und die Konfiguration des Systick
if (SysTick_Config(SystemCoreClock / 1000))
 {
   /* Capture error */
   while (1);
 }
// du kannst ausserdem das Prioritätsschema des NVIC ändern, aber nur
// wenn du weisst, was du tust
  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
Autor: Bert S. (kautschuck)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Matthias,

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

So gibt mir der PD12 ein High aus:
int main()
{
  SystemInit();

  InitializeLEDs();
  //InitializeTimer();
  //EnableTimerInterrupt();
  GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);


  // und die Konfiguration des Systick
  if (SysTick_Config(SystemCoreClock / 1000))
   {

       /* Capture error */
    while (1);
   }
}

So hingegen ein Low:
int main()
{
  SystemInit();

  // und die Konfiguration des Systick
  if (SysTick_Config(SystemCoreClock / 1000))
   {
  InitializeLEDs();
  //InitializeTimer();
  //EnableTimerInterrupt();
  GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
       /* Capture error */
    while (1);
   }
}

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

Autor: Matthias S. (Firma: matzetronics) (mschoeldgen)
Datum:

Bewertung
0 lesenswert
nicht 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:
int main()
{
  SystemInit();
  // und die Konfiguration des Systick auf 1ms 
  if (SysTick_Config(SystemCoreClock / 1000))
   {
       /* Capture error */
    while (1);
   }
// hier gehts weiter mit main()
  InitializeLEDs();
  //InitializeTimer();
  //EnableTimerInterrupt();
  GPIO_WriteBit(GPIOD, GPIO_Pin_12, Bit_SET);
// usw. usf.
// jetzt die Hauptschleife
  while (1) {
// hauptschleifen dinge

  } // ende while
} // ende main


: Bearbeitet durch User
Autor: Bert S. (kautschuck)
Datum:

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

Autor: Bert S. (kautschuck)
Datum:

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

bzw. so
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.

Autor: Bert S. (kautschuck)
Datum:

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



#include "stm32f4xx.h"
#include "stm32f4xx_tim.h"
#include "stm32f4xx_gpio.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_syscfg.h"

void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  /* GPIOA clock enable */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  /*  pin configuration */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

}


void TIM2_Configuration(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  int i;

  /* Enable TIM2 Peripheral clock */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  TIM_TimeBaseStructure.TIM_Prescaler = 60000;
  TIM_TimeBaseStructure.TIM_Period = 750;    //1Hz Interrupt frequency
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  TIM_Cmd(TIM2, ENABLE);

  // Likely will interrupt initially unless we clear it

  for(i=0; i<3; i++)
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
      TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}

//****************************************************************************

void TIM2_IRQHandler(void)
{
  if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

    //GPIO_ToggleBits(GPIOA, GPIO_Pin_6);
  }
}

//****************************************************************************

void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;

  /* Enable the TIM2 global Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

//****************************************************************************

int main(void)
{
  SystemInit();

  if (SysTick_Config(SystemCoreClock / 1000))
  {
    /* Capture error */
    while (1);
  }

  NVIC_Configuration();

  GPIO_Configuration();

  TIM2_Configuration();

  //GPIO_WriteBit(GPIOA, GPIO_Pin_6, Bit_SET);

  int i=0;
  while(1) {
    i=TIM2->CNT;
  }
}



: Bearbeitet durch User
Autor: Bert S. (kautschuck)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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
Autor: Bert S. (kautschuck)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Funktion
void TIM2_IRQHandler(void)

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

Autor: Bert S. (kautschuck)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe hier noch einen STM32F3 Discovery und mal folgenden Code 
probiert:
/**
  ******************************************************************************
  * @file    main.c
  * @author  Ac6
  * @version V1.0
  * @date    01-December-2013
  * @brief   Default main function.
  ******************************************************************************
*/


#include "stm32f3xx.h"
#include "stm32f3_discovery.h"
      
volatile int b=0;

void initTimerTIM2() {

    RCC->AHBENR = RCC_AHBENR_GPIOCEN;
    GPIOC->MODER = GPIO_MODER_MODER6_0;
    GPIOC->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR6);
    GPIOC->BSRR = GPIO_BSRR_BS_6;

    NVIC_SetPriorityGrouping(3);
    NVIC_SetPriority(TIM2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 6, 0));
    NVIC_EnableIRQ(TIM2_IRQn);

    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
    TIM2->PSC = 10000 -1;
    TIM2->ARR = 750 -1;
    TIM2->DIER |= TIM_DIER_UIE; // enable update interrupt
    TIM2->CR1 |= TIM_CR1_CEN;

}

void TIM2_IRQHandler(void)
{
  // toggle Pin
  if(b) {
    b=0;
    GPIOC->BSRR = GPIO_BSRR_BR_6;
  } else {
    GPIOC->BSRR = GPIO_BSRR_BS_6;
    b=1;
  }

  // clear interrupt flag
  TIM2->SR &= ~(TIM_SR_UIF);
}


int main(void)
{
  initTimerTIM2();
  for(;;) {

  }
}


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

Autor: Matthias S. (Firma: matzetronics) (mschoeldgen)
Datum:

Bewertung
0 lesenswert
nicht 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:
// configure the TIM4 interrupt line
  TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
  TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
  NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0b;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  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
GPIOC->BRR = GPIO_BSRR_BS_6;
bei einer der beiden Zeilen. Es reicht aber auch ein
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

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.