본문 바로가기
MCU/C2000

TMS320F28388D DSP CPU 타이머 사용법 : Driverlib API로 CPU 타이머 설정과 예제(수정본)

by linuxgo 2025. 8. 8.

TMS320F28388D는 Texas Instruments의 C2000 시리즈 마이크로컨트롤러로, 실시간 제어 애플리케이션에 최적화된 32비트 CPU 타이머를 제공합니다. 이 가이드에서는 TMS320F28388D의 CPU 타이머 구조, 모든 DriverLib API의 상세 설명, 그리고 상세 주석이 포함된 예제 코드를 제공합니다. 초보자부터 숙련된 개발자까지 활용 가능한 실용적인 정보를 제공하며, C2000Ware의 DriverLib를 기반으로 한 예제를 포함합니다.

TMS320F28388D CPU 타이머란

TMS320F28388D는 CPU1과 CPU2 각각에 3개의 32비트 타이머(Timer0, Timer1, Timer2)를 제공하여 총 6개의 타이머를 지원합니다. 이 타이머들은 주기적 인터럽트, 시간 측정, 이벤트 트리거 등에 사용됩니다. 주요 특징은 다음과 같습니다:

  • 32비트 카운터: TIM 레지스터로 시스템 클럭(SYSCLK)을 기반으로 동작.
  • 프리스케일러: TDDR 레지스터로 클럭 분주 조정 가능.
  • 인터럽트: Timer0(PIE 그룹 1, INT7), Timer1(INT13), Timer2(INT14)로 고유 인터럽트 제공.
  • 제어 레지스터: TIF(오버플로우 플래그), TRB(리로드), TSS(시작/정지) 등.

DriverLib API: TMS320F28388D CPU 타이머 제어

TI의 DriverLib는 하드웨어 추상화 계층(HAL)을 제공하여 CPU 타이머 설정을 간소화합니다. driverlib/cputimer.h에 정의된 모든 API는 다음과 같습니다:

1. initCPUTimer(void) -TI 제공 예제 함수

  • 기능: 지정된 타이머를 초기화하여 레지스터를 기본값으로 설정하고 인터럽트를 비활성화.
  • 매개변수: 타이머 베이스 주소(CPUTIMER0_BASE, CPUTIMER1_BASE, CPUTIMER2_BASE).
  • 반환값: 없음.
  • 예시: CPUTimer_initTimer(); // Timer0 초기화.

2. configCPUTimer(uint32_t timer, uint32_t sysclkHz, uint32_t period) - TI 제공 예제 함수

  • 기능: 시스템 클럭 주파수와 주기(마이크로초 단위)를 기반으로 타이머를 설정.
  • 매개변수:
    • timer: 타이머 베이스 주소.
    • sysclkHz: 시스템 클럭 주파수(Hz, 예: DEVICE_SYSCLK_FREQ).
    • period: 타이머 주기(마이크로초).
  • 반환값: 없음.
  • 예시: CPUTimer_configTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, 1000000); // 1초 주기.

3. CPUTimer_startTimer(uint32_t timer)

  • 기능: 타이머를 시작하여 카운터 동작 활성화(TSS 비트를 0으로 설정, TIM을 PRD로 리로드).
  • 매개변수: 타이머 베이스 주소.
  • 반환값: 없음.
  • 예시: CPUTimer_startTimer(CPUTIMER0_BASE); // Timer0 시작.

4. CPUTimer_stopTimer(uint32_t timer)

  • 기능: 타이머를 정지(TSS 비트를 1로 설정).
  • 매개변수: 타이머 베이스 주소.
  • 반환값: 없음.
  • 예시: CPUTimer_stopTimer(CPUTIMER0_BASE); // Timer0 정지.

5. CPUTimer_reloadTimerCounter(uint32_t timer)

  • 기능: 타이머 카운터(TIM)를 주기 레지스터(PRD) 값으로 리로드(TRB 비트 설정).
  • 매개변수: 타이머 베이스 주소.
  • 반환값: 없음.
  • 예시: CPUTimer_reloadTimer(CPUTIMER0_BASE); // Timer0 리로드.

6. CPUTimer_getTimerCount(uint32_t timer)

  • 기능: 현재 타이머 카운터(TIM) 값을 반환(인라인 함수로 빠른 실행).
  • 매개변수: 타이머 베이스 주소.
  • 반환값: uint32_t 타입의 카운터 값.
  • 예시: uint32_t count = CPUTimer_getTimerCount(CPUTIMER1_BASE); // 현재 카운터 값 읽기.

7. CPUTimer_enableInterrupt(uint32_t timer)

  • 기능: 타이머 인터럽트를 활성화(TIE 비트 설정).
  • 매개변수: 타이머 베이스 주소.
  • 반환값: 없음.
  • 예시: CPUTimer_enableInterrupt(CPUTIMER0_BASE); // Timer0 인터럽트 활성화.

8. CPUTimer_disableInterrupt(uint32_t timer)

  • 기능: 타이머 인터럽트를 비활성화(TIE 비트 클리어).
  • 매개변수: 타이머 베이스 주소.
  • 반환값: 없음.
  • 예시: CPUTimer_disableInterrupt(CPUTIMER0_BASE); // Timer0 인터럽트 비활성화.

9. CPUTimer_setPeriod(uint32_t timer, uint32_t period)

  • 기능: 타이머의 주기 레지스터(PRD) 값을 설정(클럭 사이클 단위).
  • 매개변수:
    • timer: 타이머 베이스 주소.
    • period: 주기 값(클럭 사이클 단위).
  • 반환값: 없음.
  • 예시: CPUTimer_setPeriod(CPUTIMER1_BASE, 1000000); // 주기 설정.

10. CPUTimer_setPreScaler(uint32_t timer, uint16_t prescaler)

  • 기능: 타이머의 프리스케일러(TDDR)를 설정하여 SYSCLK을 분주.
  • 매개변수:
    • timer: 타이머 베이스 주소.
    • prescaler: 프리스케일러 값(0~255, 실제 분주비는 prescaler+1).
  • 반환값: 없음.
  • 예시: CPUTimer_setPreScaler(CPUTIMER2_BASE, 1); // 분주비 2.

11. CPUTimer_getTimerOverflowStatus(uint32_t timer)

  • 기능: 타이머 오버플로우 플래그(TIF) 상태를 반환(TIM이 0에 도달 시 1).
  • 매개변수: 타이머 베이스 주소.
  • 반환값: bool 타입(true: 오버플로우 발생, false: 발생 안 함).
  • 예시: bool status = CPUTimer_getTimerOverflowStatus(CPUTIMER0_BASE); // 오버플로우 확인.

12. CPUTimer_clearOverflowFlag(uint32_t timer)

  • 기능: 타이머 오버플로우 플래그(TIF)를 클리어.
  • 매개변수: 타이머 베이스 주소.
  • 반환값: 없음.
  • 예시: CPUTimer_clearOverflowFlag(CPUTIMER0_BASE); // 오버플로우 플래그 클리어.

tms320f28388d cputimer

예제 1: 1초 주기 LED 토글

이 예제는 Timer0를 사용하여 1초마다 LED를 토글합니다. 상세 주석으로 각 단계 설명.

//#############################################################################
// FILE:   main.c
// TITLE:  TMS320F28388D CPU Timer0 LED Toggle Example
// DESCRIPTION: Uses CPU Timer0 to toggle an LED every 1 second
//              with DriverLib and C2000Ware, incorporating emulation mode.
// C2000Ware Version: v6.00.00.00
// Copyright (C) 2025 Texas Instruments Incorporated
//#############################################################################

#include "driverlib.h"          // TI DriverLib 기본 헤더 파일 포함
#include "device.h"             // 디바이스별 설정(device.h) 포함
#include "cputimer.h"           // CPU 타이머 관련 API 포함
#include "interrupt.h"          // 인터럽트 관련 API 포함

// Timer0 인터럽트 서비스 루틴(ISR) 선언
__interrupt void timer0ISR(void);

// LED 상태를 저장하는 전역 변수 (volatile로 인터럽트에서 안전하게 사용)
volatile bool ledState = false;

void main(void)
{
    // 디바이스 클럭 및 주변 장치 초기화 (PLL, Watchdog 등 설정)
    // Watchdog은 기본적으로 비활성화됨
    Device_init();

    // GPIO 초기화
    Device_initGPIO();
    // LED 핀 설정 (GPIO31, LAUNCHXL-F28388D의 LED D9 사용)
    // 주의: 사용 중인 보드의 schematics에 따라 GPIO 번호 확인 (예: GPIO34로 변경 가능)
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD); // GPIO31을 표준 GPIO로 설정
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // GPIO31을 출력 모드로 설정

    // PIE(Peripheral Interrupt Expansion) 모듈 초기화
    Interrupt_initModule();
    // 인터럽트 벡터 테이블 초기화
    Interrupt_initVectorTable();

    // Timer0 인터럽트를 ISR에 등록 (INT_TIMER0은 Timer0의 인터럽트 벡터, PIE 그룹 1, INT7)
    Interrupt_register(INT_TIMER0, &timer0ISR);
    // Timer0 인터럽트 활성화
    Interrupt_enable(INT_TIMER0);

    // Timer0 초기화: 레지스터를 수동으로 설정
    // 1. 타이머 정지 (TSS 비트를 1로 설정)
    CPUTimer_stopTimer(CPUTIMER0_BASE);
    // 2. 인터럽트 비활성화 (TIE 비트 클리어, 초기화 안전성 보장)
    CPUTimer_disableInterrupt(CPUTIMER0_BASE);
    // 3. 주기 설정: 1초 주기, 시스템 클럭 200MHz 기준 200,000,000 사이클
    CPUTimer_setPeriod(CPUTIMER0_BASE, 200000000U); // PRD에 200,000,000 설정
    // 4. 프리스케일러 설정: TDDR=0 (분주비 1)
    CPUTimer_setPreScaler(CPUTIMER0_BASE, 0);
    // 주의: Timer0는 SYSCLK(CPUTIMER_CLOCK_SOURCE_SYS)만 사용 가능
    // CPUTimer_selectClockSource는 Timer2 전용

    // 에뮬레이션 모드 설정: 디버깅 시 타이머가 자유 실행되도록 설정
    // CPUTIMER_EMULATIONMODE_RUNFREE: 디버깅 중에도 타이머 계속 실행
    CPUTimer_setEmulationMode(CPUTIMER0_BASE, CPUTIMER_EMULATIONMODE_RUNFREE);

    // Timer0 인터럽트 활성화 (TIE 비트 설정)
    CPUTimer_enableInterrupt(CPUTIMER0_BASE);

    // 전역 인터럽트 활성화 (CPU 수준에서 인터럽트 허용)
    Interrupt_enableMaster();

    // Timer0 시작 (TIM을 PRD로 리로드하고 TSS 비트를 0으로 설정하여 카운터 동작 시작)
    CPUTimer_startTimer(CPUTIMER0_BASE);

    // 무한 루프: 인터럽트가 LED 토글 작업 처리
    for(;;)
    {
        // 추가 작업이 필요 없는 경우 대기
        // 디버깅 시 ledState 또는 CPUTimer_getTimerCount(CPUTIMER0_BASE) 확인 가능
    }
}

// Timer0 인터럽트 서비스 루틴: 1초마다 호출
__interrupt void timer0ISR(void)
{
    // LED 상태 토글 (true/false 전환)
    ledState = !ledState;
    // LED 핀에 상태 쓰기 (1: 켜짐, 0: 꺼짐)
    GPIO_writePin(31, ledState ? 1 : 0);

    // 타이머 오버플로우 플래그(TIF) 클리어
    CPUTimer_clearOverflowFlag(CPUTIMER0_BASE);

    // 인터럽트 확인: PIE 그룹 1 클리어 (Timer0는 그룹 1, INT7에 속함)
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

설명: Timer0를 1초 주기로 설정하고, 인터럽트를 통해 LED를 토글합니다. 주석은 초기화, 설정, 인터럽트 처리 단계를 명확히 설명합니다.

예제 2: 타이머 카운터 모니터링 (SCI 출력)

Timer1의 카운터 값을 SCI를 통해 출력합니다. 상세 주석 포함.

//#############################################################################
// FILE:   main.c
// TITLE:  TMS320F28388D CPU Timer1 SCI Output Example
// DESCRIPTION: Uses CPU Timer1 to monitor counter value every 500ms
//              and outputs via SCIA at 115200 baudrate with DriverLib.
// C2000Ware Version: v6.00.00.00
// Copyright (C) 2025 Texas Instruments Incorporated
//#############################################################################

#include "driverlib.h"          // TI DriverLib 기본 헤더 파일 포함
#include "device.h"             // 디바이스별 설정(device.h) 포함
#include "cputimer.h"           // CPU 타이머 관련 API 포함
#include "sci.h"                // SCI 관련 API 포함
#include <stdio.h>              // sprintf를 위한 표준 라이브러리 포함
#include <string.h>             // strlen을 위한 표준 라이브러리 포함

// SCI를 통해 문자열을 전송하는 함수
void SCI_print(const char *msg)
{
    // SCI 모듈을 통해 문자열 전송 (uint16_t로 캐스팅하여 전송)
    SCI_writeCharArray(SCIA_BASE, (uint16_t *)msg, strlen(msg));
}

void main(void)
{
    // 디바이스 클럭 및 주변 장치 초기화 (PLL, Watchdog 등 설정)
    // Watchdog은 기본적으로 비활성화됨
    Device_init();

    // GPIO 초기화
    Device_initGPIO();
    // SCI TX/RX 핀 설정 (LAUNCHXL-F28388D: GPIO28=SCIA_RX, GPIO29=SCIA_TX)
    // pin_map.h: GPIO_28_SCIA_RX (0x00081801U), GPIO_29_SCIA_TX (0x00081A01U)
    GPIO_setPinConfig(GPIO_28_SCIA_RX); // GPIO28을 SCIA RX로 설정
    GPIO_setPinConfig(GPIO_29_SCIA_TX); // GPIO29를 SCIA TX로 설정

    // SCI 설정: 115200 baudrate, 8비트 데이터, 1 스톱 비트, 패리티 없음
    // LSPCLK: DEVICE_LSPCLK_FREQ (예: 50MHz) 기준
    SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200,
                  (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));
    // SCI FIFO 활성화 (전송 안정성 향상)
    SCI_enableFIFO(SCIA_BASE);
    // SCI 모듈 활성화
    SCI_enableModule(SCIA_BASE);

    // Timer1 초기화: 레지스터를 수동으로 설정
    // 1. 타이머 정지 (TSS 비트를 1로 설정)
    CPUTimer_stopTimer(CPUTIMER1_BASE);
    // 2. 인터럽트 비활성화 (TIE 비트 클리어, 이 예제에서는 인터럽트 사용 안 함)
    CPUTimer_disableInterrupt(CPUTIMER1_BASE);
    // 3. 주기 설정: 500ms 주기, 시스템 클럭 200MHz 기준 100,000,000 사이클
    CPUTimer_setPeriod(CPUTIMER1_BASE, 100000000U); // PRD에 100,000,000 설정
    // 4. 프리스케일러 설정: TDDR=0 (분주비 1)
    CPUTimer_setPreScaler(CPUTIMER1_BASE, 0);
    // 주의: Timer1은 SYSCLK(CPUTIMER_CLOCK_SOURCE_SYS)만 사용 가능
    // CPUTimer_selectClockSource는 Timer2 전용

    // 에뮬레이션 모드 설정: 디버깅 시 타이머가 자유 실행되도록 설정
    // CPUTIMER_EMULATIONMODE_RUNFREE: 디버깅 중에도 타이머 계속 실행
    CPUTimer_setEmulationMode(CPUTIMER1_BASE, CPUTIMER_EMULATIONMODE_RUNFREE);

    // Timer1 시작 (TIM을 PRD로 리로드하고 TSS 비트를 0으로 설정하여 카운터 동작 시작)
    CPUTimer_startTimer(CPUTIMER1_BASE);

    // 카운터 값을 저장할 문자열 버퍼
    char msg[50];
    // 메인 루프: 타이머 값 모니터링 및 SCI 출력
    for(;;)
    {
        // 현재 Timer1의 카운터 값 읽기 (TIM 레지스터 값 반환)
        uint32_t count = CPUTimer_getTimerCount(CPUTIMER1_BASE);

        // 카운터 값을 문자열로 변환 (포맷: "Timer1 Count: <값>")
        sprintf(msg, "Timer1 Count: %lu\r\n", count);
        // SCI로 문자열 전송
        SCI_print(msg);

        // 100ms 대기하여 과도한 SCI 전송 방지 (100,000us)
        DEVICE_DELAY_US(100000);
    }
}

설명: Timer1의 카운터 값을 100ms마다 읽어 SCI로 전송합니다. 주석은 SCI 설정, 타이머 설정, 데이터 전송 과정을 상세히 설명합니다.

예제 3: 다중 타이머 동기화

Timer0, Timer1, Timer2를 각각 1초, 2초, 4초 주기로 동기화합니다. 상세 주석 포함.



//
// 포함된 파일들
//
#include "driverlib.h"       // TI DriverLib 헤더 파일 포함: C2000 마이크로컨트롤러의 주변 장치 드라이버 라이브러리를 제공합니다.
#include "device.h"          // 디바이스별 설정(device.h) 포함: 특정 디바이스(예: TMS320F2837xD)의 설정과 매크로를 정의합니다.

//
// 전역 변수들: 각 타이머의 인터럽트 발생 횟수를 저장하는 변수들. volatile 키워드로 컴파일러 최적화 방지하여 ISR에서 안전하게 접근 가능.
//
volatile uint32_t timer0Count = 0;  // Timer0 인터럽트 카운터: 1초마다 증가
volatile uint32_t timer1Count = 0;  // Timer1 인터럽트 카운터: 2초마다 증가
volatile uint32_t timer2Count = 0;  // Timer2 인터럽트 카운터: 4초마다 증가

//
// 함수 프로토타입 선언: 컴파일러가 함수를 미리 인식하도록 함.
//
__interrupt void timer0ISR(void);   // Timer0 인터럽트 서비스 루틴(ISR) 선언: 인터럽트 발생 시 호출됨.
__interrupt void timer1ISR(void);   // Timer1 인터럽트 서비스 루틴(ISR) 선언.
__interrupt void timer2ISR(void);   // Timer2 인터럽트 서비스 루틴(ISR) 선언.
void initCPUTimers(void);           // 모든 CPU 타이머를 초기화하는 함수 선언.
void configCPUTimer(uint32_t, float, float);  // 특정 타이머를 설정하는 함수 선언: 베이스 주소, 시스템 클럭 주파수, 주기(usec) 전달.

//
// Main 함수: 프로그램의 진입점. 디바이스 초기화, 인터럽트 설정, 타이머 시작 후 무한 루프 실행.
//
void main(void)
{
    //
    // 디바이스 클럭 및 주변 장치 초기화: 시스템 클럭(SYSCLK), PLL, 주변 클럭 등을 설정합니다. Device_init()는 C2000Ware의 표준 초기화 함수입니다.
    //
    Device_init();

    //
    // PIE(Peripheral Interrupt Expansion) 모듈 초기화: PIE 레지스터를 초기화하고 CPU 인터럽트를 비활성화합니다. 인터럽트 벡터를 관리합니다.
    //
    Interrupt_initModule();

    //
    // 인터럽트 벡터 테이블 초기화: 기본 ISR을 쉘 ISR로 설정합니다. 이 테이블은 인터럽트 발생 시 호출될 함수 포인터를 저장합니다.
    //
    Interrupt_initVectorTable();

    //
    // 각 CPU 타이머 인터럽트에 대한 ISR 등록: INT_TIMER0은 PIE Group 1.7, INT_TIMER1은 CPU INT13, INT_TIMER2은 CPU INT14에 매핑됩니다.
    //
    Interrupt_register(INT_TIMER0, &timer0ISR);  // Timer0 ISR 등록: PIE를 통해 라우팅됨.
    Interrupt_register(INT_TIMER1, &timer1ISR);  // Timer1 ISR 등록: 직접 CPU 인터럽트.
    Interrupt_register(INT_TIMER2, &timer2ISR);  // Timer2 ISR 등록: 직접 CPU 인터럽트.

    //
    // CPU 타이머 주변 장치 초기화: 이 예제에서는 CPU 타이머만 초기화합니다. 다른 주변 장치는 필요 시 추가.
    //
    initCPUTimers();

    //
    // CPU-Timer 0, 1, 2를 각각 1초, 2초, 4초 주기로 인터럽트 발생하도록 설정: 주기(usec 단위)로 전달. DEVICE_SYSCLK_FREQ는 시스템 클럭(Hz)입니다.
    //
    configCPUTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, 1000000.0f);  // Timer0: 1초 주기 (1,000,000 usec)
    configCPUTimer(CPUTIMER1_BASE, DEVICE_SYSCLK_FREQ, 2000000.0f);  // Timer1: 2초 주기 (2,000,000 usec)
    configCPUTimer(CPUTIMER2_BASE, DEVICE_SYSCLK_FREQ, 4000000.0f);  // Timer2: 4초 주기 (4,000,000 usec)

    //
    // Timer2의 프리스케일러 설정: 분주비 2 (TDDR = 1)로 설정하여 클럭을 1/2로 분주. 이는 주기 계산에 영향을 줌 (효과적인 주파수 감소).
    //
    CPUTimer_setPreScaler(CPUTIMER2_BASE, 1);

    //
    // 타이밍 정확성을 위해 전체 레지스터에 write-only 명령 사용: configCPUTimer나 initCPUTimers에서 변경된 설정을 업데이트. 인터럽트 활성화.
    //
    CPUTimer_enableInterrupt(CPUTIMER0_BASE);  // Timer0 인터럽트 활성화: TIE 비트 설정.
    CPUTimer_enableInterrupt(CPUTIMER1_BASE);  // Timer1 인터럽트 활성화.
    CPUTimer_enableInterrupt(CPUTIMER2_BASE);  // Timer2 인터럽트 활성화.

    //
    // CPU 인터럽트 활성화: INT_TIMER0 (PIE Group 1.7), INT_TIMER1 (CPU INT13), INT_TIMER2 (CPU INT14) 활성화. PIE에서 TINT0 활성화.
    //
    Interrupt_enable(INT_TIMER0);
    Interrupt_enable(INT_TIMER1);
    Interrupt_enable(INT_TIMER2);

    //
    // CPU-Timer 0, 1, 2 시작: 타이머 카운터가 감소 시작. 주기 도달 시 인터럽트 발생.
    //
    CPUTimer_startTimer(CPUTIMER0_BASE);
    CPUTimer_startTimer(CPUTIMER1_BASE);
    CPUTimer_startTimer(CPUTIMER2_BASE);

    //
    // 전역 인터럽트(INTM) 및 실시간 인터럽트(DBGM) 활성화: Interrupt_enableMaster()는 EINT와 유사하게 INTM 비트 클리어.
    //
    Interrupt_enableMaster();

    //
    // 무한 루프: 인터럽트가 백그라운드에서 작업 처리. 디버깅 시 Expressions 창에서 timer0Count 등 확인 가능. 필요 시 여기에 코드 추가 (예: GPIO 토글).
    //
    for(;;)
    {
        // NOP; 또는 asm(" NOP;")으로 CPU IDLE 유지 가능.
    }
}

//
// initCPUTimers - 이 함수는 모든 세 CPU 타이머를 알려진 상태로 초기화합니다. 최대 주기, 기본 프리스케일러, 정지 상태 등 설정.
//
void
initCPUTimers(void)
{
    //
    // 타이머 주기 최대값으로 초기화: 32비트 카운터의 최대값(0xFFFFFFFF)으로 설정하여 오버플로우 방지 초기 상태.
    //
    CPUTimer_setPeriod(CPUTIMER0_BASE, 0xFFFFFFFF);  // Timer0 주기 최대 설정.
    CPUTimer_setPeriod(CPUTIMER1_BASE, 0xFFFFFFFF);  // Timer1 주기 최대 설정.
    CPUTimer_setPeriod(CPUTIMER2_BASE, 0xFFFFFFFF);  // Timer2 주기 최대 설정.

    //
    // 프리스케일러를 SYSCLKOUT으로 분주 1로 초기화: 분주비 1 (Prescaler = 0)로 클럭 그대로 사용.
    //
    CPUTimer_setPreScaler(CPUTIMER0_BASE, 0);
    CPUTimer_setPreScaler(CPUTIMER1_BASE, 0);
    CPUTimer_setPreScaler(CPUTIMER2_BASE, 0);

    //
    // 타이머 정지 확인: 카운터 동작 중지.
    //
    CPUTimer_stopTimer(CPUTIMER0_BASE);
    CPUTimer_stopTimer(CPUTIMER1_BASE);
    CPUTimer_stopTimer(CPUTIMER2_BASE);

    //
    // 모든 카운터 레지스터를 주기 값으로 리로드: TMR 카운터를 PRD 값으로 초기화.
    //
    CPUTimer_reloadTimerCounter(CPUTIMER0_BASE);
    CPUTimer_reloadTimerCounter(CPUTIMER1_BASE);
    CPUTimer_reloadTimerCounter(CPUTIMER2_BASE);

    //
    // 인터럽트 카운터 초기화: 각 타이머의 발생 횟수를 0으로 리셋.
    //
    timer0Count = 0;
    timer1Count = 0;
    timer2Count = 0;
}

//
// configCPUTimer - 이 함수는 선택된 타이머를 "freq"와 "period" 매개변수로 지정된 주기로 초기화합니다. "freq"는 Hz 단위, "period"는 uSeconds 단위. 설정 후 타이머는 정지 상태로 유지됩니다.
//
void
configCPUTimer(uint32_t cpuTimer, float freq, float period)
{
    uint32_t temp;  // 임시 변수: 주기 계산 결과를 저장.

    //
    // 타이머 주기 초기화: 공식 = (freq / 1e6) * period - 1. freq는 SYSCLK(Hz), period는 usec이므로 초당 카운트 계산.
    //
    temp = (uint32_t)((freq / 1000000.0f) * period);  // 주기 값 계산: (SYSCLK / 1e6) * usec.
    CPUTimer_setPeriod(cpuTimer, temp - 1);  // 계산된 값 -1로 PRD 레지스터 설정 (타이머는 0에서 PRD까지 카운트).

    //
    // 프리스케일러를 SYSCLKOUT으로 분주 1로 설정: 기본 분주비 1 (Prescaler = 0).
    //
    CPUTimer_setPreScaler(cpuTimer, 0);

    //
    // 타이머 제어 레지스터 초기화: 타이머 정지, 카운터 리로드, 자유 실행 비활성화, 인터럽트 활성화. 또한 free 및 soft 비트 설정.
    //
    CPUTimer_stopTimer(cpuTimer);  // 타이머 정지.
    CPUTimer_reloadTimerCounter(cpuTimer);  // 카운터 리로드.
    CPUTimer_setEmulationMode(cpuTimer, CPUTIMER_EMULATIONMODE_STOPAFTERNEXTDECREMENT);  // 에뮬레이션 모드: 디버깅 시 다음 감소 후 정지.
    CPUTimer_enableInterrupt(cpuTimer);  // 인터럽트 활성화.

    //
    // 세 CPU 타이머의 인터럽트 카운터 리셋: 해당 타이머에 따라 카운터 초기화.
    //
    if (cpuTimer == CPUTIMER0_BASE)
    {
        timer0Count = 0;  // Timer0 카운터 리셋.
    }
    else if(cpuTimer == CPUTIMER1_BASE)
    {
        timer1Count = 0;  // Timer1 카운터 리셋.
    }
    else if(cpuTimer == CPUTIMER2_BASE)
    {
        timer2Count = 0;  // Timer2 카운터 리셋.
    }
}

//
// timer0ISR - CpuTimer0에 대한 카운터: 1초마다 호출됨. PIE Group 1을 통해 처리.
//
__interrupt void
timer0ISR(void)
{
    timer0Count++;  // Timer0 인터럽트 횟수 증가: 1초마다 1씩 증가.

    //
    // 오버플로우 플래그 클리어: TIFR.INT 비트 클리어하여 다음 인터럽트 준비.
    //
    CPUTimer_clearOverflowFlag(CPUTIMER0_BASE);

    //
    // 이 인터럽트를 확인하여 Group 1에서 더 많은 인터럽트 수신: PIE ACK로 Group 1 클리어 (Timer0만 PIE 사용).
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

//
// timer1ISR - CpuTimer1에 대한 카운터: 2초마다 호출됨. 직접 CPU INT13 처리.
//
__interrupt void
timer1ISR(void)
{
    timer1Count++;  // Timer1 인터럽트 횟수 증가: 2초마다 1씩 증가.

    //
    // 오버플로우 플래그 클리어: TIFR.INT 비트 클리어.
    //
    CPUTimer_clearOverflowFlag(CPUTIMER1_BASE);
    // PIE ACK 불필요: 직접 CPU 인터럽트.
}

//
// timer2ISR - CpuTimer2에 대한 카운터: 4초마다 호출됨. 직접 CPU INT14 처리.
//
__interrupt void
timer2ISR(void)
{
    timer2Count++;  // Timer2 인터럽트 횟수 증가: 4초마다 1씩 증가.

    //
    // 오버플로우 플래그 클리어: TIFR.INT 비트 클리어.
    //
    CPUTimer_clearOverflowFlag(CPUTIMER2_BASE);
    // PIE ACK 불필요: 직접 CPU 인터럽트.
}

//
// End of File
//

설명: 세 타이머를 각각 다른 주기로 설정하고, 프리스케일러를 적용해 동기화합니다. 주석은 각 타이머의 초기화, 설정, 인터럽트 처리 과정을 상세히 설명합니다.