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 ) - 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"
#include <math.h>
// 시스템 및 PWM 설정 상수
#define SYSCLKOUT 150000000UL // 시스템 클럭 (Hz): 150 MHz
#define PWM_FREQ 20000UL // 캐리어 주파수 (Hz): 20 kHz
#define SINE_FREQ 50UL // 사인파 주파수 (Hz): 50 Hz
#define DEAD_TIME 0.000001 // 데드타임 (초): 1 µs
#define SINE_SAMPLES 100U // 사인파 테이블 샘플 수
#define MODULATION_INDEX 0.8f // 변조 지수 (0~1)
// TBCLK = SYSCLKOUT / (CLKDIV * HSPCLKDIV), TB_DIV1 = 1
#define TBCLK (SYSCLKOUT) // TBCLK = 150 MHz
#define TBPRD_VALUE ((Uint16)((TBCLK / (2UL * PWM_FREQ)) - 1UL)) // TBPRD = 3749
#define DEAD_TIME_TICKS \
((Uint16)((TBCLK / 1000000UL) * 1UL)) // 1 µs = 150 ticks
#define UPDATE_PERIOD \
((Uint32)(PWM_FREQ / (SINE_FREQ * SINE_SAMPLES))) // 업데이트 주기 = 4
// 사인파 테이블
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] = sinf(2.0f * 3.141592653589793f * i / SINE_SAMPLES);
}
}
// ePWM1 모듈 초기화
void InitEPwm1(void) {
EALLOW;
// GPIO 설정
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // GPIO0: ePWM1A
GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // GPIO1: ePWM1B
GpioCtrlRegs.GPADIR.bit.GPIO0 = 1; // 출력 설정
GpioCtrlRegs.GPADIR.bit.GPIO1 = 1;
GpioCtrlRegs.GPAPUD.bit.GPIO0 = 1; // 풀업 비활성화
GpioCtrlRegs.GPAPUD.bit.GPIO1 = 1;
EDIS;
// 타임 베이스 설정
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // Up-Down 모드
EPwm1Regs.TBPRD = TBPRD_VALUE; // PWM 주기
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // HSPCLKDIV = 1
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // CLKDIV = 1
EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW;
EPwm1Regs.TBCTR = 0;
// 카운터 비교 설정
EPwm1Regs.CMPA.half.CMPA =
(Uint16)((TBPRD_VALUE * 50UL) / 100UL); // 초기 50% 듀티
EPwm1Regs.CMPCTL.bit.SHDWAMODE = CC_SHADOW;
EPwm1Regs.CMPCTL.bit.LOADAMODE = CC_CTR_ZERO;
// 액션 한정자 설정
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;
EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC;
EPwm1Regs.DBRED = DEAD_TIME_TICKS; // Rising Edge Delay
EPwm1Regs.DBFED = DEAD_TIME_TICKS; // Falling Edge Delay
// 동기화 설정
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO;
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE;
// 인터럽트 설정
EPwm1Regs.ETSEL.bit.INTEN = 1; // 인터럽트 활성화
EPwm1Regs.ETSEL.bit.INTSEL = 1; // TBCTR=0에서 인터럽트
EPwm1Regs.ETPS.bit.INTPRD = 1; // 첫 번째 이벤트에서 인터럽트
PieCtrlRegs.PIEIER3.bit.INTx1 = 1; // PIE 인터럽트 활성화
}
// 인터럽트 서비스 루틴
interrupt void epwm1_isr(void) {
if (++update_counter >= UPDATE_PERIOD) {
update_counter = 0;
sine_index = (sine_index + 1) % SINE_SAMPLES;
EPwm1Regs.CMPA.half.CMPA =
(Uint16)(TBPRD_VALUE *
(0.5f + MODULATION_INDEX * 0.5f * sin_table[sine_index]));
}
EPwm1Regs.ETCLR.bit.INT = 1; // 인터럽트 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP3; // PIE ACK 클리어
}
void main(void) {
InitSysCtrl(); // 시스템 클럭 초기화
DINT; // 전역 인터럽트 비활성화
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
EALLOW;
PieVectTable.EPWM1_INT = &epwm1_isr;
EDIS;
InitSineTable();
InitEPwm1();
IER |= M_INT3;
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. 검증 방법
- 오실로스코프: GPIO0(ePWM1A), GPIO1(ePWM1B)에서 20 kHz 캐리어, 50 Hz SPWM, 1 µs 데드타임 확인.
- CCS 디버깅:
TBPRD
,CMPA
,sin_table
,sine_index
값 확인. - 테스트:
SINE_FREQ
(60 Hz),MODULATION_INDEX
(0.9) 변경으로 출력 조정.
6. 추가 참고 자료
- TI ePWM Reference Guide (SPRUG04)
- C2000Ware: epwm_deadband 예제
- TI E2E 커뮤니티 포럼
- MathWorks C2000 Blockset
'MCU > C2000' 카테고리의 다른 글
TMS320F28388D DSP ADC 사용법: DriverLib API로 ADC 설정 및 코드(수정) (0) | 2025.08.08 |
---|---|
TMS320F28388D DSP CPU 타이머 사용법 : Driverlib API로 CPU 타이머 설정과 예제(수정본) (0) | 2025.08.08 |
TMS320F28388D DSP SCI 사용법: Driverlib API로 UART 설정 및 예제(수정본) (0) | 2025.08.08 |
TMS320F28388D DSP Driverlib 기반 프로젝트 설정 및 기본 프로그램 작성 절차 (0) | 2025.08.08 |
TMS320F28335 DSP ePWM Half-Bridge 상보 출력 설정 방법 (0) | 2025.08.07 |
TMS320F28335 DSP SCI 사용법: Bitfield 구조 활용 (0) | 2025.08.07 |
TMS320F28335 DSP 사양 및 CCS 프로젝트 생성 절차 (0) | 2025.08.06 |
TI C2000 Lockstep 완벽 정리: 기능 안전을 위한 필수 기술 (0) | 2025.08.06 |