STM32: Timer-Interrupt funktioniert sofort

Dies ist Code für den Timer in meinem Projekt auf STM32F429:

//timer initialization
 void timerInit()
 {
  uwPrescalerValue2 = (uint32_t) ((SystemCoreClock / 2) / 100000) - 1;
  RS485Timer.Instance = TIM5;
  RS485Timer.Init.Period = 67400000; // high value to notice interrupt even without debugging
  RS485Timer.Init.Prescaler = 400000;
  RS485Timer.Init.ClockDivision = 0;
  RS485Timer.Init.CounterMode = TIM_COUNTERMODE_UP;
  HAL_TIM_Base_Init(&RS485Timer);
 }

 void timerReset()
 {
 HAL_TIM_Base_Stop_IT(&RS485Timer);
 HAL_TIM_Base_DeInit(&RS485Timer);
 HAL_TIM_Base_Init(&RS485Timer);
 HAL_TIM_Base_Start_IT(&RS485Timer);
 printf("%d timer reset\n", countereset);
 countereset++;
 } 

 void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
 {
  /*##-1- Enable peripherals and GPIO Clocks #################################*/
  /* TIMx Peripheral clock enable */
  __TIM5_CLK_ENABLE();

  /*##-2- Configure the NVIC for TIMx #########################################*/
  /* Set the TIMx priority */
  HAL_NVIC_SetPriority(TIM5_IRQn, 7, 1);

  /* Enable the TIMx global Interrupt */
  HAL_NVIC_EnableIRQ(TIM5_IRQn);
 }

 void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef *htim)
 {
  __TIM5_FORCE_RESET();
  __TIM5_RELEASE_RESET();

  HAL_NVIC_DisableIRQ(TIM5_IRQn);
 }

 void TIM5_IRQHandler(void)
 {
  if (__HAL_TIM_GET_FLAG(&RS485Timer, TIM_FLAG_UPDATE) != RESET)      //In case other interrupts are also running
  {
   if (__HAL_TIM_GET_ITSTATUS(&RS485Timer, TIM_IT_UPDATE) != RESET)
   {
    __HAL_TIM_CLEAR_FLAG(&RS485Timer, TIM_FLAG_UPDATE);
    HAL_TIM_IRQHandler(&RS485Timer);
    printf("timer interrupt\n");
   }
  }
 }

Und nachdem ich die timerReset()Funktion mitten in meinem Programm ausgeführt habe, startet der Interrupt nicht wenige Sekunden später, sondern fast sofort. Ich habe einige andere Timer ausprobiert, um zu überprüfen, ob es kein Hardwareproblem gibt, aber nein, das ist es nicht.

Ich würde vorschlagen, dass Sie das Timer-Interrupt-Flag in Ihrer Funktion timerReset() explizit löschen.
Nach dem Hinzufügen zwischen DeInit und Init __HAL_TIM_CLEAR_FLAG(&RS485Timer, TIM_FLAG_UPDATE); und __HAL_TIM_CLEAR_FLAG(&RS485Timer, TIM_IT_UPDATE); es passiert nichts neues.

Antworten (6)

Ich bin mit einem STM32F105 darauf gestoßen. Die Funktionen der STM32F1xx-Standard-Peripheriebibliothek unterscheiden sich etwas von denen, die Sie verwenden, aber die Idee sollte die gleiche sein.

Das Ausgeben der TIM_TimeBaseInit()Funktion bewirkte, dass das TIM_SR_UIF-Flag gesetzt wurde. Ich bin noch nicht zurückgegangen, um herauszufinden, warum. Sobald dieses Bit gesetzt ist, wird der Interrupt ausgelöst, sobald er aktiviert ist.

Um das Problem zu beheben TIM_TimeBaseInit(), habe ich nach dem Anruf sofort angerufen TIM_ClearITPendingBit(). Dann würde ich den Interrupt mit aktivieren TIM_ITConfig(). Dies hat das Problem behoben.

Meine komplette Initialisierungsroutine sieht so aus:

// Enable the peripheral clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);

// Configure the timebase
TIM_TimeBaseInitStructure.TIM_Prescaler = 1;
TIM_TimeBaseInitStructure.TIM_Period = 35999;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStructure);

// That last function caused the UIF flag to get set. Clear it.
TIM_ClearITPendingBit(TIM5, TIM_IT_Update);

// Configure so that the interrupt flag is only set upon overflow
TIM_UpdateRequestConfig(TIM5, TIM_UpdateSource_Regular);

// Enable the TIM5 Update Interrupt type
TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
Dasselbe Problem bei STM32L151 mit den HAL-Bibliotheken. Problemumgehung (z. B. für TIM6):__HAL_TIM_CLEAR_FLAG(&htim6, TIM_SR_UIF);
Ein Kommentar im neuen HAL-Treiber erklärt, warum: Sie tun dies, um zu erzwingen, dass der PSC-Wert bei der Initialisierung aktualisiert wird, da er erst nach einem Aktualisierungsereignis tatsächlich in den SR->PSC geladen wird.
Schön, @Galaxy, danke für die Info.

Da ich ein ähnliches Problem hatte und keine Antworten gefunden hatte, teile ich meine Erfahrungen in der Hoffnung, anderen Menschen zu helfen.

Ich glaube, dass in Ihrem Fall das Einstellen des URS (Update Request Source) vor dem Initialisieren des Timers auch das Problem löst.

In meinem Fall verwende ich die Low-Layer-Treiber, also wäre ein Beispielcode:

//Enables APB1 TIM16 peripheral clock
LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_TIM16);

//Sets update event source to counter overflows only
LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER);

//Configures the TIM16 time base
LL_TIM_InitTypeDef TIM_InitStruct;
TIM_InitStruct.Prescaler = 7999;
TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
TIM_InitStruct.Autoreload = 2999;
TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
TIM_InitStruct.RepetitionCounter = 0;
LL_TIM_Init(TIM16, &TIM_InitStruct);

//Enables update interrupt
LL_TIM_EnableIT_UPDATE(TIM16);

//Enables timer counter
LL_TIM_EnableCounter(TIM16);

//Enables Interrupt
NVIC_EnableIRQ(TIM16_IRQn);

Das Problem ist, dass ich die Funktionen LL_TIM_SetPrescaler(TIM16, 7999)und LL_TIM_SetAutoReload(TIM16, 2999)verwendet habe, um die Zeitbasis zu konfigurieren, und festgestellt habe, dass die Werte bei Verwendung dieser Funktionen nicht aktualisiert wurden, sodass ich ein Ereignis generieren musste, um die Werte mit zu aktualisieren LL_TIM_GenerateEvent_UPDATE(TIM16).

Sie können dann entweder das Ereignis-Flag mit löschen, LL_TIM_ClearFlag_UPDATE(TIM16)bevor Sie den Interrupt aktivieren, oder verwenden, LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER)bevor Sie das Ereignis erzeugen.

Basierend auf der Lösung von programrsought.com

Flag TIM_SR_UIFvor jedem HAL_TIM_Base_Start_IT()Anruf löschen

#define FIX_TIMER_TRIGGER(handle_ptr) (__HAL_TIM_CLEAR_FLAG(handle_ptr, TIM_SR_UIF))

...

void myfunc(){
    FIX_TIMER_TRIGGER(&htim7);
    HAL_TIM_Base_Start_IT(&htim7); 
}

Getestet auf STM32F407 Discovery Board.

Denken Sie beim Debuggen daran, dass die Peripheriegeräte standardmäßig nicht beim Anhalten des Kerns anhalten, sodass die Timer den Interrupt weiterhin auslösen, während Sie angehalten sind. Ich hatte vor einiger Zeit auch schöne Kopfschmerzen, bis ich die Bits zum Einfrieren von Peripheriegeräten im Debug-Modus entdeckte.

Sie können es beim Start von main wie folgt aktivieren:

void main(void){

   __HAL_DBGMCU_FREEZE_TIM1();    // Enable Timer1 Freeze on Debug

   HAL_Init();

   // blah
   // blah rest of the main code
   // blah
}

Sie haben alle Definitionen am Anfang von stm32f4xx_hal.h

Ich hatte ein ähnliches Problem im One Pulse-Mod und fand eine Lösung für die HAL-Bibliothek. Als ich Timer-Flags in der Funktion "TIM2_IRQHandler" steuerte, sah ich, dass "Capture Compare Flag 1" gesetzt ist. Also habe ich "Capture Compare Flag 1" gelöscht. Aber dieses Mal habe ich gesehen, dass "Capture Compare Flag 2" gesetzt ist. Also habe ich alle Vergleichsflags (von 1 bis 4) in meiner Funktion "TIM2_IRQHandler" gelöscht, indem ich die folgenden Codes verwendet habe.

void TIM2_IRQHandler(void)
{
  /* USER CODE BEGIN TIM2_IRQn 0 */

  /* USER CODE END TIM2_IRQn 0 */
  HAL_TIM_IRQHandler(&htim2);
  /* USER CODE BEGIN TIM2_IRQn 1 */
  if(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC1) != RESET)
  {
      timer2Proccess();
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC1 );
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC2 );
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC3 );
      __HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_CC4 );
  }
  /* USER CODE END TIM2_IRQn 1 */
}

Gleiches Problem mit TIM_TimeBaseInit() und STM32F0xx. Der letzte String dieser Funktion:

  TIMx->EGR = TIM_PSCReloadMode_Immediate;

Es setzt das Aktualisierungsereignis im Ereigniserzeugungsregister. Deshalb habe ich den IRQ-Handler mit einem Häkchen versehen:

void TIM1_IRQHandler() {
if(TIM_GetFlagStatus(TIM1, TIM_FLAG_Update) == SET) {
    TIM_ClearITPendingBit(TIM1, TIM_IT_Update);
    if((TIM1 -> CR1 & TIM_CR1_CEN) == 0) return; //Timer is not working
    //Interrupt code