TIM2 / PWM User Description

현재 구현에서 TIM2 time-base, CCR1 PWM duty, CC1E gate, CCR2 compare event가 PWM_OUT과 ADC 변환으로 이어지는 과정을 연결합니다.

1. 그림에서 먼저 보기

Figure 1의 번호는 아래 표의 같은 번호 행으로 이어집니다. 노란 경로는 현재 구현에서 보이는 CCR1→PA2/PWM_OUT과 CCR2→TIM2_CC2→ADC입니다. ADC 변환은 ADC1 설정까지 완료되어야 시작됩니다.

RM0008-style TIM2 time-base, CC1 input MUX, CCR1 PWM output, and CCR2 ADC event paths 1 2 3 4 5

Figure 1. TIM2 clock, compare, PWM_OUT, and ADC trigger route

RM0008 Rev 21 Figure 100을 현재 구현 범위에 맞게 재구성했습니다. CC1I/CC2I는 공식 interrupt/DMA request output이고 U는 update event signal이며, 이 request/flag side effect는 현재 구현에서 Reference-only입니다. ADC 시작 신호는 TRGO가 아니라 TIM2_CC2입니다. 전체 trigger/slave block과 사용하지 않는 channel lane은 생략했습니다.

2. 블록 → 레지스터 비트

읽는 순서: 지원되는 항목을 먼저 확인하고, 미지원 항목은 문서 하단의 지원하지 않는 항목에서 확인합니다.

그림 블록레지스터필드 / bit그림에서 하는 일 / 값 의미지원 여부
1Figure 1 TIM2 clock
TIM2CLK gateRCC_APB1ENRTIM2EN[0]그림에서: APB1 clock을 TIM2 peripheral path에 공급합니다.0 = TIM2 clock 차단1 = TIM2 clock 공급TIM2 register effect와 counter 진행의 clock gate입니다.지원됨
2Figure 1 prescaler
Counter dividerTIM2_PSCPSC[15:0]그림에서: TIM2 입력 clock을 PSC+1로 나눠 counter clock을 만듭니다.PSC = 0 TIM2CLK / 1PSC = n TIM2CLK / (n + 1)현재 timing 계산과 Docs / Log frequency 메시지에 반영됩니다.지원됨
3Figure 1 counter and period
Counter enableTIM2_CR1CEN[0]그림 밖에서: Figure 1에는 CEN field가 직접 표시되지 않지만 CNT와 현재 PWM 경로의 실행을 제어합니다.0 = counter 정지1 = counter 시작CEN을 0으로 내려도 공식 하드웨어의 CNT 값은 자동으로 지워지지 않습니다.지원됨
Counter valueTIM2_CNTCNT[15:0]그림에서: 현재 counter 값을 보여 줍니다.CNT = n 현재 period 안의 count 위치TIM2_CNT는 read/write(RW) register입니다. software가 현재 count를 읽을 수도 있고, 0 또는 원하는 시작값을 직접 쓸 수도 있습니다. TIM2_CCR2 crossing과 PWM sample phase도 이 값을 기준으로 합니다.지원됨
Auto-reloadTIM2_ARRARR[15:0]그림에서: counter가 포함해서 세는 마지막 값, 즉 CNT limit를 정합니다.ARR = 0 공식 하드웨어에서 counter blockARR = n CNT는 0부터 n까지 센 뒤 0으로 rollover, period counts = n + 1ARR에 100을 쓰면 CNT는 0부터 100까지 센 뒤 다음 counter clock에서 0으로 돌아갑니다. 0도 한 count이므로 총 101 counts입니다. 현재 구현은 저장된 ARR 값을 바로 timing 계산에 사용합니다.지원됨
4Figure 1 PWM compare and output gate
Duty compareTIM2_CCR1CCR1[15:0]그림에서: CNT와 비교하여 PWM 내부 파형이 바뀌는 경계값을 정합니다.CCR1 = n active-high PWM mode 1에서 CNT < n 동안 active, CNT = n부터 inactive예: ARR=99, CCR1=40이면 CNT 0~39는 active이고 40~99는 inactive라 duty는 40%입니다. 이 compare 결과가 OC1REF 방식의 내부 기준 파형이 되며, 현재 구현 고정 경로에서는 PA2/PWM_OUT으로 이어집니다.지원됨
Output gateTIM2_CCERCC1E[0]그림에서: CCR1 compare 출력을 현재 PWM_OUT 경로로 내보내는 gate입니다.0 = 출력 차단1 = 출력 허용CEN도 1이어야 하며, 공식 PA2/TIM2_CH3 gate는 CC3E입니다.지원됨
PA2 pad prerequisiteGPIOA_CRLCNF2[11:10] / MODE2[9:8]그림 밖에서: Figure 1에는 GPIOA_CRL field가 직접 표시되지 않으며, PA2 pad를 출력 가능한 상태로 준비합니다.CRL[11:8] = 0xB 공식 AF push-pull 50 MHzMODE2 != 00 현재 구현이 허용하는 단순화된 output-capable 조건현재 구현은 TIM2_CCR1을 PA2/PWM_OUT에 연결한 고정 경로를 사용하며, 이는 공식 PA2/TIM2_CH3 mux와 다릅니다.지원됨
5Figure 1 TIM2_CC2 → ADC trigger route
Sample compareTIM2_CCR2CCR2[15:0]그림에서: ADC sample trigger를 보낼 compare 위치를 정합니다.CCR2 = n CNT가 n에 도달하거나 한 simulator tick 안에서 지나면 TIM2_CC2 event 발생이 값만으로 ADC 변환이 시작되지는 않습니다.지원됨
ADC trigger acceptanceADC_CR2EXTSEL[19:17] / EXTTRIG[20]그림에서: TIM2_CC2를 regular trigger로 선택하고 external trigger를 허용합니다.EXTSEL = 011 TIM2_CC2 선택EXTTRIG = 0 외부 trigger 비활성화EXTTRIG = 1 외부 trigger 활성화실제 변환에는 ADC1 clock, PA1 analog mode, ADC_SQR3 SQ1=1도 필요하며 나머지 ADC 설정은 ADC User Description에서 이어집니다.지원됨

3. 표 기준 단순 코드

현재 코드 / 값데이터시트 필드로 해석화면에서 확인
RCC_APB1ENR_TIM2ENRCC_APB1ENR.TIM2EN[0] = 1: TIM2 clock gate 공급Registers → Clock
TIM2->PSC = 11999uTIM2_PSC.PSC[15:0] = 11999: 72 MHz / (11999 + 1) = 6 kHz counter clockRegisters, Docs / Log timing
TIM2->ARR = 99uTIM2_ARR.ARR[15:0] = 99: period count = 100Registers, Docs / Log timing
pwm_write(30u)TIM2_CCR1.CCR1[15:0] = 30: fixed PWM mode 1 rule에서 30 / (99 + 1) = 30% dutyRegisters, Board Lab pin routes, Graph
TIM2->CCER = TIM2_CCER_CC1ETIM2_CCER.CC1E[0] = 1: channel-1 output gate 허용. 현재 구현에서는 PA2/PWM_OUT 고정 alias gateRegisters, Board Lab pin routes
TIM2->CR1 = TIM2_CR1_CENTIM2_CR1.CEN[0] = 1: counter 시작Registers, Code Watch
TIM2->CCR2 = 30uTIM2_CCR2.CCR2[15:0] = 30: TIM2_CC2 compare event 위치Registers, Docs / Log, Sample log
ADC1->CR2 = ADC_CR2_EXTSEL_TIM2_CC2 | ADC_CR2_EXTTRIGADC_CR2.EXTSEL[19:17] = 011EXTTRIG[20] = 1: TIM2_CC2 event를 ADC regular trigger로 허용Registers, Graph Sample log, ADC User Description

4. 현재 Trainer 실행 예제

FW EDIT에 그대로 붙여넣어 PA2/PWM_OUT의 60 Hz, 30% duty와 TIM2 counter를 확인합니다. 각 주석의 번호는 위 블록 → 레지스터 비트 표와 연결되며, 현재 Trainer가 제공하는 CCR1→PA2 고정 경로를 사용합니다.

#include "training_api.h"

static void gpio_init(void)
{
    GPIOA->CRL = 0x40422B00u; /* TIM User Description 4번: PA2 PWM pad 전제, GPIO UD 4번 */
    GPIOB->CRL = 0x44444440u; /* P02 공통 Port API: PB0 analog, GPIO UD 4번 */
    GPIOA->ODR &= ~(GPIOA_DRV_EN_BIT | GPIOA_DRV_DIR_BIT); /* GPIO UD 2번: motor output 안전 시작 */
}

static void pwm_init(void)
{
    TIM2->PSC = 11999u;               /* TIM User Description 2번: 72 MHz / 12000 = 6 kHz */
    TIM2->ARR = 99u;                  /* TIM User Description 3번: 100 counts = 60 Hz period */
    TIM2->CCR1 = 0u;                  /* TIM User Description 4번: duty compare 안전 시작값 */
    TIM2->CCER = TIM2_CCER_CC1E;      /* TIM User Description 4번: PWM output gate 허용 */
    TIM2->CR1 = TIM2_CR1_CEN;         /* TIM User Description 3번: counter 시작 */
}

static void pwm_write(uint32_t duty_percent)
{
    if (duty_percent > 100u) duty_percent = 100u;
    TIM2->CCR1 = duty_percent; /* TIM User Description 4번: CCR1 duty compare 갱신 */
}

void user_init(void)
{
    trainer_clock_init_72mhz();               /* RCC User Description 1~4번: 72 MHz clock 경로 */
    RCC->APB2ENR = RCC_APB2ENR_AFIOEN;       /* RCC User Description 5번: AFIO gate */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;      /* TIM User Description 4번: PA2 pad용 GPIOA gate */
    RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;      /* P02 공통 Port API의 GPIOB gate */
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;      /* P02 공통 Port API의 ADC1 gate */
    RCC->APB1ENR = RCC_APB1ENR_TIM2EN;       /* TIM User Description 1번: TIM2 clock gate */
    gpio_init();                              /* TIM User Description 4번: PA2 output 전제 */
    pwm_init();                               /* TIM User Description 2~4번 설정 */
    pwm_write(30u);                           /* TIM User Description 4번: CCR1=30, duty 30% */
}

void user_loop(void)
{
    watch_u32("TIM2_PSC", TIM2->PSC);   /* 2번 prescaler */
    watch_u32("TIM2_ARR", TIM2->ARR);   /* 3번 period limit */
    watch_u32("TIM2_CNT", TIM2->CNT);   /* 3번 current counter */
    watch_u32("TIM2_CCR1", TIM2->CCR1); /* 4번 duty compare */
}

5. 사이트에서 확인

바로 위 실행 예제의 PSC·ARR·CCR1·CC1E·CEN 결과를 아래 화면에서 확인합니다.

6. 부록: ARR·CNT·COMPARE로 PWM 완성하기

Figure A와 Figure B는 위 표의 TIM2_CNT, TIM2_ARR, TIM2_CCR1, TIM2_CCER를 한 흐름으로 읽기 위한 학습 그림입니다. 공식 필드 정의는 TIM2_CNT, TIM2_ARR, TIM2_CCR1 항목과 연결됩니다.

6.1 ARR는 CNT가 포함해서 세는 마지막 값

ARR equals 100, CNT counts from 0 through 100, then rolls over to 0; CNT is read-write

Figure A. ARR=100일 때 CNT의 0→100→0 rollover와 read/write 의미

ARR는 count 개수 자체가 아니라 마지막으로 포함되는 CNT 값입니다. 따라서 ARR=100이면 CNT=0, 1, 2, …, 99, 100까지 진행하고, 다음 counter clock에서 0으로 돌아갑니다. 0도 한 count이므로 한 period는 총 ARR+1=101 counts입니다.

TIM2_CNT는 read/write(RW) register입니다. 실행 중 현재 위치를 읽을 수 있고, software가 0이나 원하는 시작값을 직접 쓸 수도 있습니다. CEN=0으로 정지해도 CNT가 자동으로 0이 되지는 않습니다.

uint32_t now = TIM2->CNT;  /* 현재 count 읽기 */
TIM2->CNT = 0u;            /* 0부터 다시 시작 */
TIM2->CNT = 40u;           /* 40을 시작 위치로 쓰기 */

6.2 CCR1 compare가 OC1REF와 PWM_OUT을 만드는 방법

CNT and CCR1 comparator creates OC1REF, then CC1E gates the fixed PA2 PWM output; ARR 99 and CCR1 40 create 40 percent duty

Figure B. ARR=99, CCR1=40에서 compare 경계, OC1REF, CC1E, PA2/PWM_OUT 흐름

compare 위치는 CNT가 CCR1과 같아지면서 PWM 상태가 바뀌는 경계입니다. 위 예에서 CCR1=40이므로 CNT=0~39에서는 CNT<CCR1이 참이고, CNT=40~99에서는 거짓입니다. 그래서 active-high PWM mode 1 기준으로 100 counts 중 40 counts가 HIGH가 되어 duty는 40%입니다.

6.3 PWM이 실제로 나오기 위한 전체 조건

순서레지스터 / 필드역할
1RCC_APB1ENR.TIM2EN / RCC_APB2ENR.IOPAENTIM2와 GPIOA에 clock을 공급합니다.
2GPIOA_CRL[11:8] = 0xBPA2를 공식 AF push-pull output으로 준비합니다. 현재 구현은 단순화되어 MODE2 != 00인 output-capable 상태를 허용합니다.
3TIM2_PSC / TIM2_ARRcounter 속도와 한 period의 마지막 CNT 값을 정합니다.
4TIM2_CCR1CNT와 비교할 경계값을 정하여 duty를 만듭니다.
5TIM2_CCER.CC1E / TIM2_CR1.CEN현재 PWM_OUT gate를 열고 counter를 시작합니다.
확인TIM2_CNT / Graph / PA2/PWM_OUTCNT 진행, HIGH/LOW 파형, 평균 전압을 확인합니다.

공식 STM32와 현재 구현의 차이: 공식 STM32F103에서 PA2는 TIM2_CH3이므로 CCR3→OC3REF→CC3E→PA2 경로를 사용합니다. 현재 구현은 학습용 고정 alias인 CCR1→OC1REF 방식→CC1E→PA2/PWM_OUT 경로를 사용합니다.

7. 지원하지 않는 항목

공식 TIM 기능 중 현재 구현에서 실행되지 않는 필드와 확장 기능을 아래에서 구분합니다.

7.1 그림 번호와 연결되는 미지원 항목

그림 블록레지스터필드 / bit공식 의미와 현재 구현 범위지원 여부
PWM mode decoderTIM2_CCMR1OC1M[6:4]그림 밖에서: Figure 1에는 OC1M field가 직접 표시되지 않으며, 공식 하드웨어에서 compare 결과가 OC1REF 파형으로 바뀌는 방식을 고릅니다.000 = Frozen, 비교 결과가 출력에 영향 없음001 = match 때 active로 set010 = match 때 inactive로 reset011 = match 때 toggle100 = 강제 inactive101 = 강제 active110 = PWM mode 1, up-counting에서 CNT < CCR1 동안 active111 = PWM mode 2, up-counting에서 CNT < CCR1 동안 inactive현재 구현은 이 필드를 학생 코드에 노출하지 않고 고정 PWM mode 1 방식으로 CCR1 duty를 계산합니다.미지원
CCR1 preloadTIM2_CCMR1OC1PE[3]그림 밖에서: Figure 1에는 OC1PE field가 직접 표시되지 않으며, 공식 하드웨어에서 CCR1 write의 preload 사용 여부를 정합니다.0 = preload 비활성화, CCR1 write가 즉시 반영1 = preload 활성화, update event 때 반영현재 구현은 preload transfer를 모델링하지 않고 CCR1 저장값을 바로 duty 계산에 사용합니다.미지원
Update event / status boundaryTIM2_SRUIF[0]그림 밖에서: Figure 1의 U는 update event signal이며, UIF는 그 event 발생을 기록하는 별도 status flag입니다.0 = update event pending 없음1 = update event pending공식 하드웨어에서는 overflow/underflow, UG, trigger reset 등으로 set되고 software가 clear합니다. 현재 구현은 rollover timing만 보이며 UIF flag side effect는 다루지 않습니다.미지원
Software update commandTIM2_EGRUG[0]그림 밖에서: UG는 Figure 1의 U update event를 software로 생성하는 write command이며, U signal 자체가 아닙니다.0 write = 변화 없음1 write = counter 재초기화와 update event 생성현재 구현은 UG write에 따른 preload transfer, UIF set, counter 재초기화를 실행하지 않습니다.미지원
Compare request / status boundaryTIM2_SRCC2IF[2]그림 밖에서: Figure 1의 CC2I는 interrupt/DMA request output이고, CC2IF는 channel 2 event를 기록하는 별도 status flag입니다.0 = compare/capture event pending 없음1 = output compare match 또는 input capture event pending현재 구현은 TIM2_CC2 event를 Docs / Log와 Sample log로 보여 주지만 CC2I request와 CC2IF flag side effect는 모델링하지 않습니다.미지원

7.2 추가 지원 경계

항목공식 STM32 의미현재 구현 경계지원 여부
TIM2_DIER / TIM2_SRCC1I/CC2I interrupt/DMA request와 UIF/CC1IF/CC2IF status flagfocused Registers 목록과 training header에서 제외되며 request/flag side effect는 모델링하지 않습니다.미지원
TIM2_CCMR1OC1M/OC1PE 등 PWM mode와 preload 설정현재 실행 예제는 mode/preload를 조절 가능한 항목처럼 보이지 않게 제외합니다. PA2/PWM_OUT은 현재 고정 경로입니다.미지원
TIM2_EGRUG로 만드는 U update event 등 software event generationcounter rollover timing은 보이지만 UG/preload/UIF side effect는 모델링하지 않습니다.미지원
TIM2_CCR3공식 PA2 TIM2_CH3 PWM은 channel 3 compare register를 사용합니다.현재 구현의 PA2/PWM_OUT은 TIM2_CCR1 고정 alias입니다.미지원
TIM1 / TIM8 advanced-control blocksRepetition counter, dead-time/break, complementary output, trigger/slave controller현재 구현의 실행 가능한 timer register/header/UI 경로는 TIM2 focused block뿐이며 TIM1/TIM8 출력 side effect는 모델링하지 않습니다.미지원