TMS320F28377D는 Texas Instruments의 C2000 시리즈 마이크로컨트롤러로, 200MHz 시스템 클럭을 지원하며 모터 제어, 인버터, 전력 변환 애플리케이션에 최적화되어 있습니다. 하프-브릿지 PWM(Pulse Width Modulation)은 상단 및 하단 MOSFET을 제어하여 효율적인 전력 전달을 구현하며, 데드밴드(dead-band) 설정으로 슈트-스루(shoot-through)를 방지합니다. 비트필드 구조체를 사용한 하프-브릿지 PWM 설정 예제 코드를 제공하며, 상세한 주석으로 초보자와 전문가 모두에게 유용한 정보를 제공합니다.
하프-브릿지 PWM의 필요성
하프-브릿지 회로는 전력 전자 시스템에서 필수적이며, PWM 신호를 통해 출력 전압을 정밀하게 제어합니다. TMS320F28377D의 ePWM 모듈은 고속 스위칭과 정밀한 타이밍 제어를 지원하며, 데드밴드 설정으로 회로 안정성을 보장합니다. 이 글에서는 20kHz PWM 주파수, 50% 듀티 사이클, 1us 데드밴드를 기준으로 설정 방법을 설명합니다.
하프-브릿지 PWM 코드
아래는 TMS320F28377D의 ePWM1 모듈을 사용한 하프-브릿지 PWM 설정 코드입니다. 시스템 클럭을 200MHz로 설정하고, F28x_Project.h 헤더 파일을 사용하여 비트필드 구조체로 레지스터를 구성했습니다. 각 설정은 상세한 주석으로 설명됩니다.
- 시스템 클럭: 200MHz로 수정(TMS320F28377D의 기본 PLL 설정 기준).
- PWM 주기(TBPRD): 20kHz 주파수를 위해 TBPRD = 5000으로 설정.
- 계산: 주기 = (TBPRD * 2) / 200MHz = 50us → 주파수 = 20kHz.
- 듀티 사이클(CMPA, CMPB): 50% 듀티 사이클을 위해 CMPA = CMPB = 2500(TBPRD / 2).
- 데드밴드(DBRED, DBFED): 1us 지연을 위해 DBRED = DBFED = 200(200MHz * 1us).
1. 시스템 초기화
- InitSysCtrl(): 200MHz 시스템 클럭, PLL, 워치독 타이머를 초기화합니다.
- DINT와 EINT: 초기화 중 인터럽트를 비활성화하고, 완료 후 활성화합니다.
2. GPIO 설정
- GPIO0과 GPIO1: 각각 ePWM1A와 ePWM1B로 설정되어 하프-브릿지 회로의 상단 및 하단 MOSFET을 제어합니다.
- EALLOW와 EDIS: 보호된 레지스터 접근을 제어합니다.
3. ePWM 모듈 설정
- 시간 기준(Time-Base): 업-다운 카운트 모드로 대칭 PWM 신호 생성. TBPRD = 5000으로 20kHz 설정.
- 비교 레지스터(CMPA, CMPB): 50% 듀티 사이클을 위해 CMPA = CMPB = 2500.
- 액션-퀄리파이어(AQ): ePWM1A와 ePWM1B를 보완 출력으로 설정.
- 데드밴드(DB): 1us 지연(DBRED = DBFED = 200)으로 슈트-스루 방지.
/**
* main.c - TMS320F28377D 하프-브릿지 PWM 예제 (가변 PWM 및 듀티 사이클 동적 제어)
*
* 이 코드는 ePWM1 모듈을 하프-브릿지 PWM 동작으로 설정하며, MOSFET 드라이버의 슈트-스루(shoot-through)를 방지하기 위해 데드밴드 제어를 포함합니다.
* - PWM 주파수, 듀티 사이클, 데드밴드는 사용자 정의 변수로 계산되어 가변 설정 가능
* - 메인 루프에서 듀티 사이클을 동적으로 변경 (최소 10% ~ 최대 90% 사이에서 스위핑)
* - 시스템 클럭: 200MHz (ePWM 모듈의 TBCLK: 100MHz)
* - GPIO 설정: GPIO0 (ePWM1A - 상단 MOSFET), GPIO1 (ePWM1B - 하단 MOSFET)
*
* 기본 설정 예시:
* - PWM 주파수: 20kHz
* - 초기 듀티 사이클: 50%
* - 데드밴드: 1us
* - 동적 듀티 사이클: 10% ~ 90%, 0.5% 스텝, 10ms 업데이트 주기
*
* Texas Instruments의 C2000Ware 라이브러리와 F28x_Project.h를 기반으로 작성되었습니다.
* F2837xD_epwm.h 헤더 파일을 참조하여 ePWM 레지스터 설정을 정확히 구성합니다.
* GPIO 설정에는 DriverLib의 GPIO_SetupPinMux와 GPIO_SetupPinOptions 함수를 사용합니다.
*/
#include "F28x_Project.h"
/**
* PWM 출력에 사용할 GPIO 핀 정의
* - PWM_GPIO_A (GPIO0): ePWM1A로 설정되어 상단 MOSFET을 제어
* - PWM_GPIO_B (GPIO1): ePWM1B로 설정되어 하단 MOSFET을 제어
*/
#define PWM_GPIO_A 0 // GPIO0: ePWM1A (상단 MOSFET)
#define PWM_GPIO_B 1 // GPIO1: ePWM1B (하단 MOSFET)
/**
* PWM 구성용 사용자 정의 변수
* - PWM_FREQ_HZ: 원하는 PWM 주파수 (Hz 단위, 예: 20000Hz = 20kHz)
* - DUTY_CYCLE_PERCENT: 초기 듀티 사이클 (%, 예: 50%)
* - DEAD_BAND_US: 원하는 데드밴드 시간 (us 단위, 예: 1us)
*/
#define PWM_FREQ_HZ 20000 // PWM 주파수: 20kHz
#define DUTY_CYCLE_PERCENT 50.0f // 초기 듀티 사이클: 50%
#define DEAD_BAND_US 1.0f // 데드밴드: 1us
/**
* 동적 듀티 사이클 제어용 변수
* - MIN_DUTY_PERCENT: 듀티 사이클 최소값 (%, 예: 10%)
* - MAX_DUTY_PERCENT: 듀티 사이클 최대값 (%, 예: 90%)
* - DUTY_STEP_PERCENT: 듀티 사이클 변경 스텝 (%, 예: 0.5%)
* - UPDATE_DELAY_MS: 듀티 사이클 업데이트 주기 (ms 단위, 예: 10ms)
*/
#define MIN_DUTY_PERCENT 10.0f // 듀티 사이클 최소: 10%
#define MAX_DUTY_PERCENT 90.0f // 듀티 사이클 최대: 90%
#define DUTY_STEP_PERCENT 0.5f // 듀티 사이클 스텝: 0.5%
#define UPDATE_DELAY_MS 10 // 업데이트 주기: 10ms
/**
* 시스템 클럭 및 TBCLK 설정
* - SYSCLK_HZ: 시스템 클럭 주파수 (200MHz)
* - TBCLK_HZ: ePWM 시간 기준 클럭 (SYSCLK / 2 = 100MHz, CLKDIV=2)
*/
#define SYSCLK_HZ 200000000UL // 시스템 클럭: 200MHz
#define TBCLK_HZ (SYSCLK_HZ / 2) // TBCLK: 100MHz (CLKDIV=2)
/**
* PWM 구성 상수 계산
* - PWM_PERIOD: TBPRD 값, 업-다운 카운트 모드에서 주파수 계산
* 계산: TBPRD = TBCLK / (2 * PWM_FREQ_HZ)
* 예: 100MHz / (2 * 20kHz) = 2500
* - PWM_DUTY: CMPA/CMPB 값, 초기 듀티 사이클 계산
* 계산: CMPA = TBPRD * (DUTY_CYCLE_PERCENT / 100)
* 예: 2500 * (50 / 100) = 1250
* - DEAD_BAND_T: DBRED/DBFED 값, 데드밴드 시간 계산
* 계산: DBRED/DBFED = DEAD_BAND_US * TBCLK
* 예: 1us * 100MHz = 100
*/
#define PWM_PERIOD ((uint16_t)(TBCLK_HZ / (2 * PWM_FREQ_HZ))) // TBPRD: 주기 계산
#define PWM_DUTY ((uint16_t)(PWM_PERIOD * (DUTY_CYCLE_PERCENT / 100.0f))) // CMPA/CMPB: 초기 듀티 계산
#define DEAD_BAND_T ((uint16_t)(DEAD_BAND_US * (TBCLK_HZ / 1000000.0f))) // DBRED/DBFED: 데드밴드 계산
/**
* PWM 출력용 GPIO 설정 함수
* GPIO0와 GPIO1을 각각 ePWM1A와 ePWM1B로 구성합니다.
* - GPIO_SetupPinMux: GPIO 핀을 ePWM 기능으로 멀티플렉싱
* - 첫 번째 인자: GPIO 번호 (0 또는 1)
* - 두 번째 인자: CPU 코어 (GPIO_MUX_CPU1 = CPU1)
* - 세 번째 인자: MUX 옵션 (0: ePWM1A/B)
* - GPIO_SetupPinOptions: GPIO 핀 옵션 설정
* - 첫 번째 인자: GPIO 번호
* - 두 번째 인자: 출력 모드 (GPIO_OUTPUT)
* - 세 번째 인자: 푸시-풀 출력 (GPIO_PUSHPULL)
* - EALLOW/EDIS: 보호된 레지스터 접근 제어
*/
void setupPwmGpio(void)
{
EALLOW; // 보호된 레지스터 접근 허용 (GPIO 설정을 위해 필요)
// GPIO0을 ePWM1A로 설정
// GPIO_SetupPinMux: GPIO0을 ePWM1A 기능으로 멀티플렉싱 (MUX = 0)
GPIO_SetupPinMux(PWM_GPIO_A, GPIO_MUX_CPU1, 0);
// GPIO_SetupPinOptions: GPIO0을 출력 모드, 푸시-풀 출력으로 설정
GPIO_SetupPinOptions(PWM_GPIO_A, GPIO_OUTPUT, GPIO_PUSHPULL);
// GPIO1을 ePWM1B로 설정
// GPIO_SetupPinMux: GPIO1을 ePWM1B 기능으로 멀티플렉싱 (MUX = 0)
GPIO_SetupPinMux(PWM_GPIO_B, GPIO_MUX_CPU1, 0);
// GPIO_SetupPinOptions: GPIO1을 출력 모드, 푸시-풀 출력으로 설정
GPIO_SetupPinOptions(PWM_GPIO_B, GPIO_OUTPUT, GPIO_PUSHPULL);
EDIS; // 보호된 레지스터 접근 비활성화
}
/**
* ePWM1을 하프-브릿지 동작으로 초기화하는 함수
* - 업-다운 카운트 모드로 대칭 PWM 생성
* - 사용자 정의 주파수(PWM_FREQ_HZ), 초기 듀티 사이클(DUTY_CYCLE_PERCENT), 데드밴드(DEAD_BAND_US) 적용
* - F2837xD_epwm.h에 정의된 레지스터와 비트필드를 참조하여 정확히 구성
*/
void setupEPwm1(void)
{
EALLOW; // 보호된 레지스터 접근 허용 (ePWM 설정을 위해 필요)
// ePWM1 모듈 클럭 활성화
// CpuSysRegs.PCLKCR2.bit.EPWM1을 1로 설정하여 ePWM1 모듈 활성화
// 이는 ePWM1에 시스템 클럭을 공급하여 동작을 시작합니다.
CpuSysRegs.PCLKCR2.bit.EPWM1 = 1;
// 시간 기준(Time-Base) 구성
// - CTRMODE: 업-다운 카운트 모드(TB_COUNT_UPDOWN)로 대칭 PWM 생성
// (카운터가 0에서 TBPRD까지 올라갔다가 내려오는 방식으로 부드러운 PWM 생성)
// - PHSEN: 위상 동기화 비활성화(TB_DISABLE), 독립 PWM 동작 (다른 ePWM과 동기화 불필요)
// - HSPCLKDIV: 고속 클럭 분주기 1(TB_DIV1), 클럭을 그대로 사용
// - CLKDIV: 저속 클럭 분주기 2(TB_DIV2), TBCLK = 200MHz / 2 = 100MHz
// - TBPRD: PWM 주기 설정(PWM_PERIOD), 예: 20kHz = 100MHz / (2500 * 2)
// - SYNCOSEL: 카운터 0에서 동기화 신호 출력(TB_CTR_ZERO), 다른 모듈과 연동 시 사용
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 업-다운 카운트 모드
EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // 위상 동기화 비활성화
EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // 고속 분주기 /1
EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV2; // 저속 분주기 /2 (TBCLK=100MHz)
EPwm1Regs.TBPRD = PWM_PERIOD; // 계산된 주기 설정
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_CTR_ZERO; // 카운터 0에서 동기화
// 비교 레지스터(Counter-Compare) 구성
// - CMPA: ePWM1A의 초기 듀티 사이클 설정 (PWM_DUTY)
// (카운터가 CMPA에 도달할 때 신호 전환)
// - CMPB: ePWM1B의 초기 듀티 사이클 설정 (PWM_DUTY, 보완 출력)
// (ePWM1B는 ePWM1A의 보완 신호로 동작하여 하프-브릿지 구현)
EPwm1Regs.CMPA.bit.CMPA = PWM_DUTY; // ePWM1A 초기 듀티 설정
EPwm1Regs.CMPB.bit.CMPB = PWM_DUTY; // ePWM1B 초기 듀티 설정
// 액션-퀄리파이어(Action-Qualifier) 구성
// - ePWM1A: 카운터 0에서 고전위 설정(AQ_SET), CMPA 상향 카운트에서 저전위(AQ_CLEAR)
// (상단 MOSFET: 주기 시작 시 켜지고, 듀티 지점에서 꺼짐)
// - ePWM1B: 카운터 0에서 저전위 설정(AQ_CLEAR), CMPB 하향 카운트에서 고전위(AQ_SET)
// (하단 MOSFET: 주기 시작 시 꺼지고, 하향 듀티 지점에서 켜짐)
// -> 상단/하단 MOSFET을 보완적으로 제어하여 하프-브릿지 동작 구현
EPwm1Regs.AQCTLA.bit.ZRO = AQ_SET; // 카운터 0에서 ePWM1A 고전위
EPwm1Regs.AQCTLA.bit.CAU = AQ_CLEAR; // CMPA 상향에서 ePWM1A 저전위
EPwm1Regs.AQCTLB.bit.ZRO = AQ_CLEAR; // 카운터 0에서 ePWM1B 저전위
EPwm1Regs.AQCTLB.bit.CBD = AQ_SET; // CMPB 하향에서 ePWM1B 고전위
// 데드밴드(Deadband) 구성
// - OUT_MODE: 전체 데드밴드 활성화(DB_FULL_ENABLE)
// (ePWM1A와 ePWM1B 모두에 데드밴드 적용)
// - POLSEL: 활성 고전위 보완(DB_ACTV_HIC), ePWM1B가 ePWM1A의 반전된 신호
// - IN_MODE: ePWM1A를 입력 소스로 사용(DBA_ALL)
// - DBRED/DBFED: 계산된 데드밴드 설정(DEAD_BAND_T), 예: 1us = 100
// - DBRED: 상승 에지 지연 (ePWM1A 꺼짐 후 ePWM1B 켜짐 지연)
// - DBFED: 하강 에지 지연 (ePWM1B 꺼짐 후 ePWM1A 켜짐 지연)
// -> 슈트-스루 방지: 상단/하단 MOSFET이 동시에 켜지지 않도록 지연 추가
EPwm1Regs.DBCTL.bit.OUT_MODE = DB_FULL_ENABLE; // 전체 데드밴드 활성화
EPwm1Regs.DBCTL.bit.POLSEL = DB_ACTV_HIC; // 활성 고전위 보완
EPwm1Regs.DBCTL.bit.IN_MODE = DBA_ALL; // ePWM1A를 소스로 사용
EPwm1Regs.DBRED.all = DEAD_BAND_T; // 상승 에지 지연
EPwm1Regs.DBFED.all = DEAD_BAND_T; // 하강 에지 지연
EDIS; // 보호된 레지스터 접근 비활성화
}
/**
* 메인 함수
* - 시스템 초기화: 클럭, PLL, GPIO, 인터럽트
* - PWM 설정: GPIO 및 ePWM1 초기화 (가변 설정 적용)
* - 무한 루프: 듀티 사이클을 동적으로 변경 (10% ~ 90% 스위핑)
* - 듀티 사이클은 MIN_DUTY_PERCENT와 MAX_DUTY_PERCENT 사이에서 증가/감소
* - DUTY_STEP_PERCENT 단위로 변경, UPDATE_DELAY_MS 주기로 업데이트
*/
void main(void)
{
// 동적 듀티 사이클 제어용 변수
float current_duty_percent = DUTY_CYCLE_PERCENT; // 현재 듀티 사이클 (%)
int duty_direction = 1; // 듀티 변경 방향 (1: 증가, -1: 감소)
// 시스템 초기화
// - InitSysCtrl(): 200MHz 시스템 클럭 설정, PLL 활성화, 주변 장치 초기화
// (외부 크리스탈 20MHz 기준 PLL로 200MHz 생성)
// - InitGpio(): 모든 GPIO를 기본 상태(입력, 풀업)로 초기화
InitSysCtrl(); // 시스템 클럭 및 주변 장치 초기화
InitGpio(); // GPIO 기본 상태로 초기화
// PWM GPIO 설정
// - setupPwmGpio(): GPIO0/1을 ePWM1A/B로 구성 (DriverLib 함수 사용)
setupPwmGpio();
// 인터럽트 제어 초기화
// - DINT: 전역 인터럽트 비활성화 (초기화 중 안전 보장)
// - InitPieCtrl(): PIE(Peripheral Interrupt Expansion) 레지스터 초기화
// - IER/IFR: CPU 인터럽트 비활성화 및 플래그 클리어
// - InitPieVectTable(): 인터럽트 벡터 테이블 초기화 (인터럽트 핸들러 매핑)
DINT; // 전역 인터럽트 비활성화
InitPieCtrl(); // PIE 제어 레지스터 초기화
IER = 0x0000; // CPU 인터럽트 비활성화
IFR = 0x0000; // CPU 인터럽트 플래그 클리어
InitPieVectTable(); // PIE 벡터 테이블 초기화
// ePWM1 설정
// - setupEPwm1(): ePWM1을 하프-브릿지 PWM으로 구성 (가변 주파수/듀티/데드밴드)
setupEPwm1();
// 전역 인터럽트 활성화
// - EINT: 전역 인터럽트 활성화 (인터럽트 기반 제어 가능)
// - ERTM: 실시간 인터럽트 활성화 (디버깅 및 실시간 동작 지원)
EINT; // 전역 인터럽트 활성화
ERTM; // 실시간 인터럽트 활성화
// 메인 루프
// - PWM은 하드웨어에서 자율적으로 실행
// - 듀티 사이클을 동적으로 변경: 10%에서 90%로 증가, 다시 감소 반복
// - 계산: CMPA = PWM_PERIOD * (current_duty_percent / 100)
// - 주기: UPDATE_DELAY_MS (ms)마다 DUTY_STEP_PERCENT (%) 단위로 변경
for(;;)
{
// 새로운 듀티 사이클 계산
uint16_t new_duty = (uint16_t)(PWM_PERIOD * (current_duty_percent / 100.0f));
// CMPA 및 CMPB 레지스터 업데이트
// - ePWM1A와 ePWM1B에 동일한 듀티 사이클 적용 (보완 출력)
EPwm1Regs.CMPA.bit.CMPA = new_duty; // ePWM1A 듀티 업데이트
EPwm1Regs.CMPB.bit.CMPB = new_duty; // ePWM1B 듀티 업데이트
// 듀티 사이클 증가/감소 방향 결정
current_duty_percent += duty_direction * DUTY_STEP_PERCENT;
// 범위 체크 및 방향 전환
// - 최대값(90%) 도달 시 감소로 전환
// - 최소값(10%) 도달 시 증가로 전환
if (current_duty_percent >= MAX_DUTY_PERCENT)
{
current_duty_percent = MAX_DUTY_PERCENT;
duty_direction = -1; // 감소 방향으로 전환
}
else if (current_duty_percent <= MIN_DUTY_PERCENT)
{
current_duty_percent = MIN_DUTY_PERCENT;
duty_direction = 1; // 증가 방향으로 전환
}
// 업데이트 주기 대기
// - DELAY_US: 마이크로초 단위 지연 (10ms = 10000us)
// - 부드러운 PWM 전환을 위해 충분한 지연 시간 확보
DELAY_US(UPDATE_DELAY_MS * 1000); // ms를 us로 변환
}
}
실제 구현 시 주의사항
- 하드웨어 확인: MOSFET 드라이버의 데이터시트를 확인하여 데드밴드 값(DBRED, DBFED)을 조정하세요.
- Code Composer Studio(CCS): F28x_Project.h가 포함된 C2000Ware 환경에서 실행됩니다.
- 동적 제어: 듀티 사이클 변경은 EPwm1Regs.CMPA.bit.CMPA를 런타임에 수정.
- 인터럽트 추가: 실시간 제어가 필요한 경우, ETSEL과 ETPS 레지스터로 인터럽트를 설정하세요.
'MCU > C2000' 카테고리의 다른 글
TI C2000 Lockstep 완벽 정리: 기능 안전을 위한 필수 기술 (0) | 2025.08.06 |
---|---|
TMS320F28377D DSP SCI 사용법: Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |
TMS320F28377D DSP ADC 트리거 모드 사용: Bitfield 구조 활용(수정) (0) | 2025.08.06 |
TMS320F28377D DSP ADC 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |
TMS320F28377D DSP CPU 타이머 사용법 :Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |
TMS320F28377D DSP CCS 프로젝트 설정 및 기본 프로그램 (0) | 2025.08.06 |
TMS320F28377D DSP GPIO 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |
TI C2000 DSP ELF 파일 구조 분석 및 CCS 확인 방법 (0) | 2025.08.02 |