STM32: Przerwanie timera działa natychmiast

10

To jest kod timera w moim projekcie na 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");
   }
  }
 }

I po uruchomieniu timerReset()funkcji w środku mojego programu, przerwanie zaczyna się nie kilka sekund później, ale prawie natychmiast. Próbowałem kilka innych timerów, aby sprawdzić, czy nie ma problemu ze sprzętem, ale nie, nie jest.

m0drzew
źródło
Sugeruję wyraźne wyczyszczenie flagi przerwania timera w funkcji timerReset ().
brhans
1
Po dodaniu między DeInit a Init __HAL_TIM_CLEAR_FLAG (i RS485Timer, TIM_FLAG_UPDATE); i __HAL_TIM_CLEAR_FLAG (i RS485Timer, TIM_IT_UPDATE); nic nowego się nie dzieje.
m0drzew

Odpowiedzi:

9

Wpadłem na to z STM32F105. Standardowe funkcje biblioteki peryferyjnej STM32F1xx różnią się nieco od używanych, ale pomysł powinien być taki sam.

TIM_TimeBaseInit()Uruchomienie tej funkcji spowodowało ustawienie flagi TIM_SR_UIF. Jeszcze nie wróciłem, żeby dowiedzieć się, dlaczego. Po ustawieniu tego bitu przerwanie zostanie uruchomione, gdy tylko zostanie włączone.

Aby to naprawić, po zadzwonieniu TIM_TimeBaseInit()natychmiast zadzwoniłem TIM_ClearITPendingBit(). Potem pozwoliłbym przerwać za pomocą TIM_ITConfig(). To rozwiązało problem.

Moja pełna procedura inicjalizacji wygląda następująco:

// 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
źródło
2
Ten sam problem na STM32L151 przy użyciu bibliotek HAL. Obejście (np. Dla TIM6):__HAL_TIM_CLEAR_FLAG(&htim6, TIM_SR_UIF);
3
Komentarz w nowym sterowniku HAL wyjaśnia, dlaczego: robią to, aby wymusić aktualizację wartości PSC podczas inicjalizacji, ponieważ jest ona faktycznie ładowana do SR-> PSC po zdarzeniu aktualizacji.
Galaxy
Fajnie, @Galaxy, dzięki za informację.
bitsmack
1

Ponieważ miałem podobny problem i nie znalazłem odpowiedzi, dzielę się swoim doświadczeniem w nadziei na pomoc innym ludziom.

Uważam, że w twoim przypadku ustawienie URS (Źródło żądania aktualizacji) przed zainicjowaniem timera również rozwiązuje problem.

W moim przypadku używam sterowników warstwy niższej, więc przykładowy kod to:

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

Problem polega na tym, że użyłem funkcji LL_TIM_SetPrescaler(TIM16, 7999)i LL_TIM_SetAutoReload(TIM16, 2999)do skonfigurowania podstawy czasu i odkryłem, że podczas korzystania z tych funkcji wartości nie były aktualizowane, więc musiałem wygenerować zdarzenie, aby zaktualizować wartości za pomocąLL_TIM_GenerateEvent_UPDATE(TIM16) .

Następnie możesz wyczyścić flagę zdarzenia za pomocą LL_TIM_ClearFlag_UPDATE(TIM16)przed włączeniem przerwania lub użyć LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER)przed wygenerowaniem zdarzenia.

Fabiano
źródło
1

Miałem podobny problem w modzie One Pulse i znalazłem rozwiązanie dla biblioteki HAL. Kiedy kontrolowałem flagi timera w funkcji „TIM2_IRQHandler”, zobaczyłem, że „przechwytywanie flagi porównania 1” jest ustawione. Więc wyczyściłem „przechwyć porównaj flagę 1”. Ale tym razem widziałem, że ustawiona jest opcja „przechwyć flagę porównania 2”. Więc wyczyściłem wszystkie flagi porównania (od 1 do 4) w mojej funkcji „TIM2_IRQHandler” za pomocą następujących kodów.

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
źródło
0

Ten sam problem z TIM_TimeBaseInit () i STM32F0xx. Ostatni ciąg tej funkcji:

  TIMx->EGR = TIM_PSCReloadMode_Immediate;

Ustawia aktualizację zdarzenia w rejestrze generowania zdarzeń. Dlatego sprawdzam moduł obsługi 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
kaponier
źródło