STM32: l'interruption de la minuterie fonctionne immédiatement

10

Voici le code de la minuterie dans mon projet sur 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");
   }
  }
 }

Et après avoir exécuté la timerReset()fonction au milieu de mon programme, l'interruption démarre quelques secondes plus tard, mais presque immédiatement. J'ai essayé quelques autres minuteries pour vérifier s'il n'y a pas de problème matériel, mais non, ce n'est pas le cas.

m0drzew
la source
Je vous suggère d'effacer explicitement l'indicateur d'interruption du minuteur dans votre fonction timerReset ().
brhans
1
Après avoir ajouté entre DeInit et Init __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_FLAG_UPDATE); et __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_IT_UPDATE); il ne se passe rien de nouveau.
m0drzew

Réponses:

9

J'ai rencontré ça avec un STM32F105. Les fonctions de la bibliothèque périphérique standard STM32F1xx sont un peu différentes de celles que vous utilisez, mais l'idée devrait être la même.

L'émission de la TIM_TimeBaseInit()fonction a entraîné la définition de l'indicateur TIM_SR_UIF. Je ne suis pas encore retourné pour comprendre pourquoi. Une fois ce bit défini, l'interruption se déclenchera dès qu'il sera activé.

Pour y remédier, après avoir appelé TIM_TimeBaseInit(), j'ai immédiatement appelé TIM_ClearITPendingBit(). Ensuite, je voudrais activer l'interruption avec TIM_ITConfig(). Cela a résolu le problème.

Ma routine d'initialisation complète ressemble à ceci:

// 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);
bitsmack
la source
2
Même problème sur STM32L151 en utilisant les bibliothèques HAL. Solution (par exemple pour TIM6):__HAL_TIM_CLEAR_FLAG(&htim6, TIM_SR_UIF);
3
Un commentaire dans le nouveau pilote HAL explique pourquoi: ils le font pour forcer la valeur PSC à être mise à jour à l'initialisation car elle n'est réellement chargée dans le SR-> PSC qu'après un événement de mise à jour.
Galaxy
Bien, @Galaxy, merci pour l'info.
bitsmack
1

Comme j'avais un problème similaire et que je n'avais pas trouvé de réponses, je partage mon expérience dans l'espoir d'aider d'autres personnes.

Je crois que dans votre cas, la définition de l'URS (Update Request Source) avant d'initialiser le minuteur résout également le problème.

Dans mon cas, j'utilise les pilotes de couche inférieure, donc un exemple de code serait:

//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);

Le problème est que j'utilisais les fonctions LL_TIM_SetPrescaler(TIM16, 7999)et LL_TIM_SetAutoReload(TIM16, 2999)pour configurer la base de temps, et j'ai découvert qu'en utilisant ces fonctions, les valeurs n'étaient pas mises à jour, j'ai donc dû générer un événement pour mettre à jour les valeurs à l'aide LL_TIM_GenerateEvent_UPDATE(TIM16).

Vous pouvez ensuite soit effacer l'indicateur d'événement en utilisant LL_TIM_ClearFlag_UPDATE(TIM16)avant d'activer l'interruption, soit utiliser LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER)avant de générer l'événement.

Fabiano
la source
1

J'ai eu un problème similaire dans le mod One Pulse et j'ai trouvé une solution pour la bibliothèque HAL. Lorsque j'ai contrôlé les drapeaux de la minuterie dans la fonction "TIM2_IRQHandler", j'ai vu que "capturer le drapeau de comparaison 1" était réglé. J'ai donc effacé "capture compare flag 1". Mais cette fois, j'ai vu que "capture compare flag 2" est réglé. J'ai donc effacé tous les indicateurs de comparaison (de 1 à 4) dans ma fonction "TIM2_IRQHandler" en utilisant les codes suivants.

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 */
}
Barış İşbiliroğlu
la source
0

Même problème avec TIM_TimeBaseInit () et STM32F0xx. La dernière chaîne de cette fonction:

  TIMx->EGR = TIM_PSCReloadMode_Immediate;

Il définit l'événement de mise à jour dans le registre de génération d'événements. C'est pourquoi j'ai mis un chèque au gestionnaire IRQ:

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
caponnière
la source