Skip to content

Bare metal C Ch09 TIM

Hongjayeong-02 edited this page Sep 21, 2026 · 2 revisions

Ch09. 범용 타이머 (TIM)

한 줄 요약: TIM2를 사용해 1 Hz Update Event를 만들고, UIF 플래그를 폴링해 LD1을 1초 주기로 토글한다.

1. 핵심 이론

SysTick과 TIM의 차이

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 polling

1 Hz 계산

Notion 정리에서는 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이 들어간다.

UIF는 직접 clear

TIM의 UIF는 한 번 set된 뒤 소프트웨어가 직접 clear해야 한다.

TIM2->SR &= ~SR_UIF;

이를 생략하면 첫 Update Event 이후 while (!(TIM2->SR & SR_UIF))가 계속 바로 통과한다.

2. 동작 흐름

RCC->APB1ENR
│
└─ TIM2 clock enable
│
▼
PSC = 1599
│
▼
ARR = 9999
│
▼
CEN = 1
│
▼
TIM2 counting
│
▼
Update Event 발생
│
▼
UIF = 1
│
▼
LED toggle
│
▼
UIF 직접 clear

3. 실제 프로젝트 구조


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를 전부 기록한다.

4. 전체 코드

Inc/gpio.h

#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 */

Src/gpio.c

#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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (LED_PIN * 2));
GPIOB-&gt;MODER |=  (0x1UL &lt;&lt; (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-&gt;MODER &amp;= ~(0x3UL &lt;&lt; (BTN_PIN * 2));  /* Input */
GPIOC-&gt;PUPDR &amp;= ~(0x3UL &lt;&lt; (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 */ }

Inc/tim.h

#ifndef TIM_H_
#define TIM_H_

#include "stm32f4xx.h"

#define SR_UIF (1U << 0)

void tim2_1hz_init(void);

#endif /* TIM_H_ */

Src/tim.c

#include "tim.h"

#define TIM2EN (1U << 0) #define CR1_CEN (1U << 0)

void tim2_1hz_init(void) { RCC->APB1ENR |= TIM2EN;

TIM2-&gt;PSC = 1600 - 1;   /* 16MHz -&gt; 10kHz */
TIM2-&gt;ARR = 10000 - 1;  /* 10kHz -&gt; 1초 */
TIM2-&gt;CNT = 0;
TIM2-&gt;CR1 = CR1_CEN;

}

Src/main.c

#include "gpio.h"
#include "tim.h"

int main(void) { led_init(); tim2_1hz_init();

while (1)
{
    led_toggle();

    while (!(TIM2-&gt;SR &amp; SR_UIF)) { }
    TIM2-&gt;SR &amp;= ~SR_UIF;
}

}

5. 검증 기록

Notion 기록 기준:

text = 764 bytes
data = 0 bytes
bss  = 2560 bytes
warning 없음

이 페이지의 Notion 기록에는 build 결과가 정리되어 있으며, 별도의 실제 보드 동작 결과 문구는 기록되어 있지 않다.

6. 핵심 정리

  • TIM 주기는 Timer Clock / ((PSC+1)*(ARR+1))로 계산한다.

  • TIM의 UIF는 software에서 직접 clear한다.

  • TIM은 SysTick과 달리 STM32 peripheral이며 여러 timer와 PWM/Input Capture 기능으로 확장된다.

Clone this wiki locally