메뉴얼에서는 못 찾았는데, 구글 검색해 보니 잘 나와 있네요.


이 내용의 원문은 다음과 같습니다.

아무리 메뉴얼을 뒤져봐도 못 찾았던 내용인데, 이 사람은 어디서 찾은 걸까요?
제가 꼭 알고 싶었던 내용입니다. 
타이머를 쓰긴 쓰는데, Clock 소스가 180 MHz 인지, 90MHz 인지, 45MHz 인지 통 모르겠드만...
그래서 오실로 스코프로 찍어보고 알아야만 했거든요. ㅜㅜ

맨 마지막에 APB 번호가 나와 있어서 CubeMX 툴의 Clock Configuration 과 비교해 보면 알 수 있습니다.




TIM2 는 이전에 해봐서 90MHz가 Clock Source 라는 것을 알았고, 만약 TIM1 으로 테스트 하면 Clock Source가 180MHz 겠군요.

클럭은 Cube Mx로 다음과 같이 설정하고,





소스 코드는 아래와 같이 TIM1 Update 인터럽트가 걸릴때 마다 PA5를 토글하도록 만들어 봤습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
 if (htim->Instance == TIM1)
 {
  GPIOA->ODR ^= GPIO_PIN_8;
 }
}
 
int main(void)
{
  HAL_Init();
 
  SystemClock_Config();
 
  MX_GPIO_Init();
  MX_TIM1_Init();
 
  HAL_TIM_Base_Start_IT(&htim1);
 
  while (1)
  {
  }
}
cs


그 결과 PA5 를 오실로 스코프로 찍어 보니, 위의 표와 계산한 값과 같이 10ms 마다 토글하도록 출력이 됩니다.




[이 프로젝트에 사용된 MCU는 NUCLEO-F446RE(STM32F446RET6) 입니다.]


제가 지금까지 타이머 인터럽트를 안다뤘더군요. 

가장 많이 쓰는 기능일텐데, 이제서야 여러 기능들을 합쳐서 프로그램을 짜 넣으려고 하다 보니 빠진 것을 알았습니다.

먼저 CubeMx 툴을 실행.
TIM2 의 Clock Source 를 Internal Clock으로 하여 기능을 살려 놓습니다. 
그리고 TIM2 Update 인터럽트가 제대로 걸리고 있는지 확인을 위해 포트를 토글하려고 PA5를 GPIOOUT으로 설정.



다음은 클럭 설정으로 가서 STM32F446의 시스템 클럭을 180MHz로 가장 높게 맞췄습니다.
참고로 메뉴얼을 봐도 TIM2 의 클럭 소스가 어떤 것인지 몰라서 직접 실험으로 알아본 결과 APB1 Timer Clock(90MHz) 네요.
누가 혹시 이 내용에 대해 자세히 나온 글이 있는지 아시면 알려 주시면 감사하겠습니다. (전 도저히 못 찾겠네요)



configuration 탭으로 가서 TIM2 의 세부 설정을 위해 TIM2를 클릭.



10ms 마다 TIM2 Update 인터럽트가 걸리게 하기 위해, Parameter 설정 탭으로 가서 Period 를 900,000 으로 설정했습니다.
공식은 period count = 0.01(sec) x 90Mhz = 900,000 입니다.



인터럽트를 쓸 것이기 때문에 NVIC Setting으로 가서 인터럽트를 인에이블 체크를 합니다.



메뉴 중, project->Generate Code 를 눌러 컴파일러에 맞게 코드를 생성합니다.



1. HAL_TIM_Base_Start_IT 함수로 타이머 업데이트 인터럽트가 걸리도록 합니다.
2. stm32f4xx_hal_tim.c 의 __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) 함수에서 
--weak 를 제거하고 main.c 에 옮겨서 TIM2 update 인터럽트가 걸릴때 실행될 코드를 추가하거나 수정합니다.
TIM2 update 인터럽트가 걸릴때 HAL_TIM_PeriodElapsedCallback 함수를 호출하도록 되어 있지요.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
  * @brief  Period elapsed callback in non blocking mode 
  * @param  htim: pointer to a TIM_HandleTypeDef structure that contains
  *                the configuration information for TIM module.
  * @retval None
  */
__weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
  UNUSED(htim);
  /* NOTE : This function Should not be modified, when the callback is needed,
            the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
   */
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* Prevent unused argument(s) compilation warning */
    if (htim->Instance == TIM2)
    {
        HAL_GPIO_TogglePin(LED_OUT_GPIO_Port,LED_OUT_Pin);
    }
    else if (htim->Instance == TIM1)
    {
    }
  /* NOTE : This function Should not be modified, when the callback is needed,
            the __HAL_TIM_PeriodElapsedCallback could be implemented in the user file
   */
}
 
 
int main(void)
{
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM1_Init();
  MX_USART2_UART_Init();
 
  /* USER CODE BEGIN 2 */
  printf("UART Test...\n\r");
    
  HAL_Delay(500);
  HAL_TIM_Base_Start_IT(&htim2);
    
  while (1)
  {
            HAL_GPIO_TogglePin(LED_OUT_GPIO_Port,LED_OUT_Pin);
  }
 
}
cs


그런데 주의할 점은 어떤 Timer 인터럽트가 실행되도 호출되는 callback 함수는 HAL_TIM_PeriodElapsedCallback 입니다.
따라서, HAL_TIM_PeriodElapsedCallback 함수 내에서 어떤 타이머에서 날 불렀는지 확인할 필요가 있습니다.

그래서 다음과 같이 확인하는 코드가 필요합니다.





즉 날 호출한 게, TIM1 이냐? TIM2 냐? 이런 뜻이죠. 
저는 TIM2에 의해 호출되도록 만들었기 때문에, TIM2에 의해 호출되면 A5 핀을 토글하도록 해서 결과는 다음과 같습니다.





정확히 10ms 마다 포트가 토글 되네요.
동작 잘 되네요~~^^

다음의 소스 코드를 첨부합니다.


+ Recent posts