Repository navigation
Bare metal C Ch09 TIM
한 줄 요약: TIM2를 사용해 1 Hz Update Event를 만들고, UIF 플래그를 폴링해 LD1을 1초 주기로 토글한다.
Ch08의 SysTick은 Cortex-M 코어에 포함된 공통 타이머이고, TIM은 STM32가 제공하는 벤더 주변장치다. STM32F439에는 여러 개의 TIM이 존재하며, 일반적인 delay뿐 아니라 PWM, Input Capture, Output Compare, Encoder 등의 기능으로 확장할 수 있다.
항목 | SysTick | TIM2 -- | -- | -- 소속 | Cortex-M 코어 | STM32 peripheral 개수 | 1개 | 여러 TIM 사용 가능 카운터 | 24-bit down counter | TIM2는 32-bit 상태 플래그 | COUNTFLAG | UIF 이번 실습 | SysTick polling | TIM2 Update Event pollingNotion 정리에서는 APB1 timer clock을 16 MHz로 두고 다음 값을 사용했다.
UEV frequency
= Timer Clock / ((PSC + 1) × (ARR + 1))
PSC = 1599
ARR = 9999
16,000,000 / (1600 × 10000)
= 1 Hz
PSC와 ARR 모두 0부터 세므로 계산에는 +1이 들어간다.
TIM의 UIF는 한 번 set된 뒤 소프트웨어가 직접 clear해야 한다.
TIM2->SR &= ~SR_UIF;
이를 생략하면 첫 Update Event 이후 while (!(TIM2->SR & SR_UIF))가 계속 바로 통과한다.
RCC->APB1ENR
│
└─ TIM2 clock enable
│
▼
PSC = 1599
│
▼
ARR = 9999
│
▼
CEN = 1
│
▼
TIM2 counting
│
▼
Update Event 발생
│
▼
UIF = 1
│
▼
LED toggle
│
▼
UIF 직접 clear
Ch09_tim/
├── Inc/gpio.h
├── Src/gpio.c
├── Inc/tim.h
├── Src/tim.c
├── Src/main.c
syscalls.c,sysmem.c, startup file, linker script, CubeIDE metadata/build output은 Ch04에서 다룬 공통 기반이므로 이 페이지에서는 반복하지 않는다. 아래에는 이 chapter 기능 구현에 직접 사용한 source/header를 전부 기록한다.
#ifndef GPIO_H
#define GPIO_H
#include <stdbool.h>
/* ---- LED (PB0, LD1 녹색) ---- */
void led_init(void);
void led_on(void);
void led_off(void);
/* ---- Push Button (PC13, B1) ---- */
void button_init(void);
bool get_btn_state(void);
void led_toggle(void); /* Ch08에서 추가 */
#endif /* GPIO_H */
#include "stm32f4xx.h"
#include "gpio.h"
#define LED_PIN 0U /* PB0 = LD1 (녹색) /
#define BTN_PIN 13U / PC13 = B1 */
void led_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER &= ~(0x3UL << (LED_PIN * 2));
GPIOB->MODER |= (0x1UL << (LED_PIN * 2));
}
void led_on(void)
{
GPIOB->BSRR = (1UL << LED_PIN); /* Set */
}
void led_off(void)
{
GPIOB->BSRR = (1UL << (LED_PIN + 16)); /* Reset */
}
void button_init(void)
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
GPIOC->MODER &= ~(0x3UL << (BTN_PIN * 2)); /* Input */
GPIOC->PUPDR &= ~(0x3UL << (BTN_PIN * 2)); /* No pull (보드가 자체 처리) */
}
bool get_btn_state(void)
{
return (GPIOC->IDR & (1UL << BTN_PIN)) != 0U; /* active-HIGH */
}
void led_toggle(void)
{
GPIOB->ODR ^= (1UL << 0); /* PB0 = LD1 */
}
#ifndef TIM_H_
#define TIM_H_
#include "stm32f4xx.h"
#define SR_UIF (1U << 0)
void tim2_1hz_init(void);
#endif /* TIM_H_ */
#include "tim.h"
#define TIM2EN (1U << 0)
#define CR1_CEN (1U << 0)
void tim2_1hz_init(void)
{
RCC->APB1ENR |= TIM2EN;
TIM2->PSC = 1600 - 1; /* 16MHz -> 10kHz */
TIM2->ARR = 10000 - 1; /* 10kHz -> 1초 */
TIM2->CNT = 0;
TIM2->CR1 = CR1_CEN;
}
#include "gpio.h"
#include "tim.h"
int main(void)
{
led_init();
tim2_1hz_init();
while (1)
{
led_toggle();
while (!(TIM2->SR & SR_UIF)) { }
TIM2->SR &= ~SR_UIF;
}
}
Notion 기록 기준:
text = 764 bytes
data = 0 bytes
bss = 2560 bytes
warning 없음
이 페이지의 Notion 기록에는 build 결과가 정리되어 있으며, 별도의 실제 보드 동작 결과 문구는 기록되어 있지 않다.
TIM 주기는
Timer Clock / ((PSC+1)*(ARR+1))로 계산한다.TIM의
UIF는 software에서 직접 clear한다.TIM은 SysTick과 달리 STM32 peripheral이며 여러 timer와 PWM/Input Capture 기능으로 확장된다.