Timer 6의 구조와 활용
- polling 하며 일정 주기마다 uart 메시지 출력,
- 익셉션핸들러(인터럽트) 이용으로 uart 메시지 출력을 해본다.
다음글 - GP(General Purpose)Timer인 Timer 9의 구조와 활용


STM32F4XX reference manual에 TIM6에 대해 나와있다.
- 16비트 업카운터로, 0부터 설정값까지 카운트한다.
- 동작 흐름 요약
- RCC로부터 APB1버스를 통해 TIM6에 클럭이 공급
- PSC(분주기) 작동
- TIM6_PSC의 값만큼 클럭을 나눔
- CNT(카운터) 증가
- PSC에서 분주된 클럭(CK_CNT)에 따라 CNT 값이 0부터 증가
- ARR 도달 시 업데이트 이벤트(U event) 발생
- CNT == ARR 일때 발생
- 인터럽트, TRGO 트리거 출력, CNT 초기화 가능
STM32F4xx 매뉴얼에 보면 Tim6엔 다양한 설정에 따른 클럭 다이어그램이 있다.
간단한 Counting Mode를 보면
internal clock을 2로 나눈 상황

- CNT_EN : Counter 활성화
- CK_CNT : CNT_EN 활성화 다음 클럭부터 Clock counter 동작
internal clock을 2로 나눈 주기로 실행하기 때문에, CK_INT(내부 클럭)가 2번 발생 시 CK_CNT가 1번 동작 - Counter overflow : Counter register 값이 설정한 주기(ARR) 값을 넘으면 오버플로우 발생
- Update event(UE) : 오버플로우 발생함에 따라 Update Event 발생
- Update interrupt flag(UIF) : Update event가 발생함에 따라 Update interrupt flag 활성화(flag가 다시 0으로 되도록 clear 동작이 필요)
기본 동작 순서를 잘 읽어보면, 클럭 다이어그램을 이해할 수 있다.
다음은 prescaler를 사용할때의 다이어그램이다. 보통 시스템 클럭값으로부터 타이머 카운트값이나, Baud rate로 사용할때 원하는 값으로 줄여주기 위해, 스케일링해주는 prescaler이다.
타이머의 입력 클럭이 너무 빠르면, 카운터가 너무 빨리 증가해서 원하는 시간 제어(예: 1초 간격 인터럽트)가 어렵다.
그래서 Prescaler(전치분주기) 를 사용해 타이머 입력 클럭을 나누어 느리게 만들어 준다.
예로는 168000000(168MHz)의 클럭값이 있을때, 오버플로우를 방지하기도하고, 간단한 수로 만들고 사용하고자할때 500000으로 스케일링 해놓고 사용한다.
- APB1 Timer Clock: 168 MHz
- Prescaler (PSC): 335
- ARR (Auto-Reload Register): 999
동작 계산
- Prescaler 설정 (PSC = 335)
→ 타이머 입력 클럭 = 168 MHz / (PSC + 1) = 168,000,000 / 336 = 500,000 Hz - ARR 설정 (ARR = 999)
→ 카운터가 0 ~ 999까지 세고 오버플로우 발생 (1000번 count) - 오버플로우 주기
→ 오버플로우 시간 = (ARR + 1) / 타이머 클럭
→ 1000 / 500,000 = 0.002초 (2ms)
=>2ms마다 타이머 인터럽트가 발생.
prescaler 값이 1 → 2 가 되는 상황

- CNT_EN : count를 활성화하여 다음 클럭부터 clock count 동작
- prescaler = 1 이므로 Prescaler buffer는 0, Prescaler counter는 0으로 유지
- TIMx_PSC 레지스터를 통해 새로운 prescaler 값을 설정
- 다음 update event에서 prescaler buffer= 1 이 되며, Prescaler counter는 2단위(0, 1)로 동작
- Prescaler counter에 맞춰 PSC counter가 0일 때 clock count 동작
4.2.2. 관련 레지스터 분석 및 설정 값 이해
- register boundary address

- RCC_APB1ENR
-


- TIMx_CR1
- Basic Timer의 동작을 설정하는 레지스터



- Basic Timer의 동작을 설정하는 레지스터
- TIMx_CR2
Trigger 트리거 관련 레지스터 -

- TIMx_DIER
-인터럽트 활성화 레지스터 -

- UIE (0번 비트)
- 0 : 업데이트 인터럽트 비활성화
- 1 : 업데이트 인터럽트 활성화
- UDE (8번 비트)
- 0 : 업데이트 DMA 요청 비활성화
- 1 : 업데이트 DMA 요청 활성화
- TIMx_SR
-status 레지스터(인터럽트 flag 확인)bit 0 : UIF : 업데이트 인터럽트 플래그 (업데이트 이벤트 발생 시 하드웨어에 의해 flag 1로 설정됨 → clear (0으로) 해주어야 한다. 

- TIMx_CNT (counter)
-현재 카운터 값 저장 
- TIMx_PSC (prescaler)
-

Bits 15:0 PSC : 타이머의 주기 결정
타이머의 입력 클럭을 나누는 역할 (타이머 클럭 분주)
실제 분주 값 = PSC + 1 (0을 포함해서 카운트하기때문)

- STM32에서 TIM6의 기본 클럭은 84MHz (1초당 84M번의 tick)
// 예시 TIM6->PSC = 8400-1; // 84,000,000Hz / (8400-1)+1 = 10kHz로 분주
- TIMx_ARR (auto-reload register)
- reload value 설정 레지스터

- 0xFFFF 초과하면 오버플로우
- 카운터는 0부터 ARR까지 카운팅, 다시 0으로 리셋
// 예시
TIM6->ARR = 5000-1; // 4999 = 500ms
- 타이머 설정 방법(500ms 주기마다 출력)
- The counter clock frequency CK_CNT is equal to fCK_PSC / (PSC[15:0] + 1).(p.709)
Prescaler = 8399
ARR = 4999
⇒ 84,000,000 / (8399 + 1) = 10,000 Hz
⇒ 타이머가 0~4999까지 센 후 오버플로우 → 5000 / 10000 = 0.5초 (500ms)
코드 구현-1 Polling으로 500mS 마다 Uart로 ‘.’ 하나씩 출력
void uart3_init(void){
//1.clock 활성화
RCC->AHB1ENR |= 1<<3;//GPIOD
RCC->APB1ENR |= 1<<18;//USART3
//2.PD8,9핀 Alternative Function으로 설정
GPIOD->MODER &= ~((0x3<< (2*8))| (0x3<<(2*9)));
GPIOD->MODER |=((0x2<<(2*8)) | (0x2<<(2*9)));
//3.MUX AFR uart tx,rx핀으로 설정.
GPIOD->AFR[1]&= ~(0xf<<4 | 0xf<<0);//MUX PD8,9(AFRH 8~15)
GPIOD->AFR[1] |= (0x7<<4 | 0x7<<0);//uart3(AF7)
//4.uart 레지스터 설정
//oversampling by 16(bit 15),UE,wordlength8bit+stop1bit(bit12),parityX(bit10),TE,RE
USART3->CR1 =(0<<15 |1<<13 | 0<<12 |0<<10 | 1<<3 | 1<<2);
USART3->BRR=(22 << 4) | 13;//115200bps,42MHZ =356
}
void uart3_send(char c){
while(!(USART3->SR>>7 &0x1));
USART3->DR=c;
}
void uart3_printf(const char* str){
while(*str){
uart3_send(*str++);
}
}
int main(void)
{
HAL_Init();
uart3_init();
SystemClock_Config();
//TIM6 clock 활성화
RCC->APB1ENR |= 1<<4;
//APB1 : 84MHz
int msec=500,pclk=84000000;
//(7:ARR preload enable,2:update request sources, 1: update enable, 0 : counter reset)
TIM6->CR1=(0x1<<7 | 0x1<<2 | 0x0<<1 | 0x0<<0);
//clk=84000000, PSC(8400-1)+1, CK_CNT=10000, 목표값 : 500ms, 주기 2
TIM6->PSC=8400-1;//prescaler 84000000->10kHz=10000
TIM6->ARR=5000-1;//5000=2Hz (int)(pclk/8400)/2)-1 reload
//TIM6->ARR=10*msec-1; // msec으로 표현
TIM6->CNT=0;//0부터count시작
//count start
TIM6->CR1 |= 0x1<<0;
char msg[100];
while (1)
{
if(TIM6->SR & 0x1){//(UIF)Update interrupt flag
uart3_printf(".");
TIM6->SR =0x0;
}
/*
sprintf(msg,"%d ",TIM6->CNT);//count출력
uart3_printf(msg);
*/
}
}

코드 구현-2 Exception(Interrupt) 활용하여 500mS 마다 Uart로 ‘#’ 하나씩 출력
startup 벡터 테이블에 등록되어 있는 TIM6_DAC_IRQHandler 이름을 사용해야 함.

void uart3_init(void){
RCC->AHB1ENR |= 1<<3;//GPIOD
RCC->APB1ENR |= 1<<18;//USART3
//PD8,9 AF모드
GPIOD->MODER &= ~((0x3<< (2*8))| (0x3<<(2*9)));
GPIOD->MODER |=((0x2<<(2*8)) | (0x2<<(2*9)));
GPIOD->AFR[1]&= ~(0xf<<4 | 0xf<<0);//MUX PD8,9(AFRH 8~15)
GPIOD->AFR[1] |= (0x7<<4 | 0x7<<0);//uart3
USART3->CR1 =(0<<15 |1<<13 | 0<<12 |0<<10 | 1<<3 | 1<<2);
USART3->BRR=(22 << 4) | 13;//115200bps,42MHZ =356
}
void uart3_send(char c){
while(!(USART3->SR>>7 &0x1));
USART3->DR=c;
}
void uart3_printf(const char* str){
while(*str){
uart3_send(*str++);
}
}
char msg[100];
void TIM6_DAC_IRQHandler(void)
{
if (TIM6->SR & (1 << 0)) {
uart3_printf("#");
TIM6->SR = ~(1 << 0); // UIF 비트 리셋
}
}
int main(void)
{
HAL_Init();
uart3_init();
SystemClock_Config();
RCC->APB1ENR |= 1<<4; //TIM6 clock
int msec=300,pclk=84000000; //APB1 : 84MHz
//(7:ARR preload enable,2:update request sources, 1: update enable, 0 : counter reset)
TIM6->CR1=(0x1<<7 | 0x1<<2 | 0x0<<1 | 0x0<<0);
//clk=84000000, PSC(8400-1)+1, CK_CNT=10000, 목표값 : 500ms, 주기 2
TIM6->PSC=8400-1;//prescaler 84000000->10kHz=10000
TIM6->ARR=5000-1;//5000=2Hz
TIM6->CNT=0;//start value
TIM6->DIER=0x1<<0;//Interrupt enable
//NVIC에 TIM6_DAC_IRQ 번호 등록하기
NVIC->ISER[1]|=0x1<<22; //54번 IRQ. ISER[1] 32~63
//count start
TIM6->CR1 |= 0x1<<0;
while (1)
{
if(TIM6->SR & 0x1){//(UIF)Update interrupt flag
uart3_printf(".");
TIM6->SR &= ~(1 << 0);
}
}
/* USER CODE END 3 */
}

'Cortex-M' 카테고리의 다른 글
| 펌웨어 기본 동작 구현1- Key 입력 시 눌린 순서 번호+문장 UART출력 | STM32CubeIDE ,STM32F429ZI (0) | 2025.05.25 |
|---|---|
| TIM9 구조와 활용, 익셉션(인터럽트)활용, PWM 파형 출력 (로직 애널라이저) (0) | 2025.05.25 |
| IWDG Independent watch dog | 레지스터 제어로 코드 구현(STM32F429ZI) (0) | 2025.05.23 |
| button Key 인터럽트로 LED 토글하기(레지스터제어) | STM32cubeIDE(32F429ZI) (0) | 2025.05.23 |
| SysTick 타이머 동작 및 레지스터 이해 | STM32F42ZI (1) | 2025.05.23 |