본문 바로가기
MCU/C2000

TMS320F28335 DSP ePWM SPWM 생성

by linuxgo 2025. 8. 7.
반응형

TMS320F28335의 ePWM 모듈로 하프 브리지에서 SPWM(사인파 PWM)을 구현하는 절차이며 , 모터 제어와 인버터 설계에 적용 가능합니다. (50 Hz 사인파, 20 kHz 캐리어 주파수, 1 µs 데드타임을 위한 예제코드를 포함)

1. SPWM

SPWM(Sinusoidal PWM)은 듀티 사이클을 사인파 형태로 변조하여 정현파 출력을 생성합니다. TMS320F28335의 ePWM 모듈은 이를 위해 사인파 테이블과 인터럽트를 활용합니다. 

  • 상보 출력: ePWMxA와 ePWMxB가 반대 위상, 데드타임 포함.
  • 사인파 변조: 50 Hz 사인파로 듀티 사이클 조정.
  • 캐리어 주파수: 20 kHz로 고주파 PWM 생성.

2. SPWM 파형 설정 절차

2.1 타임 베이스(Time-Base)

캐리어 주파수(20 kHz)를 설정, Up-Down 모드로 대칭 PWM 생성.

  • 주기 계산: TBPRD = (SYSCLKOUT / (2 * PWM_FREQ * CLKDIV * HSPCLKDIV)) - 1
  • 예: 150 MHz, 20 kHz → TBPRD = 3749

2.2 사인파 테이블 생성

100개 샘플로 0~2π 사인파 테이블 생성.

  • 계산: sin_table[i] = sin(2π * i / SINE_SAMPLES)
  • 샘플 수: 100, 사인파 주파수: 50 Hz.

2.3 듀티 사이클 변조

인터럽트에서 사인파 테이블을 참조하여 CMPA 업데이트.

  • 계산: CMPA = TBPRD * (0.5 + MODULATION_INDEX * 0.5 * sin_table[index])
  • 업데이트 주기: PWM_FREQ / (SINE_FREQ * SINE_SAMPLES) = 4

2.4 데드밴드(Dead-Band)

ePWMxA를 기준으로 ePWMxB 상보 출력, 1 µs 데드타임.

  • 계산: DEAD_TIME_TICKS = DEAD_TIME * SYSCLKOUT
  • 예: 1 µs, 150 MHz → 150 틱

2.5 GPIO 및 인터럽트

GPIO0(ePWM1A), GPIO1(ePWM1B) 출력, 인터럽트로 사인파 인덱스 갱신.

3. 예제 코드

50 Hz SPWM, 20 kHz 캐리어, 1 µs 데드타임, 변조 지수 0.8.

#include "DSP28x_Project.h" // TMS320F28335 헤더 파일
#include <math.h> // 사인파 계산용

// 시스템 및 PWM 설정 상수
#define SYSCLKOUT       150000000 // 시스템 클럭 (Hz): 150 MHz
#define PWM_FREQ        20000     // 캐리어 주파수 (Hz): 20 kHz
#define SINE_FREQ       50        // 사인파 주파수 (Hz): 50 Hz
#define DEAD_TIME       1e-6      // 데드타임 (초): 1 µs
#define CLKDIV          1         // TBCLK 분주 비율: 1:1
#define HSPCLKDIV       1         // 고속 클럭 분주 비율: 1:1
#define SINE_SAMPLES    100       // 사인파 테이블 샘플 수
#define MODULATION_INDEX 0.8      // 변조 지수 (0~1)

// 계산된 레지스터 값
#define TBPRD_VALUE     ((SYSCLKOUT / (2 * PWM_FREQ * CLKDIV * HSPCLKDIV)) - 1) // TBPRD 계산
#define DEAD_TIME_TICKS (DEAD_TIME * SYSCLKOUT) // 데드타임 틱 계산
#define UPDATE_PERIOD   (PWM_FREQ / (SINE_FREQ * SINE_SAMPLES)) // 사인파 업데이트 주기

// 사인파 테이블 (정적 할당)
float sin_table[SINE_SAMPLES];

// 글로벌 변수
volatile Uint16 sine_index = 0; // 사인파 테이블 인덱스
volatile Uint32 update_counter = 0; // 업데이트 주기 카운터

// 사인파 테이블 초기화
void InitSineTable(void) {
    Uint16 i;
    for (i = 0; i < SINE_SAMPLES; i++) {
        sin_table[i] = sin(2.0 * 3.141592653589793 * i / SINE_SAMPLES); // 0~2π 사인파
    }
}

// ePWM1 모듈 초기화 함수
void InitEPwm1(void) {
    EALLOW; // 보호된 레지스터 접근 허용

    // GPIO 설정: ePWM1A와 ePWM1B를 GPIO0, GPIO1에 매핑
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // GPIO0을 ePWM1A로 설정
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // GPIO1을 ePWM1B로 설정
    EDIS; // 보호된 레지스터 접근 비활성화

    // 타임 베이스 설정
    EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Up-Down 카운터 모드
    EPwm1Regs.TBPRD = TBPRD_VALUE; // PWM 주기 설정
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // 고속 클럭 분주: 1:1
    EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // 클럭 분주: 1:1
    EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; // 주기 레지스터 쉐도우 모드
    EPwm1Regs.TBCTR = 0; // 카운터 초기화

    // 카운터 비교 설정
    EPwm1Regs.CMPA.half.CMPA = (Uint16)(TBPRD_VALUE * 0.5); // 초기 50% 듀티
    EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW; // CMPA 쉐도우 모드
    EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO; // TBCTR=0일 때 로드

    // 액션 한정자 설정: ePWM1A 출력 동작
    EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // TBCTR=0일 때 High
    EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // TBCTR=CMPA(상승) Low
    EPwm1Regs.AQCTLA.bit.CAD = AQ_CLEAR; // TBCTR=CMPA(하강) Low

    // 데드밴드 설정: 상보 출력과 데드타임
    EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // 데드밴드 완전 활성화
    EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL; // ePWM1A를 입력으로
    EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // ePWM1A: Active High, ePWM1B: Active Low
    EPwm1Regs.DBRED = DEAD_TIME_TICKS; // Rising Edge Delay
    EPwm1Regs.DBFED = DEAD_TIME_TICKS; // Falling Edge Delay

    // 동기화 설정
    EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // TBCTR=0에서 동기화 출력
    EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // 동기화 비활성화

    // 인터럽트 설정
    EPwm1Regs.ETSEL.bit.INTEN = 1; // 인터럽트 활성화
    EPwm1Regs.ETSEL.bit.INTSEL = 4; // TBCTR=0에서 인터럽트
    EPwm1Regs.ETPS.bit.INTPRD = 1; // 첫 번째 이벤트에서 인터럽트
    PieCtrlRegs.PIEIER3.bit.INTx1 = 1; // PIE 인터럽트 활성화
}

// 인터럽트 서비스 루틴: SPWM 생성
interrupt void epwm1_isr(void) {
    update_counter++; // 주기 카운터 증가

    // 사인파 테이블 인덱스 업데이트 (20 kHz / (50 Hz * 100) = 4)
    if (update_counter >= UPDATE_PERIOD) {
        update_counter = 0; // 카운터 초기화
        sine_index = (sine_index + 1) % SINE_SAMPLES; // 다음 인덱스

        // CMPA 계산: 사인파 변조 (중간점 0.5, 변조 지수 0.8)
        EPwm1Regs.CMPA.half.CMPA = (Uint16)(TBPRD_VALUE * (0.5 + MODULATION_INDEX * 0.5 * sin_table[sine_index]));
    }

    EPwm1Regs.ETCLR.bit.INT = 1; // 인터럽트 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; // PIE ACK 클리어
}

void main(void) {
    InitSysCtrl(); // 시스템 클럭 초기화 (150 MHz)
    DINT; // 전역 인터럽트 비활성화

    InitPieCtrl(); // PIE 초기화
    IER = 0x0000; // 인터럽트 비활성화
    IFR = 0x0000; // 인터럽트 플래그 클리어
    InitPieVectTable(); // 인터럽트 벡터 테이블 초기화

    EALLOW;
    PieVectTable.EPWM1_INT = &epwm1_isr; // ePWM1 ISR 설정
    EDIS;

    InitSineTable(); // 사인파 테이블 초기화
    InitEPwm1(); // ePWM1 초기화

    IER |= M_INT3; // ePWM1 인터럽트 그룹 활성화
    EINT; // 전역 인터럽트 활성화
    ERTM; // 실시간 인터럽트 활성화

    while(1); // 무한 루프
}

4. 설정 계산식 상세

4.1 PWM 주기 (TBPRD)

TBPRD = (SYSCLKOUT / (2 * PWM_FREQ * CLKDIV * HSPCLKDIV)) - 1

  • 입력: SYSCLKOUT = 150 MHz, PWM_FREQ = 20 kHz, CLKDIV = 1, HSPCLKDIV = 1
  • 결과: (150e6 / (2 * 20e3 * 1 * 1)) - 1 = 3749

4.2 사인파 듀티 사이클 (CMPA)

CMPA = TBPRD * (0.5 + MODULATION_INDEX * 0.5 * sin_table[index])

  • 입력: TBPRD = 3749, MODULATION_INDEX = 0.8, sin_table = [-1, 1]
  • 결과: CMPA는 749~2999 범위에서 사인파 변조.

4.3 데드타임 (DBRED, DBFED)

DEAD_TIME_TICKS = DEAD_TIME * SYSCLKOUT

  • 입력: DEAD_TIME = 1 µs, SYSCLKOUT = 150 MHz
  • 결과: 1e-6 * 150e6 = 150

4.4 사인파 업데이트 주기

UPDATE_PERIOD = PWM_FREQ / (SINE_FREQ * SINE_SAMPLES)

  • 입력: PWM_FREQ = 20 kHz, SINE_FREQ = 50 Hz, SINE_SAMPLES = 100
  • 결과: 20000 / (50 * 100) = 4

5. 검증 방법

  1. 오실로스코프: GPIO0(ePWM1A), GPIO1(ePWM1B)에서 20 kHz 캐리어, 50 Hz SPWM, 1 µs 데드타임 확인.
  2. CCS 디버깅: TBPRD, CMPA, sin_table, sine_index 값 확인.
  3. 테스트: SINE_FREQ (60 Hz), MODULATION_INDEX (0.9) 변경으로 출력 조정.

6. 추가 참고 자료

  • TI ePWM Reference Guide (SPRUG04)
  • C2000Ware: epwm_deadband 예제
  • TI E2E 커뮤니티 포럼
  • MathWorks C2000 Blockset
반응형