Embedded/1. STM32, Arduino

STM32 - Clock, Timer 구현 (SysTick, Timer 사용)

잇(IT) 2024. 6. 11. 21:51

https://insoobaik.tistory.com/631

 

STM32 - TIM 이론

보호되어 있는 글입니다. 내용을 보시려면 비밀번호를 입력하세요.

insoobaik.tistory.com

TIM 이론에 이어 실제로 TIM을 Necleo board에 구현해 볼 것이다.


LSE, LSI, HSI, HSE 총 4개가 있는데 일반적으로 External 즉, 크리스탈을 이용하여 생성된 클럭이 안전하다.

RTC의 경우에도 LSE를 사용한다.

STM32F429의 경우 HSE는 ST-Link 파트에 붙어있는 MCO로부터 클럭을 받아 사용하게 된다.

 

Clock Configuration을 통해 설정이 가능하며, DataSheet를 통해 각 타이머가 사용하는 APB도 알 수 있다.

각 타이머는 위 DataSheet와 같이 동작하게 된다. 자세한 내용은 추후에 알아보도록 하겠다.

Clock Configuration을 보게 되면 이전에 설명했던 것과 같이 RTC를 활성화 하게 되면 LSI와 LSE를 사용할 수 있게 된다.

그 중 안전한 LSE를 선택하고, 그 외 Timer의 경우 APB1, 2를 사용하게 되는데 이 또한 HSI와 HSE를 사용할 수 있는데 ST_Link에서 전달하는 클럭인 HSE를 사용할 것이다. 


RCC의 HSE는 CPU 내부 클럭을 사용하며, LSE는 크리스털을 통해 발생시키는 클럭에 해당한다.
 


SysTick_Handler를 보게 되면 HAL_IncTick() 함수를 볼 수 있다.
HAL_IncTick() 함수는 시스템 시간을 증가시키는 데 사용된다. 이 함수는 SysTick 인터럽트 핸들러에서 호출되어 SysTick 타이머에 의해 주기적으로 실행된다.
인터럽트가 발생할 때마다 HAL_IncTick() 함수가 호출된다.

 

HAL_IncTick();
HAL_GetTick();
__weak처리가 되어 있으므로 사용자가 재정의하여 사용할 수 있다.
HAL_IncTick 함수의 uwTick이 SysTick 타이머 클락 소스로 1ms마다 카운트되고 HAL_Delay() 함수도 uwTick을 사용하고 있다.
 
SysTick_Handler의 HAL_SYSTICK_IRQHandler(); 함수가 Drivers의 cortex.c 파일에 아래와 같이 정의되어 있는 것을 확인할 수 있다.

 
즉, 위에서 본 SysTick_Handler()는 1ms 마다 한 번씩 호출되어 HAL_IncTick(); HAL_SYSTICK_IRQHandler(); 함수를 계속해서 호출하는 것이다.
 

HAL_IncTick 함수를 이용하여 LD2_Pin을 1초에 한 번씩 Toggle 시키는 코드를 작성하게 되면 아래 영상과 같이 1초에 한 번씩 LED가 Toggle 되는 것을 확인할 수 있다.

마찬가지로 HAL_SYSTICK_Callback() 함수를 이용하여 LD1_Pin을 1초에 한 번씩 Toggle 시키고 1초에 한 번씩 숫자를 count 하여 uart를 통해 console 창에 해당 값이 1초마다 뜨는 것을 확인할 수 있다.

 

ex) HAL_Delay(100)은 SysTick 인터럽트가 100번 발생할 동안 기다리라는 의미다. 그래서 SysTick 자체는 논블로킹으로 동작하지만 HAL_Delay(100)는 인터럽트 100번 발생할 동안 대기하기 때문에 블로킹으로 동작하게 된다.


Timer

이전 글에서 위 TIM 자료를 정리해 보았다.

 

TIM2를 기준으로 Timer에 대한 구현을 해볼 것이다.

 

TIM2는 위 표 기준으로 APB1을 사용하고, Clock Configuration을 보게되면 HSE에 의해 생성된 APB1 Timer clocks은 84MHz인 것을 확인할 수 있다.

 

즉 1초에 84000000 주기를 갖기 때문에 Prescaler = 8400으로 설정할 경우 10,000Hz 주기로 변하게 된다.

 

이렇게 되면 ARR 1 Count되는데 걸리는 시간은 0.01ms가 된다. ARR을 10,000으로 설정하게 되면 ARR이 10,000을 Count하는 시간 즉 1초에 한 번 이벤트 혹은 인터럽트를 발생시키게 된다.

위에 설명한 내용들을 CubeIde를 통해 설정할 수 있다.

위 설정으로 인해 TIM2는 1초에 한번씩 이벤트 혹으 인터럽트를 발생시킨다.

인터럽트를 사용하기 위한 설정을 완료해준다.

코드를 생성하게 되면 GUI로 설정한 값들이 Init() 함수를 통해 초기화 되는 것을 확인할 수 있다.

마찬가지로 인터럽트를 위한 IRQHandler 함수도 생성된 것을 확인할 수 있다.

위 인터럽트 핸들러는 일반적으로 타이머의 주기가 종료되었을 때 해당 타이머의 업데이트 인터럽트가 발생했을 때 해당 콜백 함수를 호출하기 위한 내용이다.

즉, 타이머의 주기가 끝나 인터럽트가 발생하게 되면 위 Callback 함수가 호출되는 것을 알 수 있다.

 

Timer 인터럽트를 사용하기 위해서 Timer 인터럽트 함수를 작성해준다.

위에서 설정한 TIM2의 속성 값에 따라 인터럽트가 발생하고 해당 인터럽트는 1초마다 발생하여 위 코드에 의해 1초에 한번씩 LED1, LED3을 Toggle 시키는 것을 확인할 수 있다.

 


다수 Timer 사용

위 사진들과 같이 TIM2, 3, 4의 속도를 각각 0.1, 0.5, 1초로 만들어서 LED 불빛을 각각 밝히도록 할 것이다.

TIM2, 3, 4 전부 APB1을 사용하기 때문에 84MHz를 PSC와 ARR를 통해 주기를 조절 할 수 있다.

HAL_TIM_PeriodElapsedCallback을 통해 인터럽트 발생 시 Callback 함수를 호출할 것이기 때문에 Base_Start_IT 함수를 TIM2, 3, 4를 실행시켜준다.

htim->Instance를 통해 각 TIM에 대한 인터럽트를 확인하고, 해당 TIMx의 인터럽트가 발생하면 해당 LED 불빛을 Toggle 시킨다.

 

 

728x90