Timer Output compare Introduction
- 이전 글에서는 타이머의 입력 기능(시간 베이스 생성, 입력 캡처 모드)을 다룸
- 이번에는 Output Compare 모드를 학습
- OC 모드는 PWM(펄스 폭 변조) 모드 및 원펄스 모드(One Pulse Mode)와도 관련
실습 목표
- Timer2를 활용하여 500Hz, 1kHz, 2kHz, 4kHz의 사각파(Square Wave) 생성
- Timer2의 4개 채널을 모두 출력 채널로 사용
- 타이머에 4개 입력, 4개 출력이 있다고 착각할 수 있지만 실제로는 총 4개의 채널을 입력 또는 출력으로 설정하는 것
출력 비교(OC) 모드 개념
- Input capture mode 에서는 특정 신호가 감지될 때 타이머 값(카운트 레지스터 값)을 저장
- Output compare mode 에서는 타이머가 특정 값(Capture Compare Register, CCR)과 일치할 때 출력을 토글.
- 파형 생성 방식:
- CCR 값 설정 → 타이머가 해당 값에 도달하면 출력 상태 변경
- 인터럽트 발생 → CCR 값을 다시 변경하여 일정한 주기로 토글
- 반복 수행하여 주기적인 신호(사각파) 생성
구현 방식
- 초기 CCR 값(Pulse Value) 설정 후 타이머 시작
- 타이머가 해당 값에 도달할 때마다 출력 채널 상태 변경(High ↔ Low)
- 인터럽트 핸들러에서 CCR 값을 변경하여 주기적인 출력 유지
- 4개의 채널을 활용하여 다양한 주파수(500Hz, 1kHz, 2kHz, 4kHz)의 신호 생성
Output Compare Exercise
1) Initialize the TIMER output Compare Time base
HAL_TIM_OC_init(TIM_HandleTypeDef*htim)
이전 Timer2 초기화 방식과 동일
2) Configure output channel of the timer
HAL_TIM_OC_ConfigChannel(TIM_HandleTypeDef*htim, TIM_OC_InitTypeDef* sConfig, uint32_t Channel)
✅ Output Compare Process (TIM_OCMODE_TOGGLE)
- 카운터 시작(0부터 증가)
- TIM2가 0부터 시작하여 계속 증가함.
- 비교 값(CCR) 도달
- 예제에서 CCR1 = 0x003A라면, 카운터가 0x003A가 되는 순간 출력을 토글
- LOW → HIGH 또는 HIGH → LOW.
- 다음 비교 값 설정 (인터럽트 발생 시 갱신 가능)
- 인터럽트 핸들러에서 CCR1 값을 새롭게 설정
- 그림에서 OC1에서 HIGH 부분의 길이가 Pulse 에 해당함
- 각 채널에 대해 원하는 frequency square waves에 따라 “Pulse” 값을 계산
OC1REF vs. OC1
- OC1REF : 타이머 내부에서 생성된 신호
- CCR1과 TCNT를 값을 비교하여 생성
- 실제 출력 핀과 연결되기 전 내부적으로 존재하는 가상의 신호
- OC1 : OC1REF를 기준으로 최종적으로 출력되는 신호
- TIMx_CH1 핀으로 나가는 실제 PWM 파형 또는 토글 신호
- OC1REF 값이 변한다고 해서 바로 OC1이 바뀌지는 않고 output polarity 의 영향을 받음
- Polarity = 0 (Active High)
- 기본값 (Default)
- OC1REF = 1이면 OC1 핀 출력도 HIGH
- OC1REF = 0이면 OC1 핀 출력도 LOW
- Polarity = 1 (Active Low)
- 반전된 출력
- OC1REF = 1이면 OC1 핀 출력은 LOW
- OC1REF = 0이면 OC1 핀 출력은 HIGH
- Polarity = 0 (Active High)
Calculate Pulse Value
타이머 설정 개요
- 타이머의 클럭 주파수: 25MHz
- 출력 채널에서 원하는 주파수: 500Hz
- 500Hz의 주기: 0.002초 (2ms)
펄스 지속 시간 (Pulse Duration) 계산
- 50% 듀티 사이클이라면, ON/OFF 시간이 같아야 함→ 즉, 펄스 지속 시간 = 0.001초 (1ms)
- 0.001초의 주파수는 1kHz→ 즉, 토글 주파수는 1kHz가 되어야 함
타이머 카운트 값 계산
- 타이머의 클럭 = 25MHz (1초에 25000000만큼 증가)
- 토글 주파수 = 1kHz (1ms마다 토글링해야함)
- 타이머가 1kHz에서 토글하려면,
→ Pulse Value = 25000 (1ms마다 타이머가 25000 증가)
원하는 출력 주파수 | 토글 주파수 | 계산된 펄스 값 |
500Hz | 1kHz | 25000 |
1kHz | 2kHz | 12500 |
2kHz | 4kHz | 6250 |
4kHz | 8kHz | 3125 |
TIM_HandleTypeDef htimer2;
UART_HandleTypeDef huart2;
uint32_t pulse1_value = 25000; // to produce 500Hz
uint32_t pulse2_value = 12500; // to produce 1kHz
uint32_t pulse3_value = 6250; // to produce 2kHz
uint32_t pulse4_value = 3125; // to produce 4kHz
void TIMER2_Init(void)
{
TIM_OC_InitTypeDef tim2OC_init;
htimer2.Instance = TIM2;
htimer2.Init.Period = 0XFFFFFFFF;
htimer2.Init.Prescaler = 1;
if(HAL_TIM_OC_Init(&htimer2) != HAL_OK) Error_handler();
tim2OC_init.OCMode = TIM_OCMODE_TOGGLE;
tim2OC_init.OCPolarity = TIM_OCPOLARITY_HIGH;
tim2OC_init.Pulse = pulse1_value;
if(HAL_TIM_OC_ConfigChannel(&htimer2, &tim2OC_init, TIM_CHANNEL_1) != HAL_OK) Error_handler();
tim2OC_init.Pulse = pulse2_value;
if(HAL_TIM_OC_ConfigChannel(&htimer2, &tim2OC_init, TIM_CHANNEL_2) != HAL_OK) Error_handler();
tim2OC_init.Pulse = pulse3_value;
if(HAL_TIM_OC_ConfigChannel(&htimer2, &tim2OC_init, TIM_CHANNEL_3) != HAL_OK) Error_handler();
tim2OC_init.Pulse = pulse4_value;
if(HAL_TIM_OC_ConfigChannel(&htimer2, &tim2OC_init, TIM_CHANNEL_4) != HAL_OK) Error_handler();
}
msp.c Configuration
PA2와 PA3는 이미 UART(시리얼 통신)로 할당되어 있기 때문에 사용할 수 없으므로 TIM2 채널 3, 4를 다른 핀으로 대체
- 채널 3: PB10 사용
- 채널 4: PB2 사용
void HAL_TIM_OC_MspInit(TIM_HandleTypeDef *htim)
{
GPIO_InitTypeDef tim2OC_ch_gpios;
// 1) Enable the peripheral clock for the timeer2 peripheral
__HAL_RCC_TIM2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
// 2) Configure a gpios to behave as timer 2 channel 1, 2, 3, and 4
tim2OC_ch_gpios.Pin = GPIO_PIN_0 | GPIO_PIN_1;
tim2OC_ch_gpios.Mode = GPIO_MODE_AF_PP;
tim2OC_ch_gpios.Speed = GPIO_SPEED_FREQ_LOW;
tim2OC_ch_gpios.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOA, &tim2OC_ch_gpios);
tim2OC_ch_gpios.Pin = GPIO_PIN_2 | GPIO_PIN_10;
tim2OC_ch_gpios.Mode = GPIO_MODE_AF_PP;
tim2OC_ch_gpios.Speed = GPIO_SPEED_FREQ_LOW;
tim2OC_ch_gpios.Alternate = GPIO_AF1_TIM2;
HAL_GPIO_Init(GPIOB, &tim2OC_ch_gpios);
// 3) NVIC settings
HAL_NVIC_SetPriority(TIM2_IRQn, 15, 0);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
Callback Implementation
- HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
- CCR1 값 설정:
- HAL_TIM_ReadCapturedValue()로 CCR1 값을 읽고, HAL_TIM_SET_COMPARE()로 CCR1 값을 설정
int main(void)
{
HAL_Init();
SystemClockConfig();
GPIO_Init();
UART2_Init();
TIMER2_Init();
if(HAL_TIM_OC_Start_IT(&htimer2, TIM_CHANNEL_1) != HAL_OK) Error_handler();
if(HAL_TIM_OC_Start_IT(&htimer2, TIM_CHANNEL_2) != HAL_OK) Error_handler();
if(HAL_TIM_OC_Start_IT(&htimer2, TIM_CHANNEL_3) != HAL_OK) Error_handler();
if(HAL_TIM_OC_Start_IT(&htimer2, TIM_CHANNEL_4) != HAL_OK) Error_handler();
while(1)
return 0;
}
uint32_t ccr_content;
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
/* TIM3_CH1 toggling with frequency = 500 Hz */
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_1, ccr_content + pulse1_value);
}
/* TIM3_CH2 toggling with frequency = 1000 Hz */
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_2, ccr_content + pulse2_value);
}
/* TIM3_CH3 toggling with frequency = 2000 Hz */
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_3, ccr_content + pulse3_value);
}
/* TIM3_CH4 toggling with frequency = 4000 Hz */
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
{
ccr_content = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
__HAL_TIM_SET_COMPARE(htim, TIM_CHANNEL_4, ccr_content + pulse4_value);
}
}
⇒ HAL_GPIO_TogglePin() 과 같은 토글 코드를 사용하지 않고 타이머가 직접 CCR register 값과 비교하여 토글링
반응형
'ComputerScience & Embedded > NUCLEO & CAN Tranceiver' 카테고리의 다른 글
CAN (Controller Area Network) Fundamentals (0) | 2025.03.01 |
---|---|
PWM(Pulse Width Modulation) (0) | 2025.03.01 |
General Purpose Timer : Input Capture Unit (0) | 2025.03.01 |
Timers (Polling mode / Interrupt mode) (0) | 2025.03.01 |
PLL Programming (0) | 2025.03.01 |