1. 서론
Buck 컨버터는 입력 DC 전압을 낮은 출력 DC 전압으로 변환하는 스위칭 레귤레이터로, 디지털 제어기를 통해 높은 정밀도와 동적 응답성을 제공합니다. TI의 C2000 DSP(F28379D)는 고속 ADC, PWM, CMPSS, CLA를 제공하여 디지털 전력 변환에 적합합니다. 본 문서의 목적은 TI C2000 DSP를 활용하여 Buck 컨버터의 디지털 제어기를 설계하는 상세 절차를 이론적인 베이스로 상세하게 기술하는 것으로, 전압 모드 제어(VMC)를 구현하고, UART를 통한 RUN/STOP 제어, 외부 스위치 입력, 소프트 스타트, 과전압/과전류 보호(OVP/OCP)를 포함합니다. 설계 과정은 요구사항 정의, 하드웨어 설계, 아날로그 및 디지털 모델링, 제어기 이산화, DSP 코드 구현, 시뮬레이션 및 검증을 제시한다.
2. 설계 요구사항
Buck 컨버터의 디지털 제어기 설계 요구사항은 다음과 같습니다:
- 입력 전압 (\( V_{in} \)): 12V
- 출력 전압 (\( V_{out} \)): 2.5V
- 출력 전류 (\( I_{out} \)): 1A
- 스위칭 주파수 (\( f_{sw} \)): 200kHz (\( T_{sw} = \frac{1}{f_{sw}} = 5 \mu s \))
- 샘플링 주기 (\( T_s \)): 5μs (PWM과 동기화)
- 전류 모드: 연속 전도 모드 (CCM)
- 제어 방식: VMC
- 하드웨어 플랫폼: TI Delfino F28379D LaunchPad + 커스터마이징된 동기 정류 Buck 컨버터 보드
- 성능 목표:
- 출력 전압 리플: \( \Delta V_{out} \leq 25mV \) (1% 이하)
- 과도 응답 시간: \(\leq 100\mu s\) (부하/전압 스텝 응답)
- 위상 마진: 45°~60°
- 대역폭: 약 20kHz (\( f_{sw}/10 \))
- 추가 요구사항:
- ADC: 12비트, 3.3V 기준
- PWM: Up-Down 모드, 200MHz 시스템 클럭
- 안정성: 듀티 사이클 제한 (0.1~0.9), ADC 입력 범위 보호
- 디버깅: UART (SCIA, 115200 baud)로 \( V_{out}, I_{out} \), 상태 모니터링
- 보호: 과전압 (\( V_{out} > 2.75V \)), 과전류 (\( I_{out} > 1.5A \))
- 기능: UART 명령('R'/'S'), 외부 스위치(GPIO4), 소프트 스타트 (10ms)
- 최적화: CLA로 PI 연산, IQmath로 고정소수점 연산, Pre-warping
3. 하드웨어 설계
커스터마이징된 동기 정류 Buck 컨버터는 BOOSTXL-BUCKCONV를 참고하여 설계되며, 입력 12V, 출력 2.5V, 1A, 200kHz, CCM에 최적화된 동기 정류 전원단과 센싱 회로로 구성됩니다. 동기 정류 방식은 프리휠링 다이오드 대신 저측(Low-Side) MOSFET을 사용하여 효율성을 향상시킵니다. 하드웨어는 TI Delfino F28379D LaunchPad와 호환되며, UART, 외부 스위치, 보호 기능을 지원합니다.
3.1 인덕터 설계
- 인덕터 리플 전류 (\( \Delta I_L \)): \( I_{out} \times 0.3 = 1A \times 0.3 = 0.3A \).
- 인덕터 값 계산: \[ L = \frac{V_{in} \cdot \left( \frac{V_{out}}{V_{in}} \right) \cdot \left( 1 - \frac{V_{out}}{V_{in}} \right)}{f_{sw} \cdot \Delta I_L} \] 대입: \( V_{in} = 12V \), \( V_{out} = 2.5V \), \( f_{sw} = 200 \times 10^3 Hz \), \( \Delta I_L = 0.3A \). \[ L = \frac{12 \cdot 0.2083 \cdot 0.7917}{200 \times 10^3 \cdot 0.3} \approx 33 \times 10^{-6} H = 33 \mu H \]
- 선택: 33μH 인덕터 (포화 전류 ≥ 1.5A, DCR ≤ 50mΩ, 예: Coilcraft MSS7341-333MLB).
3.2 커패시터 설계
- 전압 리플 (\( \Delta V_{out} \)): \( V_{out} \times 0.01 = 2.5V \times 0.01 = 0.025V \).
- 커패시터 값 계산: \[ C = \frac{\Delta I_L}{8 \cdot f_{sw} \cdot \Delta V_{out}} \] 대입: \( \Delta I_L = 0.3A \), \( f_{sw} = 200 \times 10^3 Hz \), \( \Delta V_{out} = 0.025V \). \[ C = \frac{0.3}{8 \cdot 200 \times 10^3 \cdot 0.025} = 7.5 \times 10^{-6} F = 7.5 \mu F \]
- 선택: 10μF 세라믹 커패시터 (ESR ≤ 10mΩ, 6.3V 이상, 예: Murata GRM31CR60J106KA01L).
3.3 스위치 및 동기 정류
- 고측(High-Side) MOSFET: N-채널, 30V, 25A (TI CSD87588N, \( R_{DS(on)} \leq 10m\Omega \)), ePWM1A(GPI0)로 구동.
- 저측(Low-Side) MOSFET: N-채널, 30V, 25A (TI CSD87588N, \( R_{DS(on)} \leq 10m\Omega \)), ePWM1B(GPI1)로 구동, 동기 정류 구현.
- 게이트 드라이버: UCC27424, 4A 듀얼 채널, 3.3V 로직 호환, High-Side 및 Low-Side MOSFET 동시 구동, 데드타임 66.7ns 설정.
- 설명: 동기 정류는 프리휠링 다이오드를 저측 MOSFET으로 대체하여 전도 손실을 줄이고 효율성을 향상시킵니다. ePWM1A와 ePWM1B는 상보적 출력으로 설정되며, 데드타임은 MOSFET 스위칭 충돌을 방지합니다.
3.4 센싱 및 제어 회로
- 전압 센싱:
- 분압 회로: \( R_1 = 3.3k\Omega \), \( R_2 = 2.2k\Omega \), 출력 전압을 0~3.3V로 스케일링.
- ADC 입력: ADCINA0 (GPIO2), 12비트, 3.3V 기준.
- 전류 센싱 (OCP용):
- 션트 저항: 0.1Ω (1% 정밀도, 1W 이상, 예: Vishay WSL1206R1000FEA).
- ADC 입력: ADCINA1 (GPIO3), 과전류 보호용.
- 옵션: INA240 전류 센서 앰프(고정밀도, -4V~80V CMRR)로 대체 가능.
- 외부 스위치:
- GPIO4: 풀업 저항(10kΩ), Low=RUN, High=STOP.
- 스위치: 푸시 버튼 또는 토글 스위치, 디바운싱 회로(100nF 병렬 커패시터).
- UART 디버깅:
- SCIA: GPIO28(TX), GPIO29(RX), 115200 baud.
- FTDI 칩(예: FT232R) 또는 XDS110 내장 UART 사용.
3.5 하드웨어 플랫폼
- F28379D LaunchPad: 200MHz 듀얼 코어, 12비트 ADC, 16채널 PWM, CLA 지원.
- 커스터마이징된 Buck 컨버터 보드:
- 동기 정류 전원단: High-Side/Low-Side MOSFET(CSD87588N), UCC27424 드라이버.
- 인덕터: 33μH, 커패시터: 10μF.
- 센싱: 전압 분압기, 0.1Ω 션트, INA240(옵션).
- 입출력: 12V 입력(최소 2A), 2.5V/1A 출력, 동적 부하 지원(2.5Ω 저항).
- 외부 장비:
- 전원 공급기: 12V, 2A DC.
- 오실로스코프: Tektronix TBS2000 (리플, 과도 응답 측정).
- 부하: 2.5Ω 저항(1A 정격), 동적 부하(0.5A~1A 스텝).
4. 아날로그 모델링
4.1 State-Space 평균화 모델
CCM에서 상태 변수는 인덕터 전류 (\( i_L \))와 출력 커패시터 전압 (\( v_C \))입니다.
- 스위치 온 (\( D \)): \[ L \frac{di_L}{dt} = v_{in} - v_C, \quad C \frac{dv_C}{dt} = i_L - \frac{v_C}{R} \]
- 스위치 오프 (\( 1-D \)): \[ L \frac{di_L}{dt} = -v_C, \quad C \frac{dv_C}{dt} = i_L - \frac{v_C}{R} \]
- 평균화: \[ \frac{d}{dt} \begin{bmatrix} i_L \\ v_C \end{bmatrix} = \begin{bmatrix} 0 & -\frac{1}{L} \\ \frac{1}{C} & -\frac{1}{R C} \end{bmatrix} \begin{bmatrix} i_L \\ v_C \end{bmatrix} + \begin{bmatrix} \frac{D}{L} \\ 0 \end{bmatrix} v_{in} \] 출력: \( y = v_C = [0 \ 1] \begin{bmatrix} i_L \\ v_C \end{bmatrix} \).
4.2 소신호 모델
- 상태 변수 분리: \( i_L = I_L + \hat{i}_L \), \( v_C = V_C + \hat{v}_C \), \( d = D + \hat{d} \).
- VMC 전달 함수 (\( G_{vd}(s) \)): \[ G_{vd}(s) = \frac{V_{in}}{1 + s \frac{L}{R} + s^2 L C} \] 대입: \( V_{in} = 12V \), \( L = 33 \mu H \), \( C = 10 \mu F \), \( R = 2.5 \Omega \). \[ \omega_0 = \frac{1}{\sqrt{L C}} \approx 8.72 \times 10^4 \, \text{rad/s}, \quad Q = R \sqrt{\frac{C}{L}} \approx 0.69 \]
4.3 MATLAB 모델링
% Buck 컨버터 플랜트 모델
Vin = 12; L = 33e-6; C = 10e-6; R = 2.5;
Gvd = tf(Vin, [L*C, L/R, 1]); % VMC 전달 함수
figure; bode(Gvd); grid on; % 주파수 응답
figure; step(Gvd); grid on; % 계단 응답
5. 디지털 제어기 설계
5.1 아날로그 PI 제어기
- 전달 함수: \[ G_c(s) = K_p + \frac{K_i}{s} = \frac{K_p s + K_i}{s} \] \( K_p = 0.1 \), \( K_i = 1000 \) (MATLAB pidTuner, 위상 마진 45°~60°, 대역폭 20kHz).
- MATLAB 튜닝:
Kp = 0.1; Ki = 1000; Gc = tf([Kp Ki], [1 0]); G_loop = series(Gc, Gvd); margin(G_loop); grid on;
5.2 이산화 (Tustin 변환 with Pre-warping)
- Pre-warping 주파수: 20kHz.
- Tustin 변환: \[ s = \frac{\omega_p}{\tan(\omega_p T_s / 2)} \cdot \frac{z - 1}{z + 1}, \quad \omega_p = 2 \pi \cdot 20 \times 10^3, \quad T_s = 5 \times 10^{-6} \]
- 이산 PI 제어기: \[ G_c(z) \approx \frac{0.1025 z - 0.0975}{z - 1} \] 차분 방정식: \[ u[n] = u[n-1] + 0.1025 e[n] - 0.0975 e[n-1] \]
- MATLAB:
Ts = 5e-6; Gc_d = c2d(Gc, Ts, 'tustin', 'PrewarpFrequency', 2e4); [num, den] = tfdata(Gc_d, 'v'); % 출력: [0.1025, -0.0975], [1, -1]
6. TI C2000 DSP 구현
F28379D에서 VMC를 구현하며, CLA, IQmath, UART, RUN/STOP, 소프트 스타트, OVP/OCP를 통합합니다.
6.1 시스템 구성
- ADC: 12비트, 3.3V 기준, ADCINA0(전압), ADCINA1(전류, OCP용).
- PWM: 200kHz Up-Down 모드, 주기 375 (200MHz / (2 * 200kHz)).
- CLA: PI 연산.
- UART: SCIA, GPIO28(TX), GPIO29(RX), 115200 baud.
- 외부 스위치: GPIO4, 풀업, RUN/STOP 토글.
- GPIO: PWM(GPI0, GPI1), 전압(GPIO2), 전류(GPIO3), UART(GPIO28, GPIO29), 스위치(GPIO4).
6.2 VMC 코드
VMC는 전압 루프만 사용하여 제어하며, UART, 외부 스위치, 소프트 스타트, OVP/OCP 기능을 지원합니다.
// buck_vmc.c: F28379D를 사용한 Buck 컨버터 전압 모드 제어(VMC) 디지털 제어기
// 시스템 클럭: 200MHz (20MHz 크리스털, PLL 배수 10)
// PWM 주파수: 200kHz, 목표 출력 전압: 2.5V, 입력 전압: 10~14V
#include "F28x_Project.h"
#include "IQmathLib.h"
// 제어기 파라미터 (IQ24 고정소수점 형식)
#define VREF _IQ(2.5) // 목표 출력 전압: 2.5V
#define KP _IQ(0.1) // 비례 게인: 0.1 (MATLAB pidTuner, 위상 마진 45°~60°)
#define KI _IQ(1000.0) // 적분 게인: 1000 (MATLAB pidTuner, 전달함수 기반)
#define TS _IQ(0.000005) // 샘플링 주기: 5us (200kHz PWM 동기화)
#define ADC_VREF _IQ(3.3) // ADC 기준 전압: 3.3V
#define ADC_MAX _IQ(4095.0) // 12비트 ADC 최대값
#define PWM_PERIOD 500 // PWM 주기: 200MHz / (2 * 200kHz) = 500
#define DUTY_MIN _IQ(0.1) // 최소 듀티 사이클: 0.1 (MOSFET 보호)
#define DUTY_MAX _IQ(0.9) // 최대 듀티 사이클: 0.9 (안정성)
#define V_OVP _IQ(2.75) // 과전압 보호 임계값: 2.5V + 10%
#define I_OCP _IQ(1.5) // 과전류 보호 임계값: 1.5A
#define SOFT_START_TIME _IQ(0.01) // 소프트 스타트 시간: 10ms
#define SOFT_START_STEPS 2000 // 소프트 스타트 스텝 수: 10ms / 5us = 2000
#define SHUNT_R _IQ(0.1) // 션트 저항: 0.1Ω (OCP용)
#define VIN_MIN _IQ(10.0) // 최소 입력 전압: 10V
#define VIN_MAX _IQ(14.0) // 최대 입력 전압: 14V
#define ADC_VIN_SCALE _IQ(0.2) // Vin 분압기 비율: 3.3V / 15V ≈ 0.2
#define TX_TIMEOUT_COUNT 20000 // UART TX 타임아웃: 1ms @ 200MHz
#define FAULT_COUNT_MAX 3 // OVP/OCP 필터링: 3회 연속 초과 시 FAULT
// 전역 변수: 상태 모니터링 및 제어
volatile _iq Vout = _IQ(0.0); // 측정 출력 전압 (IQ24, 0~3.3V)
volatile _iq Iout = _IQ(0.0); // 측정 인덕터 전류 (IQ24, 0~2A)
volatile _iq Vin = _IQ(12.0); // 측정 입력 전압 (IQ24, 10~14V)
volatile _iq error = _IQ(0.0); // 전압 오차 (Vref - Vout)
volatile _iq duty = _IQ(0.0); // 현재 듀티 사이클 (소프트 스타트 초기 0)
volatile _iq error_prev = _IQ(0.0); // 이전 오차
volatile _iq duty_prev = _IQ(0.0); // 이전 듀티 사이클
volatile Uint16 error_count = 0; // ADC 에러 카운터 (디버깅용)
volatile Uint16 system_state = 0; // 시스템 상태: 0(STOP), 1(RUN), 2(FAULT)
volatile Uint16 soft_start_count = 0; // 소프트 스타트 카운터
volatile _iq duty_target = _IQ(0.0); // 목표 듀티 사이클 (소프트 스타트용, 동적 계산)
volatile Uint16 ovp_count = 0; // OVP 연속 초과 카운터
volatile Uint16 ocp_count = 0; // OCP 연속 초과 카운터
volatile Uint16 fault_reset_flag = 0; // FAULT 복구 플래그 (UART 'F' 명령)
// CLA 전용 변수: CPU-CLA 메모리 공유
#pragma DATA_SECTION(CLA_Vout, "Cla1DataRam0");
#pragma DATA_SECTION(CLA_Iout, "Cla1DataRam0");
#pragma DATA_SECTION(CLA_error, "Cla1DataRam0");
#pragma DATA_SECTION(CLA_duty, "Cla1DataRam0");
volatile _iq CLA_Vout, CLA_Iout, CLA_error, CLA_duty;
// 함수 선언
void initSystem(void); // 시스템 클럭, PIE, CLA 초기화
void initGPIO(void); // GPIO 설정 (PWM, ADC, UART, 스위치)
void initADC(void); // ADC 설정 (Vout, Iout, Vin 샘플링)
void initPWM(void); // PWM 설정 (200kHz Up-Down)
void initCLA(void); // CLA 설정 (PI 연산 오프로드)
void initUART(void); // UART 설정 (SCIA, 115200 baud)
void initTimer0(void); // Timer0 설정 (100ms 주기 UART 전송)
void initInterrupts(void); // 인터럽트 설정 (ADCINT1, CLA Task 1, SCIA RX, Timer0)
void softStart(void); // 소프트 스타트: 듀티 사이클 선형 증가
void checkProtection(void); // OVP/OCP 확인 및 PWM 비활성화
void updateSystemState(Uint16 new_state); // 시스템 상태 업데이트 및 UART 전송
void calculateDutyTarget(void); // 목표 듀티 사이클 동적 계산 (Vin 기반)
__interrupt void adc_isr(void); // ADC ISR: 전압/전류 샘플링, 보호 확인
__interrupt void cla_task1_isr(void); // CLA ISR: PI 연산
__interrupt void scia_rx_isr(void); // UART RX ISR: RUN/STOP/FAULT 복구 명령 처리
__interrupt void timer0_isr(void); // Timer0 ISR: 100ms 주기 UART 전송
void scia_xmit(_iq data, Uint16 type); // UART 데이터 전송 (Vout, Iout, error_count)
void scia_xmit_status(Uint16 status); // UART 상태 전송 (RUN/STOP/FAULT)
// 메인 함수: 시스템 및 주변장치 초기화 후 유휴 루프
void main(void) {
// 시스템 및 주변장치 초기화
initSystem(); // 시스템 클럭(200MHz), PIE, CLA 초기화
initGPIO(); // GPIO 설정 (PWM, ADC, UART, 스위치)
initADC(); // ADC 초기화 (Vout, Iout, Vin)
initPWM(); // PWM 초기화 (200kHz Up-Down)
initCLA(); // CLA 초기화 (PI 연산)
initUART(); // UART 초기화 (SCIA, 115200 baud)
initTimer0(); // Timer0 초기화 (100ms 주기 UART 전송)
initInterrupts(); // 인터럽트 초기화 (ADC, CLA, SCIA RX, Timer0)
// 초기 목표 듀티 사이클 계산 (Vin = 12V 가정)
calculateDutyTarget();
// 글로벌 인터럽트 활성화
EALLOW;
EINT; // 글로벌 인터럽트 활성화
ERTM; // 실시간 인터럽트 활성화
EDIS;
// 초기 상태: STOP
updateSystemState(0); // 시스템 상태를 STOP(0)으로 설정하고 UART로 전송
// 유휴 루프: 외부 스위치 처리
while(1) {
// 외부 스위치(GPIO4) 상태 확인: Low(0) = RUN, High(1) = STOP
if (GpioDataRegs.GPADAT.bit.GPIO4 == 0 && system_state == 0) {
updateSystemState(1); // 스위치로 RUN 전환
} else if (GpioDataRegs.GPADAT.bit.GPIO4 == 1 && system_state == 1) {
updateSystemState(0); // 스위치로 STOP 전환
}
}
}
// 시스템 초기화: 클럭, PIE, CLA 설정
void initSystem(void) {
// 시스템 클럭 설정: 20MHz 크리스털, PLL로 200MHz 생성
InitSysCtrl(); // F28379D: PLL 배수 10, SYSCLK = 20MHz * 10 = 200MHz
DINT; // 모든 인터럽트 비활성화
InitPieCtrl(); // PIE 컨트롤러 초기화
IER = 0x0000; // 인터럽트 인에이블 레지스터 클리어
IFR = 0x0000; // 인터럽트 플래그 레지스터 클리어
InitPieVectTable(); // PIE 벡터 테이블 초기화
InitCla(); // CLA 초기화 (Control Law Accelerator)
}
// GPIO 초기화: PWM, ADC, UART, 외부 스위치 설정
void initGPIO(void) {
EALLOW;
// PWM: ePWM1A (High-Side MOSFET), ePWM1B (Low-Side MOSFET)
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; // GPIO0: ePWM1A
GpioCtrlRegs.GPADIR.bit.GPIO0 = 1; // 출력 방향
GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0; // 풀업 저항 활성화 (MOSFET 드라이버 안정성)
GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; // GPIO1: ePWM1B
GpioCtrlRegs.GPADIR.bit.GPIO1 = 1; // 출력 방향
GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0; // 풀업 저항 활성화
// ADC: Vout, Iout, Vin 센싱
GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 0; // GPIO2: ADCINA0 (Vout, 0~3.3V)
GpioCtrlRegs.GPADIR.bit.GPIO2 = 0; // 입력 방향
GpioCtrlRegs.GPAQSEL1.bit.GPIO2 = 0; // 즉시 샘플링 (RC 필터 가정)
GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 0; // GPIO3: ADCINA1 (Iout, 션트 0.1Ω)
GpioCtrlRegs.GPADIR.bit.GPIO3 = 0; // 입력 방향
GpioCtrlRegs.GPAQSEL1.bit.GPIO3 = 0; // 즉시 샘플링
GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 0; // GPIO5: ADCINA2 (Vin, 분압기 3.3V/15V)
GpioCtrlRegs.GPADIR.bit.GPIO5 = 0; // 입력 방향
GpioCtrlRegs.GPAQSEL1.bit.GPIO5 = 0; // 즉시 샘플링
// 외부 스위치: GPIO4, Low = RUN, High = STOP
GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 0; // GPIO4: 외부 스위치
GpioCtrlRegs.GPADIR.bit.GPIO4 = 0; // 입력 방향
GpioCtrlRegs.GPAPUD.bit.GPIO4 = 1; // 내부 풀업 활성화 (스위치 GND 연결)
GpioCtrlRegs.GPAQSEL1.bit.GPIO4 = 0; // 즉시 샘플링
// UART: SCIA TX/RX
GpioCtrlRegs.GPBMUX1.bit.GPIO28 = 1; // GPIO28: SCIA TX
GpioCtrlRegs.GPBDIR.bit.GPIO28 = 1; // 출력 방향
GpioCtrlRegs.GPBMUX1.bit.GPIO29 = 1; // GPIO29: SCIA RX
GpioCtrlRegs.GPBDIR.bit.GPIO29 = 0; // 입력 방향
EDIS;
}
// ADC 초기화: Vout, Iout, Vin 샘플링 설정
void initADC(void) {
EALLOW;
AdcRegs.ADCCTL2.bit.PRESCALE = 8; // ADC 클럭: SYSCLK/8 = 25MHz
// SOC0: Vout (ADCINA0)
AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADCINA0: Vout 채널
AdcRegs.ADCSOC0CTL.bit.ACQPS = 14; // 샘플링 윈도우: 15 사이클 (75ns @ 200MHz)
AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // 트리거: ePWM1 SOCA (PWM 동기화)
// SOC1: Iout (ADCINA1)
AdcRegs.ADCSOC1CTL.bit.CHSEL = 1; // ADCINA1: Iout 채널
AdcRegs.ADCSOC1CTL.bit.ACQPS = 14; // 샘플링 윈도우: 15 사이클
AdcRegs.ADCSOC1CTL.bit.TRIGSEL = 5; // 트리거: ePWM1 SOCA
// SOC2: Vin (ADCINA2)
AdcRegs.ADCSOC2CTL.bit.CHSEL = 2; // ADCINA2: Vin 채널
AdcRegs.ADCSOC2CTL.bit.ACQPS = 14; // 샘플링 윈도우: 15 사이클
AdcRegs.ADCSOC2CTL.bit.TRIGSEL = 5; // 트리거: ePWM1 SOCA
// 인터럽트 설정
AdcRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // ADCINT1: SOC0 완료 시 발생
AdcRegs.ADCINTSEL1N2.bit.INT1E = 1; // ADCINT1 활성화
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 클리어
AdcRegs.ADCCTL1.bit.INTPULSEPOS = 1; // 인터럽트 펄스: 샘플링 완료 후
AdcRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 전원 활성화
DELAY_US(1000); // ADC 안정화 대기 (1ms)
EDIS;
}
// PWM 초기화: 200kHz Up-Down 모드 설정
void initPWM(void) {
EALLOW;
EPwm1Regs.TBCTL.bit.CTRMODE = 2; // Up-Down 카운트 모드 (대칭 PWM)
EPwm1Regs.TBCTL.bit.PHSEN = 0; // 위상 동기화 비활성화
EPwm1Regs.TBCTL.bit.HSPCLKDIV = 1; // 고속 클럭 분주 1
EPwm1Regs.TBCTL.bit.CLKDIV = 0; // 클럭 분주 없음 (200MHz)
EPwm1Regs.TBPRD = PWM_PERIOD; // 주기: 200MHz / (2 * 200kHz) = 500
EPwm1Regs.CMPA.bit.CMPA = 0; // 초기 듀티 0 (소프트 스타트)
EPwm1Regs.CMPB.bit.CMPB = 0; // Low-Side MOSFET 초기 듀티 0
EPwm1Regs.TBCTR = 0; // 타이머 카운터 초기화
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // SOCA 활성화 (ADC 트리거)
EPwm1Regs.ETSEL.bit.SOCASEL = 1; // SOCA 발생: 주기 시작 시
EPwm1Regs.ETPS.bit.SOCAPRD = 1; // 매 주기마다 SOCA 발생
EPwm1Regs.DBCTL.bit.OUT_MODE = 3; // 데드밴드 완전 활성화
EPwm1Regs.DBCTL.bit.POLSEL = 2; // Active High Complementary 출력
EPwm1Regs.DBRED.bit.DBRED = 10; // Rising Edge Delay: 50ns (10 클럭 @ 200MHz)
EPwm1Regs.DBFED.bit.DBFED = 10; // Falling Edge Delay: 50ns (MOSFET 스위칭 특성 기반)
EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; // 소프트 스톱: PWM 비활성화 시 안전 정지
EDIS;
}
// CLA 초기화: PI 연산을 CLA로 오프로드
void initCLA(void) {
EALLOW;
Cla1Regs.MVECT1 = (Uint16)((Uint32)&cla_task1_isr); // CLA Task 1 ISR 연결
Cla1Regs.MCTL.bit.IACKE = 1; // 인터럽트 ACK 활성화
Cla1Regs.MIER.bit.MINT1 = 1; // Task 1 인터럽트 활성화
EDIS;
}
// UART 초기화: SCIA, 115200 baud, RUN/STOP/FAULT 복구 명령 수신
void initUART(void) {
EALLOW;
SciaRegs.SCICCR.all = 0x0007; // 1 stop bit, No parity, 8-bit 데이터
SciaRegs.SCICTL1.all = 0x0003; // TX, RX 활성화
SciaRegs.SCIHBAUD.all = 0x0000; // Baud rate 상위 비트
SciaRegs.SCILBAUD.all = 216; // 115200 baud: 200MHz / (115200 * 8) - 1
SciaRegs.SCICTL2.bit.RXBKINTENA = 1; // RX 인터럽트 활성화
SciaRegs.SCICTL1.all = 0x0023; // SW reset 해제
EDIS;
}
// Timer0 초기화: 100ms 주기 UART 전송
void initTimer0(void) {
EALLOW;
CpuTimer0Regs.TCR.bit.TSS = 1; // 타이머 정지
CpuTimer0Regs.PRD.all = 20000000; // 100ms @ 200MHz (20000000 사이클)
CpuTimer0Regs.TCR.bit.TRB = 1; // 주기 리로드
CpuTimer0Regs.TCR.bit.TIE = 1; // 인터럽트 활성화
CpuTimer0Regs.TCR.bit.TSS = 0; // 타이머 시작
EDIS;
}
// UART 데이터 전송: Vout(mV), Iout(mA), error_count
void scia_xmit(_iq data, Uint16 type) {
Uint16 val;
Uint32 timeout = 0;
if (type == 0) { // Vout (mV)
val = (Uint16)(_IQtoF(data) * 1000); // IQ24 -> mV
} else if (type == 1) { // Iout (mA)
val = (Uint16)(_IQtoF(data) * 1000); // IQ24 -> mA
} else { // error_count
val = (Uint16)data; // 직접 전송
}
while (SciaRegs.SCIFFTX.bit.TXFFST != 0 && timeout < TX_TIMEOUT_COUNT) {
timeout++; // 타임아웃 카운터 (1ms)
}
if (timeout >= TX_TIMEOUT_COUNT) {
error_count++; // 타임아웃 에러 기록
return;
}
SciaRegs.SCITXBUF.all = val; // 데이터 전송
}
// UART 상태 전송: 시스템 상태 (0: STOP, 1: RUN, 2: FAULT)
void scia_xmit_status(Uint16 status) {
Uint32 timeout = 0;
while (SciaRegs.SCIFFTX.bit.TXFFST != 0 && timeout < TX_TIMEOUT_COUNT) {
timeout++;
}
if (timeout >= TX_TIMEOUT_COUNT) {
error_count++;
return;
}
SciaRegs.SCITXBUF.all = status;
}
// 목표 듀티 사이클 계산: Vout / Vin
void calculateDutyTarget(void) {
if (_IQtoF(Vin) < _IQtoF(VIN_MIN) || _IQtoF(Vin) > _IQtoF(VIN_MAX)) {
duty_target = _IQ(0.208); // 기본값: 2.5V / 12V
} else {
duty_target = _IQdiv(VREF, Vin); // duty = Vout / Vin
if (duty_target > DUTY_MAX) duty_target = DUTY_MAX;
if (duty_target < DUTY_MIN) duty_target = DUTY_MIN;
}
}
// 소프트 스타트: 듀티 사이클을 0에서 목표값까지 선형 증가
void softStart(void) {
if (soft_start_count < SOFT_START_STEPS) {
// 듀티 증가: duty = (soft_start_count / SOFT_START_STEPS) * duty_target
duty = _IQmpy(_IQdiv(_IQ(soft_start_count), _IQ(SOFT_START_STEPS)), duty_target);
EPwm1Regs.CMPA.bit.CMPA = (Uint16)(_IQtoF(duty) * PWM_PERIOD); // PWM 업데이트
soft_start_count++;
} else {
duty = duty_target; // 목표 듀티 도달
EPwm1Regs.CMPA.bit.CMPA = (Uint16)(_IQtoF(duty) * PWM_PERIOD);
}
}
// 보호 기능: OVP, OCP 확인 및 PWM 비활성화
void checkProtection(void) {
// OVP: Vout > 2.75V
if (_IQtoF(Vout) > _IQtoF(V_OVP)) {
ovp_count++;
if (ovp_count >= FAULT_COUNT_MAX) {
updateSystemState(2); // FAULT 상태로 전환
ovp_count = 0; // 카운터 리셋
}
} else {
ovp_count = 0; // 정상 시 카운터 리셋
}
// OCP: Iout > 1.5A
if (_IQtoF(Iout) > _IQtoF(I_OCP)) {
ocp_count++;
if (ocp_count >= FAULT_COUNT_MAX) {
updateSystemState(2); // FAULT 상태로 전환
ocp_count = 0; // 카운터 리셋
}
} else {
ocp_count = 0; // 정상 시 카운터 리셋
}
// FAULT 상태 처리
if (system_state == 2) {
EALLOW;
EPwm1Regs.TBCTL.bit.CTRMODE = 3; // PWM 비활성화
EPwm1Regs.CMPA.bit.CMPA = 0; // 듀티 0
EPwm1Regs.CMPB.bit.CMPB = 0; // Low-Side MOSFET 듀티 0
EDIS;
soft_start_count = 0; // 소프트 스타트 리셋
duty = _IQ(0.0); // 듀티 초기화
duty_prev = _IQ(0.0); // 이전 듀티 초기화
}
}
// 시스템 상태 업데이트: RUN/STOP/FAULT 전환 및 UART 전송
void updateSystemState(Uint16 new_state) {
if (new_state == system_state) return; // 동일 상태면 무시
system_state = new_state;
EALLOW;
if (system_state == 1) { // RUN
EPwm1Regs.TBCTL.bit.CTRMODE = 2; // PWM 활성화 (Up-Down 모드)
soft_start_count = 0; // 소프트 스타트 초기화
duty = _IQ(0.0); // 듀티 초기화
ovp_count = 0; // 보호 카운터 리셋
ocp_count = 0;
} else { // STOP or FAULT
EPwm1Regs.TBCTL.bit.CTRMODE = 3; // PWM 비활성화
EPwm1Regs.CMPA.bit.CMPA = 0; // 듀티 0
EPwm1Regs.CMPB.bit.CMPB = 0; // Low-Side MOSFET 듀티 0
soft_start_count = 0; // 소프트 스타트 리셋
duty = _IQ(0.0); // 듀티 초기화
duty_prev = _IQ(0.0); // 이전 듀티 초기화
ovp_count = 0; // 보호 카운터 리셋
ocp_count = 0;
}
EDIS;
scia_xmit_status(system_state); // 상태 전송
}
// 인터럽트 초기화: ADCINT1, CLA Task 1, SCIA RX, Timer0 설정
void initInterrupts(void) {
EALLOW;
PieVectTable.ADCA1_INT = &adc_isr; // ADCINT1 ISR
PieVectTable.CLA1_1_INT = &cla_task1_isr; // CLA Task 1 ISR
PieVectTable.SCIA_RX_INT = &scia_rx_isr; // SCIA RX ISR
PieVectTable.TIMER0_INT = &timer0_isr; // Timer0 ISR
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // ADCINT1 활성화
PieCtrlRegs.PIEIER11.bit.INTx1 = 1; // CLA 인터럽트 활성화
PieCtrlRegs.PIEIER9.bit.INTx1 = 1; // SCIA RX 인터럽트 활성화
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // Timer0 인터럽트 활성화
IER |= M_INT1 | M_INT9 | M_INT11; // CPU 인터럽트 그룹 1, 9, 11 활성화
EDIS;
}
// ADC ISR: Vout, Iout, Vin 샘플링, 보호 및 소프트 스타트 처리
__interrupt void adc_isr(void) {
// Vout = ADCRESULT0 * (3.3V / 4095)
Vout = _IQmpy(_IQ(AdcaResultRegs.ADCRESULT0), _IQdiv(ADC_VREF, ADC_MAX));
// Iout = ADCRESULT1 * (3.3V / (4095 * 0.1Ω))
Iout = _IQmpy(_IQ(AdcaResultRegs.ADCRESULT1), _IQdiv(ADC_VREF, _IQmpy(ADC_MAX, SHUNT_R)));
// Vin = ADCRESULT2 * (3.3V / 4095) / 0.2 (분압기 비율)
Vin = _IQdiv(_IQmpy(_IQ(AdcaResultRegs.ADCRESULT2), _IQdiv(ADC_VREF, ADC_MAX)), ADC_VIN_SCALE);
// 입력 범위 확인: Vout(0~3.3V), Iout(0~2A), Vin(10~14V)
if (_IQtoF(Vout) < 0.0f || _IQtoF(Vout) > 3.3f ||
_IQtoF(Iout) < 0.0f || _IQtoF(Iout) > 2.0f ||
_IQtoF(Vin) < _IQtoF(VIN_MIN) || _IQtoF(Vin) > _IQtoF(VIN_MAX)) {
error_count++; // 에러 카운터 증가
Vout = _IQ(0.0); // 기본값 설정
Iout = _IQ(0.0);
Vin = _IQ(12.0); // 기본 입력 전압
}
// 목표 듀티 사이클 업데이트
calculateDutyTarget();
// CLA로 데이터 전달
CLA_Vout = Vout;
CLA_Iout = Iout;
// 보호 기능 확인
checkProtection();
// RUN 상태에서만 소프트 스타트 및 CLA 트리거
if (system_state == 1) {
softStart(); // 소프트 스타트 처리
if (soft_start_count >= SOFT_START_STEPS) {
Cla1Regs.MIFRC.bit.INT1 = 1; // CLA Task 1 트리거 (소프트 스타트 완료 후)
}
}
AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
// CLA ISR: PI 제어기 연산 (VMC)
// 이산 PI 제어기: u[n] = u[n-1] + 0.1025 e[n] - 0.0975 e[n-1]
// 계산 근거: KP = 0.1, KI = 1000, TS = 5us
// 비례항: KP * e[n] = 0.1 * e[n]
// 적분항: KI * TS * e[n] = 1000 * 5e-6 * e[n] = 0.005 * e[n]
// 이산화: u[n] = u[n-1] + KP * e[n] + KI * TS * e[n] - KP * e[n-1]
__interrupt void cla_task1_isr(void) {
if (system_state != 1 || soft_start_count < SOFT_START_STEPS) {
Cla1Regs.MIRUN.bit.INT1 = 0; // CLA 인터럽트 클리어
return; // RUN 상태 또는 소프트 스타트 완료 후에만 연산
}
// 오차 계산: e[n] = Vref - Vout
CLA_error = _IQmpy(VREF - CLA_Vout, _IQ(1.0));
// 이산 PI 제어기
CLA_duty = duty_prev + _IQmpy(_IQ(0.1025), CLA_error) - _IQmpy(_IQ(0.0975), error_prev);
// 듀티 사이클 제한: 0.1~0.9
if (CLA_duty > DUTY_MAX) CLA_duty = DUTY_MAX;
if (CLA_duty < DUTY_MIN) CLA_duty = DUTY_MIN;
// PWM 업데이트
EPwm1Regs.CMPA.bit.CMPA = (Uint16)(_IQtoF(CLA_duty) * PWM_PERIOD);
error_prev = CLA_error; // 이전 오차 저장
duty_prev = CLA_duty; // 이전 듀티 저장
Cla1Regs.MIRUN.bit.INT1 = 0; // CLA 인터럽트 클리어
}
// UART RX ISR: RUN('R'), STOP('S'), FAULT 복구('F') 명령 처리
__interrupt void scia_rx_isr(void) {
Uint16 rx_data = SciaRegs.SCIRXBUF.all; // 수신 데이터 읽기
if (rx_data == 'R' && system_state == 0) {
updateSystemState(1); // RUN 상태로 전환
} else if (rx_data == 'S' && system_state == 1) {
updateSystemState(0); // STOP 상태로 전환
} else if (rx_data == 'F' && system_state == 2) {
fault_reset_flag = 1; // FAULT 복구 플래그 설정
if (ovp_count == 0 && ocp_count == 0) {
updateSystemState(0); // FAULT 조건 해제 시 STOP으로 복구
}
}
SciaRegs.SCIFFRX.bit.RXFFOVRCLR = 1; // 오버플로우 플래그 클리어
SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1; // RX 인터럽트 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP9; // PIE 그룹 9 ACK
}
// Timer0 ISR: 100ms 주기 UART 전송
__interrupt void timer0_isr(void) {
// UART로 Vout, Iout, error_count, 상태 전송
scia_xmit(Vout, 0); // Vout (mV)
scia_xmit(Iout, 1); // Iout (mA)
scia_xmit(_IQ(error_count), 2); // error_count
scia_xmit_status(system_state); // 상태 (0: STOP, 1: RUN, 2: FAULT)
CpuTimer0Regs.TCR.bit.TIF = 1; // 인터럽트 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
7. 시뮬레이션 및 검증
VMC 구현은 MATLAB/Simulink와 Code Composer Studio(CCS)를 사용해 검증되었습니다.
- Simulink 시뮬레이션:
- 플랜트 모델 (\( G_{vd}(s) \))과 이산 PI 제어기 (\( G_c(z) \))를 결합하여 폐루프 응답을 분석.
- 부하 스텝(0.5A→1A)에서 과도 응답 시간 \(\leq 100\mu s\), 리플 \(\leq 25mV\) 확인.
- 소프트 스타트: 10ms 동안 출력 전압이 선형적으로 0V에서 2.5V로 증가.
- 하드웨어 검증:
- CCS를 통해 코드 디버깅, UART로 \( V_{out}, I_{out} \), 상태 모니터링.
- 오실로스코프(Tektronix TBS2000)로 전압 리플, 스위칭 파형, 과도 응답 확인.
- OVP: \( V_{out} > 2.75V \) 시 PWM 비활성화 및 FAULT 상태 전환 확인.
- OCP: \( I_{out} > 1.5A \) 시 PWM 비활성화 및 FAULT 상태 전환 확인.
- 외부 스위치(GPIO4) 및 UART 명령('R'/'S')으로 RUN/STOP 동작 확인.
'Power Electronics > DC-DC변환' 카테고리의 다른 글
TI C2000 DSP를 사용한 양방향 CLLC 컨버터의 디지털 제어기 설계 (1) | 2025.08.27 |
---|---|
TI C2000 DSP를 사용한 PSFB 컨버터 2차측 동기 정류 디지털 제어기 설계 (2) | 2025.08.26 |
TI C2000 DSP를 사용한 LLC 풀-브릿지 컨버터 2차측 동기 정류 디지털 제어기 설계 (0) | 2025.08.26 |
TI C2000 DSP를 사용한 Boost 컨버터 디지털 제어기 설계-PCMC (0) | 2025.08.26 |
TI C2000 DSP를 사용한 Buck 컨버터 디지털 제어기 설계-PCMC (2) | 2025.08.26 |
양방향 전력 전송 공진형 CLLC 컨버터 설계 절차 (1) | 2025.08.21 |
PSFB(Phase-Shifted Full-Bridge) 컨버터 설계 절차 (0) | 2025.08.19 |
양방향 전력 전송 공진형 CLLC 컨버터 설계 절차 및 제어기 분석 (2) | 2025.08.19 |