STM32: A interrupção do temporizador funciona imediatamente


10

Este é o código para o timer no meu projeto no 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 depois de executar a timerReset()função no meio do meu programa, a interrupção começa não apenas alguns segundos depois, mas quase imediatamente. Tentei alguns outros temporizadores para verificar se não há nenhum problema de hardware, mas não, não é.


Eu sugiro que você limpe explicitamente o sinalizador de interrupção do timer na sua função timerReset ().
brhans

11
Após adicionar entre DeInit e Init __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_FLAG_UPDATE); e __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_IT_UPDATE); nada de novo está acontecendo.
m0drzew

Respostas:


9

Eu me deparei com isso com um STM32F105. As funções da Biblioteca de periféricos padrão STM32F1xx são um pouco diferentes das que você está usando, mas a ideia deve ser a mesma.

A emissão da TIM_TimeBaseInit()função fez com que o sinalizador TIM_SR_UIF fosse definido. Ainda não voltei para descobrir o porquê. Depois que esse bit é definido, a interrupção será acionada assim que for ativada.

Para consertar, depois de ligar TIM_TimeBaseInit(), liguei imediatamente TIM_ClearITPendingBit(). Então eu habilitaria a interrupção com TIM_ITConfig(). Isso resolveu o problema.

Minha rotina completa de inicialização é assim:

// 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
Mesmo problema no STM32L151 usando as bibliotecas HAL. Solução alternativa (por exemplo, para TIM6):__HAL_TIM_CLEAR_FLAG(&htim6, TIM_SR_UIF);

3
Um comentário no novo driver HAL explica o motivo: eles fazem isso para forçar o valor do PSC a ser atualizado na inicialização, pois ele é realmente carregado apenas no SR-> PSC após um evento de atualização.
Galaxy

Legal, @Galaxy, obrigado pela informação.
bitsmack

1

Como tive um problema semelhante e não encontrei respostas, estou compartilhando minha experiência na esperança de ajudar outras pessoas.

Acredito que, no seu caso, definir o URS (Update Request Source) antes de inicializar o timer também resolve o problema.

No meu caso, estou usando os drivers de camada baixa, portanto, um código de exemplo seria:

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

O problema é que eu estava usando as funções LL_TIM_SetPrescaler(TIM16, 7999)e LL_TIM_SetAutoReload(TIM16, 2999)para configurar a base de tempo e descobri que, ao usar essas funções, os valores não estavam sendo atualizados, então tive que gerar um evento para atualizar os valores usando LL_TIM_GenerateEvent_UPDATE(TIM16).

Você pode limpar o sinalizador de evento usando LL_TIM_ClearFlag_UPDATE(TIM16)antes de ativar a interrupção ou usar LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER)antes de gerar o evento.


1

Eu tive um problema semelhante no mod One Pulse e encontrei a solução para a biblioteca HAL. Quando eu controlei sinalizadores de timer na função "TIM2_IRQHandler", vi "captura comparar sinalizador 1" está definido. Então eu limpei "capture compare flag 1". Mas desta vez vi "captura comparar bandeira 2" está definido. Portanto, limpei todos os sinalizadores de comparação (de 1 a 4) na minha função "TIM2_IRQHandler" usando os códigos a seguir.

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

Mesmo problema com TIM_TimeBaseInit () e STM32F0xx. A última string desta função:

  TIMx->EGR = TIM_PSCReloadMode_Immediate;

Ele define o evento de atualização no Event Generation Register. É por isso que coloquei o cheque no manipulador de 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.