본문 바로가기
MCU/C2000

TMS320F28388D DSP eQEP 사용법: DriverLib API로 eQEP 설정 및 코드(수정)

by linuxgo 2025. 8. 17.

1. TMS320F28388D eQEP 개요

TMS320F28388D는 Texas Instruments의 C2000 시리즈에 속하는 고성능 32비트 마이크로컨트롤러로, 최대 4개의 eQEP(Enhanced Quadrature Encoder Pulse) 모듈을 제공합니다. eQEP 모듈은 로터리 인코더 또는 리니어 인코더를 사용하여 모터의 위치, 속도, 방향을 정밀하게 측정하는 데 최적화되어 있습니다. 이는 모터 제어, 로보틱스, 산업 자동화 등에서 필수적인 기능을 제공합니다.

eQEP 모듈의 주요 특징

  • 쿼드러처 디코딩: A, B, I(인덱스) 신호를 분석하여 위치와 방향을 감지.
  • 위치 카운터: 32비트 카운터로 고해상도 위치 추적 가능.
  • 속도 계산: 단위 시간당 펄스 수 또는 펄스 간 시간을 통해 속도 계산.
  • 인덱스 및 스트로브: 인덱스 펄스로 절대 위치 동기화, 스트로브 신호로 특정 이벤트 감지.
  • 타이머: 참조 클럭을 사용하여 주기적 속도 계산 및 인터럽트 생성.
  • 에러 감지: 쿼드러처 신호의 위상 오류 감지.
  • 클럭: 시스템 클럭(최대 200MHz)을 기반으로 동작, 프리스케일러로 조정 가능.

DriverLib API는 복잡한 레지스터 조작을 추상화하여 eQEP 설정을 간소화합니다.

2. 주요 eQEP DriverLib API 함수

아래는 TMS320F28388D의 eQEP 모듈을 제어하기 위해 자주 사용되는 DriverLib API 함수입니다.

2.1. eQEP 기본 설정 관련 함수

  • EQEP_enableModule(base): eQEP 모듈을 활성화하여 동작 시작.
  • EQEP_disableModule(base): eQEP 모듈을 비활성화하여 동작 중지.
  • EQEP_setDecoderConfig(base, config): 쿼드러처 디코더 설정(4x/2x 디코딩, A/B 신호 스왑 여부).
  • EQEP_setPositionCounterConfig(base, mode, maxCount): 위치 카운터 동작 모드(리셋 조건) 및 최대 카운트 설정.
  • EQEP_setPositionInitMode(base, initMode): 위치 카운터 초기화 조건(예: 인덱스 펄스) 설정.

2.2. 속도 계산 관련 함수

  • EQEP_enableUnitTimer(base, period): 단위 타이머 활성화 및 주기 설정(속도 계산용).
  • EQEP_setCaptureConfig(base, prescale, eventPrescindale): 캡처 유닛 설정(펄스 간 시간 측정).
  • EQEP_enableCompare(base, value): 위치 비교 이벤트 설정.

2.3. 인터럽트 관련 함수

  • EQEP_enableInterrupt(base, intFlags): 인터럽트 활성화(예: 위치 오버플로우, 단위 타이머).
  • EQEP_clearInterruptStatus(base, intFlags): 인터럽트 플래그 지우기.
  • Interrupt_register(intNumber, handler): 인터럽트 서비스 루틴(ISR) 등록.

2.4. 인덱스 및 스트로브 관련 함수

  • EQEP_setStrobeSource(base, source): 스트로브 입력 소스 설정.

3. eQEP 설정 및 동작 원리

  1. 시스템 초기화: 시스템 클럭, GPIO, 인터럽트 모듈 초기화(Device_init(), Device_initGPIO()).
  2. eQEP 모듈 설정: 클럭 활성화, 디코더 설정, 위치 카운터, 단위 타이머 구성.
  3. 인터럽트 설정(선택): 위치 카운터 오버플로우 또는 단위 타이머 인터럽트 활성화.
  4. 인덱스 및 캡처 설정(선택): 인덱스 펄스 또는 펄스 캡처 설정.
  5. eQEP 활성화: eQEP 모듈을 활성화하여 인코더 신호 처리 시작.

4. eQEP 예제 코드

아래는 C2000Ware의 DriverLib를 기반으로 작성된 eQEP 예제 코드입니다. 각 설정값은 계산식을 통해 도출되며, 상세한 주석을 포함하여 코드 가독성을 높였습니다. GPIO 설정은 별도의 initGPIO() 함수로 분리되어 있으며, 모든 코드는 Code Composer Studio(CCS)에서 실행 가능합니다.

MS320F28388D DSP eQEP

4.1. 예제 1: 기본 위치 측정

eQEP1을 사용하여 쿼드러처 인코더의 위치를 측정합니다.

#include "driverlib.h"
#include "device.h"
#include "eqep.h"
#include <string.h>
#include <stdio.h>

// 디버깅용 상태 변수
volatile uint32_t eqepStatus = 0; // 0: 초기화 완료, 1: eQEP 동작 중, 0xFFFF: 오류
volatile int32_t position = 0;    // 현재 위치 카운터 값
volatile float velocity = 0.0f;   // 속도 (pulses/sec)

// 시스템 클럭 및 인코더 설정
#define SYSTEM_CLOCK_HZ 200000000 // 200MHz 시스템 클럭
#define ENCODER_PPR     1000      // 인코더 PPR
#define MAX_COUNT       (ENCODER_PPR * 4) // 4x 디코딩 최대 카운트
#define UNIT_PERIOD     1000000   // 단위 타이머 주기 (1초)

// UART 설정
#define UART_BAUDRATE   115200
#define UART_BASE       SCIA_BASE

// 인터럽트 핸들러 선언
__interrupt void eqep1ISR(void);

// GPIO 초기화
void initGPIO(void)
{
    // GPIO10을 eQEP1_A로 설정
    GPIO_setPinConfig(GPIO_10_EQEP1_A);
    GPIO_setDirectionMode(10, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(10, GPIO_PIN_TYPE_PULLUP);

    // GPIO11을 eQEP1_B로 설정
    GPIO_setPinConfig(GPIO_11_EQEP1_B);
    GPIO_setDirectionMode(11, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(11, GPIO_PIN_TYPE_PULLUP);

    // 디버깅용 LED (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(31, 0);
}

// UART 초기화
void initUART(void)
{
    // GPIO42, GPIO43을 SCIA_TX, SCIA_RX로 설정
    GPIO_setPinConfig(GPIO_42_SCIA_TX);
    GPIO_setPinConfig(GPIO_43_SCIA_RX);
    GPIO_setDirectionMode(42, GPIO_DIR_MODE_OUT);
    GPIO_setDirectionMode(43, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(42, GPIO_PIN_TYPE_PULLUP);
    GPIO_setPadConfig(43, GPIO_PIN_TYPE_PULLUP);

    // UART 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_SCIA);

    // UART 설정: 115200 baud, 8-N-1
    SCI_setConfig(UART_BASE, DEVICE_LSPCLK_FREQ, UART_BAUDRATE, 
                  (SCI_CONFIG_WLEN_8 | SCI_CONFIG_STOP_ONE | SCI_CONFIG_PAR_NONE));
    SCI_enableModule(UART_BASE);
}

// eQEP1 초기화
void initEQEP(void)
{
    // eQEP1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);

    // 입력 소스 설정
    EQEP_SourceSelect sourceConfig = {
        EQEP_SOURCE_DEVICE_PIN, // QEPA
        EQEP_SOURCE_DEVICE_PIN, // QEPB
        EQEP_SOURCE_DEVICE_PIN  // Index
    };
    EQEP_selectSource(EQEP1_BASE, sourceConfig);

    // 입력 극성 설정 (반전 없음)
    EQEP_setInputPolarity(EQEP1_BASE, false, false, false, false);

    // 쿼드러처 디코더 설정: 4x 디코딩, 스왑 없음
    EQEP_setDecoderConfig(EQEP1_BASE, EQEP_CONFIG_2X_RESOLUTION | 
                                     EQEP_CONFIG_QUADRATURE | 
                                     EQEP_CONFIG_NO_SWAP | 
                                     EQEP_CONFIG_IGATE_DISABLE);

    // 위치 카운터 설정: 인덱스 펄스에서 리셋
    EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_IDX, MAX_COUNT);

    // 래치 모드 설정
    EQEP_setLatchMode(EQEP1_BASE, EQEP_LATCH_UNIT_TIME_OUT | 
                                 EQEP_LATCH_RISING_INDEX);

    // 단위 타이머 설정
    EQEP_enableUnitTimer(EQEP1_BASE, SYSTEM_CLOCK_HZ / 1000000);
    EQEP_loadUnitTimer(EQEP1_BASE, UNIT_PERIOD);

    // 캡처 유닛 설정
    EQEP_setCaptureConfig(EQEP1_BASE, EQEP_CAPTURE_CLK_DIV_8, 
                                     EQEP_UNIT_POS_EVNT_DIV_8);
    EQEP_enableCapture(EQEP1_BASE);

    // 인터럽트 설정
    EQEP_enableInterrupt(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT | 
                                     EQEP_INT_POS_CNT_ERROR | 
                                     EQEP_INT_PHASE_ERROR);
    Interrupt_register(INT_EQEP1, &eqep1ISR);
    Interrupt_enable(INT_EQEP1);

    // eQEP 모듈 활성화
    EQEP_enableModule(EQEP1_BASE);

    eqepStatus = 1;
}

// 인터럽트 서비스 루틴
__interrupt void eqep1ISR(void)
{
    // 인터럽트 상태 확인
    uint16_t intFlags = EQEP_getInterruptStatus(EQEP1_BASE);

    // 쿼드러처 에러 확인
    if (EQEP_getError(EQEP1_BASE) || (intFlags & EQEP_INT_POS_CNT_ERROR) || 
        (intFlags & EQEP_INT_PHASE_ERROR))
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        EQEP_clearInterruptStatus(EQEP1_BASE, intFlags);
        return;
    }

    // 위치 및 속도 계산
    position = EQEP_getPosition(EQEP1_BASE);
    uint16_t capturePeriod = EQEP_getCapturePeriod(EQEP1_BASE);
    velocity = (capturePeriod != 0) ? (float)(SYSTEM_CLOCK_HZ / 8.0f) / capturePeriod : 0.0f;

    // UART 출력
    char buffer[64];
    snprintf(buffer, sizeof(buffer), "Pos: %ld, Vel: %.2f pulses/sec, Status: 0x%X\r\n", 
             position, velocity, EQEP_getStatus(EQEP1_BASE));
    SCI_writeCharArray(UART_BASE, (uint16_t*)buffer, strlen(buffer));

    // 인터럽트 플래그 클리어
    EQEP_clearInterruptStatus(EQEP1_BASE, intFlags);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);
}

void main(void)
{
    // 시스템 초기화 (PLL, 클럭 등 설정, Watchdog은 비활성화 상태로 유지)
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != SYSTEM_CLOCK_HZ)
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // GPIO, UART, eQEP 초기화
    initGPIO();
    initUART();
    initEQEP();

    // 초기화 오류 확인
    if (eqepStatus != 1)
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        ESTOP0;
    }

    // Watchdog 설정 및 활성화
    // Device_init에서 Watchdog은 비활성화 상태이므로 명시적으로 활성화
    SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_1024); // INTOSC1 / 1024
    SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_1);   // PREDIVCLK / 1
    SysCtl_enableWatchdog(); // Watchdog 활성화

    // 글로벌 인터럽트 활성화
    EINT;

    // 메인 루프
    for(;;)
    {
        SysCtl_serviceWatchdog(); // Watchdog 서비스
        GPIO_writePin(31, (eqepStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000);
    }
}

설명:

  • 기능: eQEP1 모듈을 사용하여 쿼드러처 인코더의 위치를 실시간으로 측정.
  • 설정:
    • 디코더: 4x 모드로 설정하여 A, B 신호의 모든 에지에서 카운트 (최대 해상도).
    • 위치 카운터: 리셋 없이 연속 카운트, 최대값 0xFFFFFFFF.
  • GPIO:
    • GPIO0: eQEP1A (A 신호 입력).
    • GPIO1: eQEP1B (B 신호 입력).
    • GPIO31: 디버깅용 LED.
  • 출력: 위치 값은 position 변수에 저장, 정상 동작 시 LED ON.
  • 용도: 모터 위치 추적, 로봇 위치 제어.

4.2. 예제 2: 속도 계산

eQEP1의 단위 타이머를 사용하여 인코더의 회전 속도를 계산합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수
volatile uint32_t eqepStatus = 0; // 0: 초기화 완료, 1: eQEP 동작 중, 0xFFFF: 오류
volatile int32_t position = 0;    // 현재 위치 카운터 값
volatile uint32_t velocity = 0;   // 속도 (펄스/단위 시간)
static volatile int32_t prevPosition = 0; // 이전 위치 저장 (속도 계산용)

// 시스템 클럭 및 타이머 주기 정의
#define SYSTEM_CLOCK_HZ 200000000 // 200MHz 시스템 클럭
#define UNIT_TIMER_PERIOD (SYSTEM_CLOCK_HZ / 1000) // 1ms 주기 = 200MHz / 1000 = 200000 클럭
#define ENCODER_PPR     1000      // 인코더 PPR
#define MAX_COUNT       (ENCODER_PPR * 4) // 4x 디코딩 최대 카운트

// 인터럽트 서비스 루틴 (단위 타이머)
__interrupt void eqep1ISR(void)
{
    // 인터럽트 상태 확인
    uint16_t intFlags = EQEP_getInterruptStatus(EQEP1_BASE);

    // 쿼드러처 에러 확인
    if (EQEP_getError(EQEP1_BASE) || (intFlags & EQEP_INT_POS_CNT_ERROR) || 
        (intFlags & EQEP_INT_PHASE_ERROR))
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        EQEP_clearInterruptStatus(EQEP1_BASE, intFlags);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);
        return;
    }

    // 위치 및 속도 계산
    position = EQEP_getPosition(EQEP1_BASE);
    velocity = position - prevPosition; // 1ms 동안의 펄스 수 (펄스/1ms)
    prevPosition = position;           // 이전 위치 업데이트

    // 인터럽트 플래그 지우기
    EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);

    // 상태 업데이트
    eqepStatus = 1;
}

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO20을 eQEP1_A로 설정 (pin_map.h: 0x00080801U)
    GPIO_setPinConfig(GPIO_20_EQEP1_A);
    GPIO_setDirectionMode(20, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(20, GPIO_PIN_TYPE_PULLUP);

    // GPIO21을 eQEP1_B로 설정 (pin_map.h: 0x00080A01U)
    GPIO_setPinConfig(GPIO_21_EQEP1_B);
    GPIO_setDirectionMode(21, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(21, GPIO_PIN_TYPE_PULLUP);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(31, 0); // 초기 LED OFF
}

// eQEP1 초기화
void initEQEP(void)
{
    // eQEP1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);

    // 입력 소스 설정
    EQEP_SourceSelect sourceConfig = {
        EQEP_SOURCE_DEVICE_PIN, // QEPA
        EQEP_SOURCE_DEVICE_PIN, // QEPB
        EQEP_SOURCE_DEVICE_PIN  // Index
    };
    EQEP_selectSource(EQEP1_BASE, sourceConfig);

    // 입력 극성 설정 (반전 없음)
    EQEP_setInputPolarity(EQEP1_BASE, false, false, false, false);

    // 쿼드러처 디코더 설정: 4x 디코딩, 스왑 없음
    EQEP_setDecoderConfig(EQEP1_BASE, EQEP_CONFIG_2X_RESOLUTION | EQEP_CONFIG_QUADRATURE | 
                                     EQEP_CONFIG_NO_SWAP | EQEP_CONFIG_IGATE_DISABLE);

    // 위치 카운터 설정: 최대 위치에서 리셋, 최대 카운트 0xFFFFFFFF
    // EQEP_POSITION_RESET_MAX_POS는 위치 카운터가 0xFFFFFFFF에 도달할 때만 리셋
    EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_MAX_POS, 0xFFFFFFFF);

    // 단위 타이머 설정: 1ms 주기
    EQEP_enableUnitTimer(EQEP1_BASE, UNIT_TIMER_PERIOD);

    // 인터럽트 설정: 단위 타이머 타임아웃 시 발생
    EQEP_enableInterrupt(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT | 
                                     EQEP_INT_POS_CNT_ERROR | EQEP_INT_PHASE_ERROR);
    Interrupt_register(INT_EQEP1, &eqep1ISR);
    Interrupt_enable(INT_EQEP1);

    // eQEP 모듈 활성화
    EQEP_enableModule(EQEP1_BASE);

    eqepStatus = 1;
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화 (Watchdog은 비활성화 상태로 유지)
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != SYSTEM_CLOCK_HZ)
    {
        eqepStatus = 0xFFFF; // 오류 상태
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // eQEP 관련 GPIO 및 모듈 초기화
    initGPIO();
    initEQEP();

    // 초기화 오류 확인
    if (eqepStatus != 1)
    {
        eqepStatus = 0xFFFF; // 초기화 실패
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // Watchdog 설정 및 활성화
    SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_1024); // INTOSC1 / 1024
    SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_1);   // PREDIVCLK / 1
    SysCtl_enableWatchdog(); // Watchdog 활성화

    // 글로벌 인터럽트 활성화
    EINT;

    // 무한 루프
    for(;;)
    {
        // Watchdog 서비스
        SysCtl_serviceWatchdog();

        // 현재 위치 카운터 읽기
        position = EQEP_getPosition(EQEP1_BASE);

        // 디버깅용: 상태 표시
        GPIO_writePin(31, (eqepStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000); // 1초 대기
    }
}

설명:

  • 기능: eQEP1의 단위 타이머를 사용하여 1ms마다 인코더의 속도를 계산.
  • 설정:
    • 디코더: 4x 모드로 최대 해상도 제공.
    • 단위 타이머: 주기 = 200MHz / 1000 = 200000 클럭 (1ms).
    • 인터럽트: 단위 타이머 타임아웃 시 속도 계산.
  • GPIO: GPIO0(eQEP1A), GPIO1(eQEP1B), GPIO31(LED).
  • 출력: 속도는 velocity 변수에 저장 (펄스/1ms), 정상 동작 시 LED ON.
  • 용도: 모터 속도 제어, 속도 피드백 시스템.

4.3. 예제 3: 인덱스 이벤트를 사용한 위치 초기화

eQEP1의 인덱스 신호를 사용하여 위치 카운터를 초기화합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수
volatile uint32_t eqepStatus = 0; // 0: 초기화 완료, 1: eQEP 동작 중, 0xFFFF: 오류
volatile int32_t position = 0;    // 현재 위치 카운터 값
volatile uint32_t velocity = 0;   // 속도 (펄스/단위 시간)
static volatile int32_t prevPosition = 0; // 이전 위치 저장 (속도 계산용)

// 시스템 클럭 및 타이머 주기 정의
#define SYSTEM_CLOCK_HZ 200000000 // 200MHz 시스템 클럭
#define UNIT_TIMER_PERIOD (SYSTEM_CLOCK_HZ / 1000) // 1ms 주기 = 200MHz / 1000 = 200000 클럭
#define ENCODER_PPR     1000      // 인코더 PPR
#define MAX_COUNT       (ENCODER_PPR * 4) // 4x 디코딩 최대 카운트

// 인터럽트 서비스 루틴 (단위 타이머)
__interrupt void eqep1ISR(void)
{
    // 인터럽트 상태 확인
    uint16_t intFlags = EQEP_getInterruptStatus(EQEP1_BASE);

    // 쿼드러처 에러 확인
    if (EQEP_getError(EQEP1_BASE) || (intFlags & EQEP_INT_POS_CNT_ERROR) ||
        (intFlags & EQEP_INT_PHASE_ERROR))
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        EQEP_clearInterruptStatus(EQEP1_BASE, intFlags);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);
        return;
    }

    // 위치 및 속도 계산
    position = EQEP_getPosition(EQEP1_BASE);
    velocity = position - prevPosition; // 1ms 동안의 펄스 수 (펄스/1ms)
    prevPosition = position;           // 이전 위치 업데이트

    // 인터럽트 플래그 지우기
    EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);

    // 상태 업데이트
    eqepStatus = 1;
}

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO20을 eQEP1_A로 설정 (pin_map.h: 0x00080801U)
    GPIO_setPinConfig(GPIO_20_EQEP1_A);
    GPIO_setDirectionMode(20, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(20, GPIO_PIN_TYPE_PULLUP);

    // GPIO21을 eQEP1_B로 설정 (pin_map.h: 0x00080A01U)
    GPIO_setPinConfig(GPIO_21_EQEP1_B);
    GPIO_setDirectionMode(21, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(21, GPIO_PIN_TYPE_PULLUP);

    // GPIO13을 eQEP1_I로 설정 (pin_map.h: 0x00061A05U)
    GPIO_setPinConfig(GPIO_23_EQEP1_INDEX);
    GPIO_setDirectionMode(13, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(13, GPIO_PIN_TYPE_PULLUP);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(31, 0); // 초기 LED OFF
}

// eQEP1 초기화
void initEQEP(void)
{
    // eQEP1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);

    // 입력 소스 설정
    EQEP_SourceSelect sourceConfig = {
        EQEP_SOURCE_DEVICE_PIN, // QEPA
        EQEP_SOURCE_DEVICE_PIN, // QEPB
        EQEP_SOURCE_DEVICE_PIN  // Index
    };
    EQEP_selectSource(EQEP1_BASE, sourceConfig);

    // 입력 극성 설정 (반전 없음)
    EQEP_setInputPolarity(EQEP1_BASE, false, false, false, false);

    // 쿼드러처 디코더 설정: 4x 디코딩, 스왑 없음
    EQEP_setDecoderConfig(EQEP1_BASE, EQEP_CONFIG_2X_RESOLUTION | EQEP_CONFIG_QUADRATURE |
                                     EQEP_CONFIG_NO_SWAP | EQEP_CONFIG_IGATE_DISABLE);

    // 인덱스 이벤트 설정: 상승 에지에서 위치 카운터 초기화
    EQEP_setPositionInitMode(EQEP1_BASE, EQEP_INIT_RISING_INDEX);

    // 위치 카운터 설정: 인덱스 펄스에서 리셋, 최대 카운트 0xFFFFFFFF
    EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_IDX, 0xFFFFFFFF);

    // 단위 타이머 설정: 1ms 주기
    EQEP_enableUnitTimer(EQEP1_BASE, UNIT_TIMER_PERIOD);

    // 인터럽트 설정: 단위 타이머 타임아웃 시 발생
    EQEP_enableInterrupt(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT |
                                     EQEP_INT_POS_CNT_ERROR | EQEP_INT_PHASE_ERROR);
    Interrupt_register(INT_EQEP1, &eqep1ISR);
    Interrupt_enable(INT_EQEP1);

    // eQEP 모듈 활성화
    EQEP_enableModule(EQEP1_BASE);

    eqepStatus = 1;
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화 (Watchdog은 비활성화 상태로 유지)
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != SYSTEM_CLOCK_HZ)
    {
        eqepStatus = 0xFFFF; // 오류 상태
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // eQEP 관련 GPIO 및 모듈 초기화
    initGPIO();
    initEQEP();

    // 초기화 오류 확인
    if (eqepStatus != 1)
    {
        eqepStatus = 0xFFFF; // 초기화 실패
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // Watchdog 설정 및 활성화
    SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_1024); // INTOSC1 / 1024
    SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_1);   // PREDIVCLK / 1
    SysCtl_enableWatchdog(); // Watchdog 활성화

    // 글로벌 인터럽트 활성화
    EINT;

    // 무한 루프
    for(;;)
    {
        // Watchdog 서비스
        SysCtl_serviceWatchdog();

        // 현재 위치 카운터 읽기
        position = EQEP_getPosition(EQEP1_BASE);

        // 디버깅용: 상태 표시
        GPIO_writePin(31, (eqepStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000); // 1초 대기
    }
}

설명:

  • 기능: eQEP1의 인덱스 신호를 사용하여 위치 카운터를 0으로 초기화.
  • 설정:
    • 디코더: 4x 모드로 최대 해상도.
    • 인덱스: 상승 에지에서 위치 카운터 리셋.
    • 위치 카운터: 인덱스 펄스에서 리셋, 최대값 0xFFFFFFFF.
  • GPIO:
    • GPIO0: eQEP1A (A 신호).
    • GPIO1: eQEP1B (B 신호).
    • GPIO2: eQEP1I (인덱스 신호).
    • GPIO31: LED.
  • 출력: 인덱스 펄스 발생 시 position이 0으로 리셋, 정상 동작 시 LED ON.
  • 용도: 절대 위치 동기화가 필요한 애플리케이션.

4.4. 예제 4: 캡처 유닛을 사용한 펄스 간 시간 측정

eQEP1의 캡처 유닛을 사용하여 쿼드러처 펄스 간 시간을 측정하여 속도를 계산합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수
volatile uint32_t eqepStatus = 0; // 0: 초기화 완료, 1: eQEP 동작 중, 0xFFFF: 오류
volatile int32_t position = 0;    // 현재 위치 카운터 값
volatile uint32_t velocity = 0;   // 속도 (펄스/초)
static volatile int32_t prevPosition = 0; // 이전 위치 저장 (속도 계산용)

// 시스템 클럭 및 타이머 주기 정의
#define SYSTEM_CLOCK_HZ 200000000 // 200MHz 시스템 클럭
#define UNIT_TIMER_PERIOD (SYSTEM_CLOCK_HZ / 1000) // 1ms 주기 = 200MHz / 1000 = 200000 클럭
#define ENCODER_PPR     1000      // 인코더 PPR
#define MAX_COUNT       (ENCODER_PPR * 4) // 4x 디코딩 최대 카운트

// 인터럽트 서비스 루틴 (단위 타이머)
__interrupt void eqep1ISR(void)
{
    // 인터럽트 상태 확인
    uint16_t intFlags = EQEP_getInterruptStatus(EQEP1_BASE);

    // 쿼드러처 에러 확인
    if (EQEP_getError(EQEP1_BASE) || (intFlags & EQEP_INT_POS_CNT_ERROR) || 
        (intFlags & EQEP_INT_PHASE_ERROR))
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        EQEP_clearInterruptStatus(EQEP1_BASE, intFlags);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);
        return;
    }

    // 위치 및 속도 계산
    position = EQEP_getPosition(EQEP1_BASE);
    velocity = (position - prevPosition) * 1000; // 펄스/1ms * 1000 = 펄스/초
    prevPosition = position;                    // 이전 위치 업데이트

    // 인터럽트 플래그 지우기
    EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);

    // 상태 업데이트
    eqepStatus = 1;
}

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO20을 eQEP1_A로 설정 (pin_map.h: 0x00080801U)
    GPIO_setPinConfig(GPIO_20_EQEP1_A);
    GPIO_setDirectionMode(20, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(20, GPIO_PIN_TYPE_PULLUP);

    // GPIO21을 eQEP1_B로 설정 (pin_map.h: 0x00080A01U)
    GPIO_setPinConfig(GPIO_21_EQEP1_B);
    GPIO_setDirectionMode(21, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(21, GPIO_PIN_TYPE_PULLUP);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(31, 0); // 초기 LED OFF
}

// eQEP1 초기화
void initEQEP(void)
{
    // eQEP1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);

    // 입력 소스 설정
    EQEP_SourceSelect sourceConfig = {
        EQEP_SOURCE_DEVICE_PIN, // QEPA
        EQEP_SOURCE_DEVICE_PIN, // QEPB
        EQEP_SOURCE_DEVICE_PIN  // Index (미사용)
    };
    EQEP_selectSource(EQEP1_BASE, sourceConfig);

    // 입력 극성 설정 (반전 없음)
    EQEP_setInputPolarity(EQEP1_BASE, false, false, false, false);

    // 쿼드러처 디코더 설정: 4x 디코딩, 스왑 없음
    EQEP_setDecoderConfig(EQEP1_BASE, EQEP_CONFIG_2X_RESOLUTION | EQEP_CONFIG_QUADRATURE | 
                                     EQEP_CONFIG_NO_SWAP | EQEP_CONFIG_IGATE_DISABLE);

    // 위치 카운터 설정: 최대 위치에서 리셋, 최대 카운트 0xFFFFFFFF
    EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_MAX_POS, 0xFFFFFFFF);

    // 단위 타이머 설정: 1ms 주기
    EQEP_enableUnitTimer(EQEP1_BASE, UNIT_TIMER_PERIOD);

    // 인터럽트 설정: 단위 타이머 타임아웃 시 발생
    EQEP_enableInterrupt(EQEP1_BASE, EQEP_INT_UNIT_TIME_OUT | EQEP_INT_POS_CNT_ERROR | EQEP_INT_PHASE_ERROR);
    Interrupt_register(INT_EQEP1, &eqep1ISR);
    Interrupt_enable(INT_EQEP1);

    // eQEP 모듈 활성화
    EQEP_enableModule(EQEP1_BASE);

    eqepStatus = 1;
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화 (Watchdog은 비활성화 상태로 유지)
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != SYSTEM_CLOCK_HZ)
    {
        eqepStatus = 0xFFFF; // 오류 상태
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // eQEP 관련 GPIO 및 모듈 초기화
    initGPIO();
    initEQEP();

    // 초기화 오류 확인
    if (eqepStatus != 1)
    {
        eqepStatus = 0xFFFF; // 초기화 실패
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // Watchdog 설정 및 활성화
    SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_1024); // INTOSC1 / 1024
    SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_1);   // PREDIVCLK / 1
    SysCtl_enableWatchdog(); // Watchdog 활성화

    // 글로벌 인터럽트 활성화
    EINT;

    // 무한 루프
    for(;;)
    {
        // Watchdog 서비스
        SysCtl_serviceWatchdog();

        // 디버깅용: 상태 표시
        GPIO_writePin(31, (eqepStatus == 1) ? 1 : 0);
        DEVICE_DELAY_US(1000000); // 1초 대기
    }
}

설명:

  • 기능: eQEP1의 캡처 유닛을 사용하여 쿼드러처 펄스 간 시간을 측정, 속도 계산에 활용.
  • 설정:
    • 디코더: 4x 모드로 최대 해상도.
    • 캡처 유닛: 프리스케일러 = 1, 이벤트 프리스케일러 = 1 (모든 펄스 캡처).
    • 인터럽트: 캡처 이벤트 발생 시 펄스 간 시간 업데이트.
  • GPIO: GPIO0(eQEP1A), GPIO1(eQEP1B), GPIO31(LED).
  • 출력: 펄스 간 시간은 capturePeriod 변수에 저장 (클럭 수), 정상 동작 시 LED ON.
  • 용도: 저속 모터 또는 고정밀 속도 측정.

4.5. 예제 5: 위치 비교 이벤트

eQEP1의 위치 비교 기능을 사용하여 특정 위치에서 이벤트를 발생시킵니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수
volatile uint32_t eqepStatus = 0; // 0: 초기화 완료, 1: eQEP 동작 중, 0xFFFF: 오류
volatile int32_t position = 0;    // 현재 위치 카운터 값
volatile bool compareEvent = false; // 위치 비교 이벤트 플래그

// 시스템 클럭 및 비교 위치 정의
#define SYSTEM_CLOCK_HZ 200000000 // 200MHz 시스템 클럭
#define COMPARE_POSITION 1000     // 비교 위치: 1000 펄스
#define ENCODER_PPR     1000      // 인코더 PPR
#define MAX_COUNT       (ENCODER_PPR * 4) // 4x 디코딩 최대 카운트

// 인터럽트 서비스 루틴 (위치 비교 이벤트)
__interrupt void eqep1ISR(void)
{
    // 인터럽트 상태 확인
    uint16_t intFlags = EQEP_getInterruptStatus(EQEP1_BASE);

    // 쿼드러처 에러 확인
    if (EQEP_getError(EQEP1_BASE) || (intFlags & EQEP_INT_POS_CNT_ERROR) || 
        (intFlags & EQEP_INT_PHASE_ERROR))
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        EQEP_clearInterruptStatus(EQEP1_BASE, intFlags);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);
        return;
    }

    // 위치 비교 이벤트 발생
    if (intFlags & EQEP_INT_POS_COMP_READY)
    {
        compareEvent = true;
    }

    // 인터럽트 플래그 지우기
    EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_POS_COMP_READY | EQEP_INT_POS_CNT_ERROR | EQEP_INT_PHASE_ERROR);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);

    // 상태 업데이트
    eqepStatus = 1;
}

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO20을 eQEP1_A로 설정 (pin_map.h: 0x00080801U)
    GPIO_setPinConfig(GPIO_20_EQEP1_A);
    GPIO_setDirectionMode(20, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(20, GPIO_PIN_TYPE_PULLUP);

    // GPIO21을 eQEP1_B로 설정 (pin_map.h: 0x00080A01U)
    GPIO_setPinConfig(GPIO_21_EQEP1_B);
    GPIO_setDirectionMode(21, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(21, GPIO_PIN_TYPE_PULLUP);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(31, 0); // 초기 LED OFF
}

// eQEP1 초기화
void initEQEP(void)
{
    // eQEP1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);

    // 입력 소스 설정
    EQEP_SourceSelect sourceConfig = {
        EQEP_SOURCE_DEVICE_PIN, // QEPA
        EQEP_SOURCE_DEVICE_PIN, // QEPB
        EQEP_SOURCE_DEVICE_PIN  // Index (미사용)
    };
    EQEP_selectSource(EQEP1_BASE, sourceConfig);

    // 입력 극성 설정 (반전 없음)
    EQEP_setInputPolarity(EQEP1_BASE, false, false, false, false);

    // 쿼드러처 디코더 설정: 4x 디코딩, 스왑 없음
    EQEP_setDecoderConfig(EQEP1_BASE, EQEP_CONFIG_2X_RESOLUTION | EQEP_CONFIG_QUADRATURE | 
                                     EQEP_CONFIG_NO_SWAP | EQEP_CONFIG_IGATE_DISABLE);

    // 위치 카운터 설정: 최대 위치에서 리셋, 최대 카운트 0xFFFFFFFF
    EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_MAX_POS, 0xFFFFFFFF);

    // 위치 비교 설정: COMPARE_POSITION (1000 펄스)에서 이벤트 발생
    EQEP_setCompareConfig(EQEP1_BASE, COMPARE_POSITION, 0, EQEP_COMPARE_NO_SHADOW);

    // 인터럽트 설정: 위치 비교 이벤트 발생 시
    EQEP_enableInterrupt(EQEP1_BASE, EQEP_INT_POS_COMP_READY | EQEP_INT_POS_CNT_ERROR | EQEP_INT_PHASE_ERROR);
    Interrupt_register(INT_EQEP1, &eqep1ISR);
    Interrupt_enable(INT_EQEP1);

    // eQEP 모듈 활성화
    EQEP_enableModule(EQEP1_BASE);

    eqepStatus = 1;
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화 (Watchdog은 비활성화 상태로 유지)
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != SYSTEM_CLOCK_HZ)
    {
        eqepStatus = 0xFFFF; // 오류 상태
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // eQEP 관련 GPIO 및 모듈 초기화
    initGPIO();
    initEQEP();

    // 초기화 오류 확인
    if (eqepStatus != 1)
    {
        eqepStatus = 0xFFFF; // 초기화 실패
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // Watchdog 설정 및 활성화
    SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_1024); // INTOSC1 / 1024
    SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_1);   // PREDIVCLK / 1
    SysCtl_enableWatchdog(); // Watchdog 활성화

    // 글로벌 인터럽트 활성화
    EINT;

    // 무한 루프
    for(;;)
    {
        // Watchdog 서비스
        SysCtl_serviceWatchdog();

        // 현재 위치 카운터 읽기
        position = EQEP_getPosition(EQEP1_BASE);

        // 디버깅용: 상태 표시 (이벤트 발생 시 LED 깜빡임)
        GPIO_writePin(31, (compareEvent && eqepStatus == 1) ? 1 : 0);
        if (compareEvent)
        {
            compareEvent = false; // 이벤트 플래그 리셋
            DEVICE_DELAY_US(500000); // 0.5초 ON
            GPIO_writePin(31, 0);
        }
        DEVICE_DELAY_US(1000000); // 1초 대기
    }
}

설명:

  • 기능: eQEP1의 위치 비교 기능을 사용하여 특정 위치(1000 펄스)에서 이벤트를 발생.
  • 설정:
    • 디코더: 4x 모드로 최대 해상도.
    • 위치 비교: 1000 펄스에서 인터럽트 발생.
  • GPIO: GPIO0(eQEP1A), GPIO1(eQEP1B), GPIO31(LED).
  • 출력: 위치가 1000 펄스에 도달 시 compareEvent 플래그 설정, LED 0.5초 깜빡임.
  • 용도: 특정 위치에서의 동작 트리거(예: 로봇 암 정지).

4.6. 예제 6: 스트로브 신호를 사용한 이벤트 감지

eQEP1의 스트로브 신호를 사용하여 특정 이벤트를 감지합니다.

#include "driverlib.h"
#include "device.h"

// 디버깅용 상태 변수
volatile uint32_t eqepStatus = 0; // 0: 초기화 완료, 1: eQEP 동작 중, 0xFFFF: 오류
volatile bool strobeEvent = false; // 스트로브 이벤트 플래그

// 시스템 클럭 정의
#define SYSTEM_CLOCK_HZ 200000000 // 200MHz 시스템 클럭
#define ENCODER_PPR     1000      // 인코더 PPR
#define MAX_COUNT       (ENCODER_PPR * 4) // 4x 디코딩 최대 카운트

// 인터럽트 서비스 루틴 (스트로브 이벤트)
__interrupt void eqep1ISR(void)
{
    // 인터럽트 상태 확인
    uint16_t intFlags = EQEP_getInterruptStatus(EQEP1_BASE);

    // 쿼드러처 에러 확인
    if (EQEP_getError(EQEP1_BASE) || (intFlags & EQEP_INT_POS_CNT_ERROR) ||
        (intFlags & EQEP_INT_PHASE_ERROR))
    {
        eqepStatus = 0xFFFF;
        GPIO_writePin(31, 0);
        EQEP_clearInterruptStatus(EQEP1_BASE, intFlags);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);
        return;
    }

    // 스트로브 이벤트 발생
    if (intFlags & EQEP_INT_STROBE_EVNT_LATCH)
    {
        strobeEvent = true;
    }

    // 인터럽트 플래그 지우기
    EQEP_clearInterruptStatus(EQEP1_BASE, EQEP_INT_STROBE_EVNT_LATCH | EQEP_INT_POS_CNT_ERROR | EQEP_INT_PHASE_ERROR);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP5);

    // 상태 업데이트
    eqepStatus = 1;
}

// GPIO 초기화 함수
void initGPIO(void)
{
    // GPIO20을 eQEP1_A로 설정 (pin_map.h: 0x00080801U)
    GPIO_setPinConfig(GPIO_20_EQEP1_A);
    GPIO_setDirectionMode(20, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(20, GPIO_PIN_TYPE_PULLUP);

    // GPIO21을 eQEP1_B로 설정 (pin_map.h: 0x00080A01U)
    GPIO_setPinConfig(GPIO_21_EQEP1_B);
    GPIO_setDirectionMode(21, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(21, GPIO_PIN_TYPE_PULLUP);

    // GPIO54을 eQEP1_S로 설정 (pin_map.h: 0x001A0801U)
    GPIO_setPinConfig(GPIO_22_EQEP1_STROBE);
    GPIO_setDirectionMode(54, GPIO_DIR_MODE_IN);
    GPIO_setPadConfig(54, GPIO_PIN_TYPE_PULLUP);

    // 디버깅용 LED 설정 (GPIO31)
    GPIO_setPinConfig(GPIO_31_GPIO31);
    GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
    GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP);
    GPIO_writePin(31, 0); // 초기 LED OFF
}

// eQEP1 초기화
void initEQEP(void)
{
    // eQEP1 클럭 활성화
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);

    // 입력 소스 설정
    EQEP_SourceSelect sourceConfig = {
        EQEP_SOURCE_DEVICE_PIN, // QEPA
        EQEP_SOURCE_DEVICE_PIN, // QEPB
        EQEP_SOURCE_DEVICE_PIN  // Strobe
    };
    EQEP_selectSource(EQEP1_BASE, sourceConfig);

    // 입력 극성 설정: 스트로브 신호 상승 에지 (strobePolarity = false)
    EQEP_setInputPolarity(EQEP1_BASE, false, false, false, false);

    // 쿼드러처 디코더 설정: 4x 디코딩, 스왑 없음
    EQEP_setDecoderConfig(EQEP1_BASE, EQEP_CONFIG_2X_RESOLUTION | EQEP_CONFIG_QUADRATURE |
                                     EQEP_CONFIG_NO_SWAP | EQEP_CONFIG_IGATE_DISABLE);

    // 위치 카운터 설정: 최대 위치에서 리셋, 최대 카운트 0xFFFFFFFF
    EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_MAX_POS, 0xFFFFFFFF);

    // 인터럽트 설정: 스트로브 이벤트 발생 시
    EQEP_enableInterrupt(EQEP1_BASE, EQEP_INT_STROBE_EVNT_LATCH | EQEP_INT_POS_CNT_ERROR | EQEP_INT_PHASE_ERROR);
    Interrupt_register(INT_EQEP1, &eqep1ISR);
    Interrupt_enable(INT_EQEP1);

    // eQEP 모듈 활성화
    EQEP_enableModule(EQEP1_BASE);

    eqepStatus = 1;
}

void main(void)
{
    // 시스템 클럭 및 주변 장치 초기화 (Watchdog은 비활성화 상태로 유지)
    Device_init();
    Device_initGPIO();
    Interrupt_initModule();
    Interrupt_initVectorTable();

    // 시스템 클럭 확인
    uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
    if (sysClockHz != SYSTEM_CLOCK_HZ)
    {
        eqepStatus = 0xFFFF; // 오류 상태
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // eQEP 관련 GPIO 및 모듈 초기화
    initGPIO();
    initEQEP();

    // 초기화 오류 확인
    if (eqepStatus != 1)
    {
        eqepStatus = 0xFFFF; // 초기화 실패
        GPIO_writePin(31, 0); // LED OFF로 오류 표시
        ESTOP0;
    }

    // Watchdog 설정 및 활성화
    SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_1024); // INTOSC1 / 1024
    SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_1);   // PREDIVCLK / 1
    SysCtl_enableWatchdog(); // Watchdog 활성화

    // 글로벌 인터럽트 활성화
    EINT;

    // 무한 루프
    for(;;)
    {
        // Watchdog 서비스
        SysCtl_serviceWatchdog();

        // 디버깅용: 상태 표시 (스트로브 이벤트 시 LED 깜빡임)
        GPIO_writePin(31, (strobeEvent && eqepStatus == 1) ? 1 : 0);
        if (strobeEvent)
        {
            strobeEvent = false; // 이벤트 플래그 리셋
            DEVICE_DELAY_US(500000); // 0.5초 ON
            GPIO_writePin(31, 0);
        }
        DEVICE_DELAY_US(1000000); // 1초 대기
    }
}

설명:

  • 기능: eQEP1의 스트로브 신호를 사용하여 특정 이벤트 감지.
  • 설정:
    • 디코더: 4x 모드로 최대 해상도.
    • 스트로브: 상승 에지에서 인터럽트 발생.
  • GPIO: GPIO0(eQEP1A), GPIO1(eQEP1B), GPIO3(eQEP1S), GPIO31(LED).
  • 출력: 스트로브 신호 발생 시 strobeEvent 플래그 설정, LED 0.5초 깜빡임.
  • 용도: 인코더의 특정 위치 이벤트 감지(예: 기계적 정지 신호).

5. 추가 고려 사항

  • 펄스 해상도: 인코더의 PPR(Pulses Per Revolution)에 따라 최대 카운트를 계산. 예: PPR=1000, 4x 디코딩 → 최대 펄스 = 1000 * 4 = 4000.
  • 속도 계산: 단위 타이머 주기는 속도 범위에 따라 조정. 예: 고속 모터는 0.1ms, 저속은 10ms.
  • GPIO 설정: eQEP 핀은 풀업 저항 활성화로 신호 안정성 확보.
  • C2000Ware: 코드는 C2000Ware의 DriverLib 기반 (C:\ti\c2000).
  • 디버깅: Code Composer Studio의 .syscfg 툴로 eQEP 및 GPIO 설정 시각화.

키워드: TMS320F28388D, eQEP, DriverLib, C2000, 쿼드러처 인코더, 위치 측정, 속도 계산, 인덱스 이벤트, 캡처 유닛, 위치 비교, 스트로브, Code Composer Studio