STM32 : 타이머 인터럽트가 즉시 작동


10

이것은 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");
   }
  }
 }

그리고 timerReset()프로그램 중간에 기능을 실행 한 후 몇 초 후에 인터럽트가 시작되지만 거의 즉시 시작됩니다. 하드웨어 문제가 없는지 확인하기 위해 다른 타이머를 거의 시도하지 않았지만 그렇지 않습니다.


timerReset () 함수에서 타이머 인터럽트 플래그를 명시 적으로 지우는 것이 좋습니다.
brhans

1
DeInit과 Init 사이에 추가 한 후 __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_FLAG_UPDATE); 및 __HAL_TIM_CLEAR_FLAG (& RS485Timer, TIM_IT_UPDATE); 새로운 일이 일어나지 않습니다.
m0drzew

답변:


9

나는 STM32F105와 함께 이것에 부딪쳤다. STM32F1xx 표준 주변기기 라이브러리 기능은 사용중인 것과 약간 다르지만 아이디어는 동일해야합니다.

TIM_TimeBaseInit()함수를 발행하면 TIM_SR_UIF 플래그가 설정되었습니다. 이유를 알아 내기 위해 아직 돌아 가지 않았습니다. 이 비트가 설정되면 인터럽트가 활성화 되 자마자 트리거됩니다.

문제를 해결하기 위해을 호출 한 후 TIM_TimeBaseInit()즉시 전화했습니다 TIM_ClearITPendingBit(). 그런 다음로 인터럽트를 활성화합니다 TIM_ITConfig(). 문제가 해결되었습니다.

내 완전한 초기화 루틴은 다음과 같습니다.

// 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
HAL 라이브러리를 사용하는 STM32L151의 동일한 문제. 해결 방법 (예 : TIM6의 경우) :__HAL_TIM_CLEAR_FLAG(&htim6, TIM_SR_UIF);

3
새로운 HAL 드라이버에 대한 설명은 이유를 설명합니다. PSC 값이 실제로 업데이트 이벤트 후 SR-> PSC에만로드되기 때문에 PSC 값이 초기화시 업데이트되도록합니다.
Galaxy

@Galaxy, 정보 감사합니다.
bitsmack

1

비슷한 문제가 있는데 답을 찾지 못해 다른 사람들을 돕기 위해 내 경험을 나누고 있습니다.

타이머를 초기화하기 전에 URS (Update Request Source)를 설정하면 문제가 해결된다고 생각합니다.

필자의 경우 하위 계층 드라이버를 사용하고 있으므로 예제 코드는 다음과 같습니다.

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

문제는 시간 기반을 구성하기 위해 LL_TIM_SetPrescaler(TIM16, 7999)and LL_TIM_SetAutoReload(TIM16, 2999)함수를 사용 하고 있었고이 함수를 사용할 때 값이 업데이트되지 않았 음을 발견하여를 사용하여 값을 업데이트하는 이벤트를 생성해야한다는 것을 알았습니다 LL_TIM_GenerateEvent_UPDATE(TIM16).

그런 다음 LL_TIM_ClearFlag_UPDATE(TIM16)인터럽트를 활성화하기 전에를 사용하여 이벤트 플래그를 지우거나 이벤트 LL_TIM_SetUpdateSource(TIM16, LL_TIM_UPDATESOURCE_COUNTER)를 생성하기 전에 사용할 수 있습니다 .


1

One Pulse 모드에서 비슷한 문제가 있었고 HAL 라이브러리에 대한 솔루션을 찾았습니다. "TIM2_IRQHandler"기능에서 타이머 플래그를 제어 할 때 "캡처 비교 플래그 1"이 설정되었습니다. 그래서 "캡처 비교 플래그 1"을 클리어했습니다. 그러나 이번에는 "캡처 비교 플래그 2"가 설정되었습니다. 따라서 다음 코드를 사용하여 "TIM2_IRQHandler"함수에서 모든 비교 플래그 (1에서 4까지)를 지 웠습니다.

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

TIM_TimeBaseInit () 및 STM32F0xx와 동일한 문제입니다. 이 함수의 마지막 문자열 :

  TIMx->EGR = TIM_PSCReloadMode_Immediate;

이벤트 생성 레지스터에서 업데이트 이벤트를 설정합니다. 그래서 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.