STM32: l'interruzione del timer funziona immediatamente


10

Questo è il codice per il timer nel mio progetto su 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");
   }
  }
 }

E dopo aver eseguito la timerReset()funzione nel mezzo del mio programma, l'interrupt inizia non pochi secondi dopo, ma quasi immediatamente. Ho provato alcuni altri timer per verificare se non ci sono problemi hardware, ma no, non lo è.


Ti suggerirei di cancellare esplicitamente il flag di interruzione del timer nella funzione timerReset ().
brhans,

1
Dopo aver aggiunto tra DeInit e Init __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_FLAG_UPDATE); e __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_IT_UPDATE); non sta succedendo nulla di nuovo.
m0drzew,

Risposte:


9

Mi sono imbattuto in questo con un STM32F105. Le funzioni della Libreria periferica standard STM32F1xx sono leggermente diverse da quelle in uso, ma l'idea dovrebbe essere la stessa.

L'emissione della TIM_TimeBaseInit()funzione ha comportato l'impostazione del flag TIM_SR_UIF. Non sono ancora tornato per capire perché. Una volta impostato questo bit, l'interrupt si attiverà non appena sarà abilitato.

Per risolvere il problema, dopo aver chiamato TIM_TimeBaseInit(), ho subito chiamato TIM_ClearITPendingBit(). Quindi abiliterei l'interruzione con TIM_ITConfig(). Ciò ha risolto il problema.

La mia routine di inizializzazione completa è simile alla seguente:

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

2
Stesso problema su STM32L151 utilizzando le librerie HAL. Soluzione alternativa (ad es. Per TIM6):__HAL_TIM_CLEAR_FLAG(&htim6, TIM_SR_UIF);

3
Un commento nel nuovo driver HAL spiega perché: lo fanno per forzare l'aggiornamento del valore PSC al momento dell'inizializzazione poiché viene effettivamente caricato nell'SR-> PSC solo dopo un evento di aggiornamento.
Galaxy

Bello, @Galaxy, grazie per le informazioni.
bitsmack

1

Dato che avevo un problema simile e non avevo trovato risposte, condivido la mia esperienza nella speranza di aiutare altre persone.

Credo che nel tuo caso, anche l'impostazione di URS (Origine richiesta aggiornamento) prima di inizializzare il timer risolva il problema.

Nel mio caso, sto usando i driver di livello basso, quindi un codice di esempio sarebbe:

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

Il problema è che stavo usando LL_TIM_SetPrescaler(TIM16, 7999)eLL_TIM_SetAutoReload(TIM16, 2999) funzioni per configurare la base dei tempi e ho scoperto che quando si utilizzavano queste funzioni, i valori non venivano aggiornati, quindi dovevo generare un evento per aggiornare i valori usando LL_TIM_GenerateEvent_UPDATE(TIM16).

È quindi possibile cancellare il flag di evento utilizzando LL_TIM_ClearFlag_UPDATE(TIM16)prima di abilitare l'interrupt o utilizzare LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER)prima di generare l'evento.


1

Ho avuto un problema simile nella mod One Pulse e ho trovato la soluzione per la libreria HAL. Quando ho controllato i flag del timer nella funzione "TIM2_IRQHandler", ho visto che è stato impostato il "flag di confronto acquisizione 1". Così ho cancellato "cattura confronta bandiera 1". Ma questa volta ho visto "cattura confronto bandiera 2" è impostato. Così ho cancellato tutti i flag di confronto (da 1 a 4) nella mia funzione "TIM2_IRQHandler" usando i codici seguenti.

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 */
}

0

Stesso problema con TIM_TimeBaseInit () e STM32F0xx. L'ultima stringa di questa funzione:

  TIMx->EGR = TIM_PSCReloadMode_Immediate;

Imposta l'evento di aggiornamento nel registro di generazione eventi. Ecco perché metto il controllo al gestore 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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.