본문 바로가기
MCU/C2000

[TMS320F28388D] 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. CPUTimer_initTimer(uint32_t timer)

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

2. CPUTimer_configTimer(uint32_t timer, uint32_t sysclkHz, uint32_t period)

  • 기능: 시스템 클럭 주파수와 주기(마이크로초 단위)를 기반으로 타이머를 설정.
  • 매개변수:
    • 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_reloadTimer(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); // 오버플로우 플래그 클리어.

예제 1: 1초 주기 LED 토글

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

#include "driverlib.h"       // TI DriverLib 헤더 파일 포함
#include "device.h"          // 디바이스별 설정(device.h) 포함

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

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

void main(void)
{
    // 디바이스 클럭 및 주변 장치 초기화 (PLL, Watchdog 등 설정)
    Device_init();

    // GPIO 초기화 및 LED 핀 설정 (예: GPIO0을 LED로 사용)
    Device_initGPIO();
    GPIO_setPadConfig(DEVICE_GPIO_PIN_LED1, GPIO_PIN_TYPE_STD); // 표준 GPIO 설정
    GPIO_setDirectionMode(DEVICE_GPIO_PIN_LED1, GPIO_DIR_MODE_OUT); // 출력 모드 설정

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

    // Timer0 인터럽트를 ISR에 등록 (INT_TINT0은 Timer0의 인터럽트 벡터)
    Interrupt_register(INT_TINT0, &timer0ISR);
    // Timer0 인터럽트 활성화
    Interrupt_enable(INT_TINT0);

    // Timer0 초기화 (레지스터를 기본값으로 리셋)
    CPUTimer_initTimer(CPUTIMER0_BASE);

    // Timer0 설정: 시스템 클럭(예: 200MHz), 1초(1000000us) 주기로 설정
    CPUTimer_configTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, 1000000);

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

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

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

    // 무한 루프: 인터럽트가 작업 처리
    for(;;)
    {
        // 추가 작업이 필요 없는 경우 대기
    }
}

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

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

    // 인터럽트 확인 (PIE 그룹 1 클리어)
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

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

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

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

#include "driverlib.h"       // TI DriverLib 헤더 파일 포함
#include "device.h"          // 디바이스별 설정(device.h) 포함
#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 등 설정)
    Device_init();
    // GPIO 초기화
    Device_initGPIO();

    // SCI TX/RX 핀 설정 (예: SCIA 모듈 사용)
    GPIO_setPinConfig(DEVICE_GPIO_CFG_SCIA_TX); // SCI 전송 핀 설정
    GPIO_setPinConfig(DEVICE_GPIO_CFG_SCIA_RX); // SCI 수신 핀 설정

    // SCI 설정: 115200 baudrate, 8비트 데이터, 1 스톱 비트, 패리티 없음
    SCI_setConfig(SCIA_BASE, DEVICE_LSPCLK_FREQ, 115200, 
                  (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));
    // SCI 모듈 활성화
    SCI_enableModule(SCIA_BASE);

    // Timer1 초기화 (레지스터를 기본값으로 리셋)
    CPUTimer_initTimer(CPUTIMER1_BASE);

    // Timer1 설정: 시스템 클럭, 500ms(500000us) 주기로 설정
    CPUTimer_configTimer(CPUTIMER1_BASE, DEVICE_SYSCLK_FREQ, 500000);

    // Timer1 시작 (카운터 동작 시작)
    CPUTimer_startTimer(CPUTIMER1_BASE);

    // 카운터 값을 저장할 문자열 버퍼
    char msg[50];
    // 메인 루프: 타이머 값 모니터링
    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 전송 방지
        DEVICE_DELAY_US(100000);
    }
}

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

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

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

#include "driverlib.h"       // TI DriverLib 헤더 파일 포함
#include "device.h"          // 디바이스별 설정(device.h) 포함

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

// 각 타이머의 인터럽트 발생 횟수를 저장하는 전역 변수
volatile uint32_t timer0Count = 0, timer1Count = 0, timer2Count = 0;

void main(void)
{
    // 디바이스 클럭 및 주변 장치 초기화
    Device_init();
    // GPIO 초기화 (이 예제에서는 GPIO 사용 없음, 필요 시 추가)
    Device_initGPIO();

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

    // 각 타이머 인터럽트를 ISR에 등록
    Interrupt_register(INT_TINT0, &timer0ISR); // Timer0 인터럽트
    Interrupt_register(INT_TINT1, &timer1ISR); // Timer1 인터럽트
    Interrupt_register(INT_TINT2, &timer2ISR); // Timer2 인터럽트

    // 각 타이머 인터럽트 활성화
    Interrupt_enable(INT_TINT0);
    Interrupt_enable(INT_TINT1);
    Interrupt_enable(INT_TINT2);

    // 모든 CPU 타이머 초기화
    CPUTimer_initTimer(CPUTIMER0_BASE); // Timer0 초기화
    CPUTimer_initTimer(CPUTIMER1_BASE); // Timer1 초기화
    CPUTimer_initTimer(CPUTIMER2_BASE); // Timer2 초기화

    // 타이머 설정: 각각 1초, 2초, 4초 주기
    CPUTimer_configTimer(CPUTIMER0_BASE, DEVICE_SYSCLK_FREQ, 1000000); // 1초
    CPUTimer_configTimer(CPUTIMER1_BASE, DEVICE_SYSCLK_FREQ, 2000000); // 2초
    CPUTimer_configTimer(CPUTIMER2_BASE, DEVICE_SYSCLK_FREQ, 4000000); // 4초

    // Timer2의 프리스케일러 설정: 분주비 2 (TDDR = 1)
    CPUTimer_setPreScaler(CPUTIMER2_BASE, 1);

    // 각 타이머의 인터럽트 활성화
    CPUTimer_enableInterrupt(CPUTIMER0_BASE);
    CPUTimer_enableInterrupt(CPUTIMER1_BASE);
    CPUTimer_enableInterrupt(CPUTIMER2_BASE);

    // 전역 인터럽트 활성화
    Interrupt_enableMaster();

    // 모든 타이머 시작
    CPUTimer_startTimer(CPUTIMER0_BASE);
    CPUTimer_startTimer(CPUTIMER1_BASE);
    CPUTimer_startTimer(CPUTIMER2_BASE);

    // 무한 루프: 인터럽트가 작업 처리
    for(;;)
    {
        // 디버깅 시 timer0Count, timer1Count, timer2Count 확인 가능
    }
}

// Timer0 ISR: 1초마다 호출
__interrupt void timer0ISR(void)
{
    // Timer0 인터럽트 카운터 증가
    timer0Count++;
    // 오버플로우 플래그 클리어
    CPUTimer_clearOverflowFlag(CPUTIMER0_BASE);
    // PIE 그룹 1 인터럽트 확인
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

// Timer1 ISR: 2초마다 호출
__interrupt void timer1ISR(void)
{
    // Timer1 인터럽트 카운터 증가
    timer1Count++;
    // 오버플로우 플래그 클리어
    CPUTimer_clearOverflowFlag(CPUTIMER1_BASE);
    // PIE 그룹 13 인터럽트 확인
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP13);
}

// Timer2 ISR: 4초마다 호출
__interrupt void timer2ISR(void)
{
    // Timer2 인터럽트 카운터 증가
    timer2Count++;
    // 오버플로우 플래그 클리어
    CPUTimer_clearOverflowFlag(CPUTIMER2_BASE);
    // PIE 그룹 14 인터럽트 확인
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP14);
}

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

반응형