본문 바로가기
Power Electronics/DC-DC변환

TI C2000 DSP를 사용한 양방향 CLLC 컨버터의 디지털 제어기 설계

by linuxgo 2025. 8. 27.
반응형

1. 서론

이 문서는 TI C2000 DSP(F28379D)를 활용한 양방향 CLLC 공진 컨버터의 디지털 제어기 설계 과정을 상세히 기술합니다. CLLC 컨버터는 1차측과 2차측 풀-브릿지 구조를 통해 양방향 전력 전송을 지원하며, 제로 전압 스위칭(ZVS)과 제로 전류 스위칭(ZCS)을 구현하여 고효율 전력 변환을 달성합니다. 본 설계의 주요 목적은 주파수 변조(FM)를 기반으로 안정적인 출력 전압(48V)과 전류(±10A)를 유지하고, 소프트 스타트(20ms), 과전압 보호(OVP, 52.8V), 과전류 보호(OCP, 15A)를 포함한 안전 기능을 구현하는 것입니다. 제어는 UART 명령('R'/'S')과 외부 스위치(GPIO10)를 통해 수행되며, 동기 정류(SR)를 통해 2차측 효율을 극대화합니다. 설계는 아날로그 모델링(상태-공간 및 소신호 분석), 디지털 제어기 설계(PI 제어기, Tustin 변환), MATLAB/Simulink 시뮬레이션, 그리고 F28379D 하드웨어 구현을 포함하며, CLA와 IQmath를 활용해 고속 연산을 지원합니다. 이 문서는 설계 요구사항, 수학적 모델링, 코드 구현, 시뮬레이션 및 하드웨어 검증을 체계적으로 다룹니다.

2. 설계 요구사항

  • 입력 전압 (\( V_{in} \)): 300V ~ 400V
  • 출력 전압 (\( V_{out} \)): 48V (양방향)
  • 출력 전류 (\( I_{out} \)): ±10A
  • 스위칭 주파수 (\( f_{sw} \)): 100kHz ~ 200kHz (\( f_r = 150kHz \))
  • 샘플링 주기 (\( T_s \)): 5μs
  • 제어 방식: FM, 1차/2차 풀-브릿지 동기 정류
  • 성능 목표:
    • 리플: \( \leq 480mV \)
    • 과도 응답: \( \leq 200\mu s \)
    • 위상 마진: 45° ~ 60°
    • 대역폭: ~10kHz
  • 기능: UART ('R'/'S'), GPIO10 스위치, 소프트 스타트(20ms), OVP (\( V_{out} > 52.8V \)), OCP (\( |I_{out}| > 15A \))
  • 플랫폼: F28379D LaunchPad, 200MHz, CLA/IQmath

3. CLLC 설계 절차

  • 출력 전력: \[ P_{out} = V_{out} \times I_{out} = 48 \times 10 = 480 \, \text{W} \]
  • 입력 전력 (\( \eta = 0.95 \)): \[ P_{in} = \frac{480}{0.95} = 505.2631578947368 \, \text{W} \]
  • 입력 전류 (\( V_{in,min} = 300 \, \text{V} \)): \[ I_{in,rms} = \frac{505.2631578947368}{300 / \sqrt{2}} \approx 2.3817 \, \text{A} \]
  • 턴 비율 (\( n \)): \[ n = \frac{300 / 2}{48} = 3.125 \rightarrow 3 \]
  • 공진 탱크: \[ L_{r1} = L_{r2} = 50 \, \mu H, \quad C_{r1} = C_{r2} = 22 \, \text{nF} \] \[ f_r = \frac{1}{2\pi \sqrt{L_{r1} C_{r1}}} \approx 151716.482 \, \text{Hz} \]
  • 이득: \[ M_{min} = \frac{48}{400 / (2 \times 3)} \approx 0.72, \quad M_{max} = \frac{48}{300 / (2 \times 3)} = 0.96 \]

4. 아날로그 모델링

4.1 State-Space 모델

4.1.1 회로 구성

1차측 풀-브릿지로 \( v_{in} \) 스위칭, 공진 탱크(\( L_{r1}, C_{r1} \)). 2차측 풀-브릿지 SR로 \( V_{out} \) 생성. 트랜스포머: \( n = 3 \), \( L_m = 300 \, \mu H \). 상태 변수: \( i_{r1}, v_{Cr1}, i_{r2}, v_{Cr2}, i_m \).

4.1.2 상태 방정식 유도

FHA로 1차 고조파 근사, KVL/KCL 적용:

  1. 1차측 KVL: \[ v_{in} = L_{r1} \frac{d i_{r1}}{dt} + v_{Cr1} + n v_{Cr2} \] \[ \frac{d i_{r1}}{dt} = \frac{1}{L_{r1}} v_{in} - \frac{1}{L_{r1}} v_{Cr1} - \frac{n}{L_{r1}} v_{Cr2} \]
  2. 1차측 KCL: \[ i_{r1} = C_{r1} \frac{d v_{Cr1}}{dt}, \quad \frac{d v_{Cr1}}{dt} = \frac{1}{C_{r1}} i_{r1} \]
  3. 2차측 KVL: \[ n v_{Cr1} = L_{r2} \frac{d i_{r2}}{dt} + v_{Cr2} + V_{out} \] \[ \frac{d i_{r2}}{dt} = \frac{n}{L_{r2}} v_{Cr1} - \frac{1}{L_{r2}} v_{Cr2} - \frac{1}{L_{r2}} V_{out} \]
  4. 2차측 KCL: \[ i_{r2} = C_{r2} \frac{d v_{Cr2}}{dt}, \quad \frac{d v_{Cr2}}{dt} = \frac{1}{C_{r2}} i_{r2} \]
  5. 자화 인덕터: \[ n v_{Cr2} = L_m \frac{d i_m}{dt}, \quad \frac{d i_m}{dt} = \frac{n}{L_m} v_{Cr2} \]
  6. 부하 전류: \[ i_{r2} - i_m = \frac{V_{out}}{R_{eq}}, \quad R = \frac{48}{10} = 4.8 \, \Omega \] \[ R_{eq} = \frac{8 \times 3^2 \times 4.8}{\pi^2} \approx 35.01368576 \, \Omega \]

상태 방정식 행렬:

\[ \frac{d}{dt} \begin{bmatrix} i_{r1} \\ v_{Cr1} \\ i_{r2} \\ v_{Cr2} \\ i_m \end{bmatrix} = \begin{bmatrix} 0 & -\frac{1}{L_{r1}} & 0 & -\frac{n}{L_{r1}} & 0 \\ \frac{1}{C_{r1}} & 0 & 0 & 0 & 0 \\ 0 & \frac{n}{L_{r2}} & 0 & -\frac{1}{L_{r2}} & 0 \\ 0 & 0 & \frac{1}{C_{r2}} & 0 & 0 \\ 0 & 0 & 0 & \frac{n}{L_m} & 0 \end{bmatrix} \begin{bmatrix} i_{r1} \\ v_{Cr1} \\ i_{r2} \\ v_{Cr2} \\ i_m \end{bmatrix} + \begin{bmatrix} \frac{1}{L_{r1}} \\ 0 \\ 0 \\ 0 \\ 0 \end{bmatrix} v_{in} + \begin{bmatrix} 0 \\ 0 \\ -\frac{1}{R_{eq}} \\ 0 \\ \frac{1}{R_{eq}} \end{bmatrix} V_{out} \]

출력 방정식:

\[ V_{out} = R_{eq} (i_{r2} - i_m) \]

4.1.3 파라미터 대입

계수:

  • \( L_{r1} = L_{r2} = 50 \times 10^{-6} \, \text{H} \), \( C_{r1} = C_{r2} = 22 \times 10^{-9} \, \text{F} \), \( L_m = 300 \times 10^{-6} \, \text{H} \), \( n = 3 \), \( R_{eq} \approx 35.01368576 \, \Omega \)
  • \( \frac{1}{L_{r1}} = 20000 \), \( \frac{n}{L_{r1}} = 60000 \), \( \frac{1}{C_{r1}} \approx 45454545.45454545 \)
  • \( \frac{n}{L_{r2}} = 60000 \), \( \frac{1}{L_{r2}} = 20000 \), \( \frac{1}{C_{r2}} \approx 45454545.45454545 \)
  • \( \frac{n}{L_m} = 10000 \), \( \frac{1}{R_{eq}} \approx 0.02855844156 \)

검증: MATLAB으로 확인:

Lr1 = 50e-6; Cr1 = 22e-9; Lr2 = 50e-6; Cr2 = 22e-9; Lm = 300e-6; n = 3; R = 4.8;
Req = 8 * n^2 * R / pi^2;
A = [0, -1/Lr1, 0, -n/Lr1, 0; 1/Cr1, 0, 0, 0, 0; 0, n/Lr2, 0, -1/Lr2, 0; 0, 0, 1/Cr2, 0, 0; 0, 0, 0, n/Lm, 0];
B = [1/Lr1, 0; 0, 0; 0, -1/Req; 0, 0; 0, 1/Req];
C = [0, 0, Req, 0, -Req];
D = [0, 0];
sys = ss(A, B, C, D);
figure; step(sys); grid on;
    

4.2 소신호 모델

4.2.1 FHA 기반 이득

가정: \( v_{in} = \frac{4 V_{in}}{\pi} \sin(2 \pi f_{sw} t) \), \( f_{sw} \approx f_r \).

이득 공식:

\[ R_{eq} \approx 35.01368576 \, \Omega \] \[ Q = \frac{\sqrt{\frac{50 \times 10^{-6}}{22 \times 10^{-9}}}}{35.01368576} \approx 1.361357977 \] \[ M(\omega) = \frac{1}{\sqrt{\left(1 + \frac{L_{r1}}{L_m} \left(1 - \frac{\omega_r^2}{\omega^2}\right) + \frac{L_{r2}}{n^2 L_m} \left(1 - \frac{\omega_r^2}{\omega^2}\right)\right)^2 + \left(Q \left(\frac{\omega}{\omega_r} - \frac{\omega_r}{\omega}\right)\right)^2}} \]

계수: \( \frac{L_{r1}}{L_m} = 0.1666666667 \), \( \frac{L_{r2}}{n^2 L_m} \approx 0.01851851852 \), \( \omega_r \approx 942477.7960769379 \, \text{rad/s} \).

4.2.2 소신호 전달 함수

\[ G_{vf}(s) = \frac{-0.00032}{1 + 1.428446084 \times 10^{-6} s + 1.1 \times 10^{-12} s^2} \]

검증: MATLAB으로 확인:

Vout = 48; fr = 150000; Lr1 = 50e-6; Cr1 = 22e-9; R = 4.8; n = 3;
Req = 8 * n^2 * R / pi^2;
K = -Vout / fr;
Gvf = tf(K, [Lr1*Cr1, Lr1/Req, 1]);
figure; bode(Gvf); grid on;
figure; step(Gvf); grid on;
    

5. 디지털 제어기 설계

5.1 아날로그 PI 제어기

\[ G_c(s) = \frac{0.2 s + 2000}{s} \]

검증: MATLAB으로 위상 마진 ~50° 확인:

Kp = 0.2; Ki = 2000;
Gc = tf([Kp Ki], [1 0]);
Gol = series(Gc, Gvf);
[Gm, Pm] = margin(Gol);
figure; step(Gol); grid on;
    

5.2 디지털 변환 (Tustin with Pre-warping)

샘플링 주기: \( T_s = 5 \times 10^{-6} \, \text{s} \).

Tustin 변환:

\[ s = \frac{2}{T_s} \cdot \frac{z - 1}{z + 1} = 400000 \cdot \frac{z - 1}{z + 1} \]

Pre-warping (\( \omega_p = 2 \pi \times 10000 \)):

\[ \frac{\omega_p T_s}{2} = 0.15707963267948966 \] \[ \tan\left(0.15707963267948966\right) \approx 0.15838444032453627 \] \[ s \approx 396693.4983164983 \cdot \frac{z - 1}{z + 1} \]

이산 전달 함수:

\[ G_c(z) \approx \frac{0.205 z - 0.195}{z - 1} \]

차분 방정식:

\[ u[n] = u[n-1] + 0.205 e[n] - 0.195 e[n-1] \]

검증: MATLAB으로 확인:

Ts = 5e-6; wp = 2 * pi * 10000;
Gc = tf([0.2 2000], [1 0]);
Gc_d = c2d(Gc, Ts, 'tustin', 'PrewarpFrequency', wp);
figure; step(Gc_d); grid on;
    

5.3 양방향 SR 설계

CMPSS로 전류 제로 크로싱 감지, 데드타임 100ns, DAC 설정: \( V_{DAC} = 2048 \) (3.3V/2).

6. TI C2000 DSP 구현

#include "F28x_Project.h"
#include "IQmathLib.h"

// 상수 정의
#define VREF _IQ(48.0)            // 출력 전압 기준값: 48V (CLLC 컨버터 목표 출력)
#define KP _IQ(0.2)               // PI 제어기 비례 게인 (전압 제어 안정성 조정)
#define KI _IQ(2000.0)            // PI 제어기 적분 게인 (정상 상태 오차 제거)
#define TS _IQ(0.000005)          // 샘플링 주기: 5us (200kHz 제어 루프)
#define ADC_VREF _IQ(3.3)         // ADC 기준 전압: 3.3V (F28379D ADC 하드웨어)
#define ADC_MAX _IQ(4095.0)       // 12비트 ADC 최대값 (2^12 - 1)
#define FSW_INIT _IQ(150000.0)    // 초기 스위칭 주파수: 150kHz (공진 주파수 기준)
#define FSW_MIN _IQ(80000.0)      // 최소 스위칭 주파수: 80kHz (ZVS 범위 하한)
#define FSW_MAX _IQ(250000.0)     // 최대 스위칭 주파수: 250kHz (ZVS 범위 상한)
#define DEAD_TIME _IQ(0.0000001)  // 데드타임: 100ns (ZVS 보장, 스위치 보호)
#define SHUNT_R _IQ(0.005)        // 션트 저항: 5mΩ (전류 측정용)
#define V_OVP _IQ(52.8)           // 과전압 보호 임계값: 52.8V (48V + 10%)
#define I_OCP _IQ(15.0)           // 과전류 보호 임계값: 15A (안전 마진)
#define SOFT_START_TIME _IQ(0.02) // 소프트 스타트 시간: 20ms (인러시 전류 방지)
#define SOFT_START_STEPS 4000     // 소프트 스타트 단계 수 (20ms / 5us)
#define ERROR_COUNT_MAX 10        // ADC 오류 최대 허용 횟수 (보호 트리거)
#define TIMER0_PERIOD 20000000    // CPU Timer0 주기: 100ms (200MHz / 10Hz)
#define IOUT_DELTA_THRESH _IQ(1.0)// 부하 변화 감지 임계값: 1A (fsw_target 조정)
#define FSW_ADJUST_STEP _IQ(5000.0) // fsw_target 조정 스텝: 5kHz

// 전역 변수
volatile _iq Vout = _IQ(0.0);        // 측정된 출력 전압 (ADC 변환 결과)
volatile _iq Iout = _IQ(0.0);        // 측정된 출력 전류 (션트 저항 기반)
volatile _iq Iout_prev = _IQ(0.0);   // 이전 출력 전류 (부하 변화 감지용)
volatile _iq error = _IQ(0.0);       // 전압 오차 (Vref - Vout)
volatile _iq fsw = _IQ(0.0);         // 현재 스위칭 주파수 (PWM 제어)
volatile _iq error_prev = _IQ(0.0);  // 이전 오차 (PI 제어기용)
volatile _iq fsw_prev = _IQ(0.0);    // 이전 스위칭 주파수 (PI 안정성)
volatile Uint16 error_count = 0;      // ADC 이상 값 카운터 (보호 감지)
volatile Uint16 system_state = 0;     // 시스템 상태: 0=정지, 1=동작, 2=보호
volatile Uint16 soft_start_count = 0; // 소프트 스타트 진행 카운터
volatile _iq fsw_target = FSW_INIT;  // 목표 스위칭 주파수 (부하 적응)
volatile Uint16 power_direction = 0;  // 전력 방향: 0=정방향, 1=역방향 (CLLC 양방향)

// 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_fsw, "Cla1DataRam0");
volatile _iq CLA_Vout, CLA_Iout, CLA_error, CLA_fsw;

// CLA 태스크 선언 (별도 .cla 파일에서 구현)
extern void Cla1Task1(void);

void initSystem(void) {
    // 시스템 초기화: F28379D의 클럭, PLL, 인터럽트 설정
    InitSysCtrl(); // 200MHz SYSCLK 설정 (F28379D PLL 초기화)
    DINT;          // 글로벌 인터럽트 비활성화 (안전 초기화)
    InitPieCtrl(); // PIE (Peripheral Interrupt Expansion) 초기화
    IER = 0x0000; IFR = 0x0000; // 인터럽트 레지스터 클리어
    InitPieVectTable(); // 인터럽트 벡터 테이블 설정
    // CLA 클럭 활성화 (F28379D의 CLA1 모듈용)
    EALLOW;
    SysCtrlRegs.PCLKCR3.bit.CLA1ENCLK = 1; // CLA1 클럭 활성화
    EDIS;
}

void initGPIO(void) {
    // GPIO 설정: PWM 출력, ADC 입력, UART, 외부 스위치 (F28379D 핀아웃 기준)
    EALLOW;
    // 1차측 풀-브릿지 PWM: ePWM1A/B=GPIO0/1, ePWM2A/B=GPIO2/3
    GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 1; GpioCtrlRegs.GPADIR.bit.GPIO0 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO0 = 0; // ePWM1A
    GpioCtrlRegs.GPAMUX1.bit.GPIO1 = 1; GpioCtrlRegs.GPADIR.bit.GPIO1 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO1 = 0; // ePWM1B
    GpioCtrlRegs.GPAMUX1.bit.GPIO2 = 1; GpioCtrlRegs.GPADIR.bit.GPIO2 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO2 = 0; // ePWM2A
    GpioCtrlRegs.GPAMUX1.bit.GPIO3 = 1; GpioCtrlRegs.GPADIR.bit.GPIO3 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO3 = 0; // ePWM2B
    // 2차측 동기정류(SR) PWM: ePWM3A/B=GPIO4/5, ePWM4A/B=GPIO6/7
    GpioCtrlRegs.GPAMUX1.bit.GPIO4 = 1; GpioCtrlRegs.GPADIR.bit.GPIO4 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO4 = 0; // ePWM3A
    GpioCtrlRegs.GPAMUX1.bit.GPIO5 = 1; GpioCtrlRegs.GPADIR.bit.GPIO5 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO5 = 0; // ePWM3B
    GpioCtrlRegs.GPAMUX1.bit.GPIO6 = 1; GpioCtrlRegs.GPADIR.bit.GPIO6 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO6 = 0; // ePWM4A
    GpioCtrlRegs.GPAMUX1.bit.GPIO7 = 1; GpioCtrlRegs.GPADIR.bit.GPIO7 = 1; GpioCtrlRegs.GPAPUD.bit.GPIO7 = 0; // ePWM4B
    // ADC 입력: ADCINA0=GPIO58 (Vout), ADCINA1=GPIO59 (Iout)
    GpioCtrlRegs.GPBMUX2.bit.GPIO58 = 0; GpioCtrlRegs.GPBDIR.bit.GPIO58 = 0; GpioCtrlRegs.GPBQSEL2.bit.GPIO58 = 0; // ADCINA0
    GpioCtrlRegs.GPBMUX2.bit.GPIO59 = 0; GpioCtrlRegs.GPBDIR.bit.GPIO59 = 0; GpioCtrlRegs.GPBQSEL2.bit.GPIO59 = 0; // ADCINA1
    // 외부 스위치: GPIO12 (LaunchPad 스위치, 풀업 저항 활성화)
    GpioCtrlRegs.GPAMUX1.bit.GPIO12 = 0; GpioCtrlRegs.GPADIR.bit.GPIO12 = 0; GpioCtrlRegs.GPAPUD.bit.GPIO12 = 1;
    // UART: SCIA TX=GPIO28, RX=GPIO29 (시리얼 통신)
    GpioCtrlRegs.GPBMUX1.bit.GPIO28 = 1; GpioCtrlRegs.GPBDIR.bit.GPIO28 = 1; // TX
    GpioCtrlRegs.GPBMUX1.bit.GPIO29 = 1; GpioCtrlRegs.GPBDIR.bit.GPIO29 = 0; // RX
    EDIS;
}

void initADC(void) {
    // ADC 설정: 출력 전압(Vout) 및 전류(Iout) 측정 (ADC 모듈 A 사용)
    EALLOW;
    AdcaRegs.ADCCTL2.bit.PRESCALE = 8; // ADC 클럭: SYSCLK/8 (25MHz)
    AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // SOC0: ADCINA0 (Vout)
    AdcaRegs.ADCSOC0CTL.bit.ACQPS = 25; // 샘플링 윈도우: 25 SYSCLK (노이즈 감소)
    AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // 트리거: ePWM1 SOCA
    AdcaRegs.ADCSOC1CTL.bit.CHSEL = 1; // SOC1: ADCINA1 (Iout)
    AdcaRegs.ADCSOC1CTL.bit.ACQPS = 25;
    AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 5;
    AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 1; // INT1: SOC1 완료 시 트리거
    AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // 인터럽트 활성화
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // 인터럽트 플래그 클리어
    AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // 인터럽트 펄스 위치: 샘플링 완료
    AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 전원 활성화
    DELAY_US(1000); // ADC 안정화 대기 (1ms)
    EDIS;
}

void initPWM(void) {
    // PWM 설정: 1차측 풀-브릿지 및 2차측 동기정류(SR) 제어 (대칭 PWM)
    EALLOW;
    // ePWM1: 1차측 Q1/Q2 (마스터 모듈)
    EPwm1Regs.TBCTL.bit.CTRMODE = 2; // Up-Down 카운트 (대칭 PWM, ZVS 최적화)
    EPwm1Regs.TBCTL.bit.PHSEN = 0;   // 위상 동기화 비활성화 (마스터)
    EPwm1Regs.TBCTL.bit.HSPCLKDIV = 1; EPwm1Regs.TBCTL.bit.CLKDIV = 0; // 200MHz 클럭
    EPwm1Regs.TBPRD = (Uint16)(200e6 / (2 * _IQtoF(FSW_INIT))); // 주기: 150kHz
    EPwm1Regs.CMPA.bit.CMPA = EPwm1Regs.TBPRD / 2; // 50% 듀티 사이클
    EPwm1Regs.TBCTR = 0; // 타이머 카운터 초기화
    EPwm1Regs.ETSEL.bit.SOCAEN = 1; EPwm1Regs.ETSEL.bit.SOCASEL = 2; // SOCA: CTR=PRD
    EPwm1Regs.ETPS.bit.SOCAPRD = 1; // ADC 트리거 주기
    EPwm1Regs.DBCTL.bit.OUT_MODE = 3; // 데드타임 활성화 (A/B 모두)
    EPwm1Regs.DBRED.bit.DBRED = (Uint16)(_IQtoF(DEAD_TIME) * 200e6); // 상승 데드타임
    EPwm1Regs.DBFED.bit.DBFED = (Uint16)(_IQtoF(DEAD_TIME) * 200e6); // 하강 데드타임
    // ePWM2: 1차측 Q3/Q4 (ePWM1과 동기화)
    EPwm2Regs.TBCTL.bit.CTRMODE = 2;
    EPwm2Regs.TBCTL.bit.PHSEN = 1; // ePWM1 동기화
    EPwm2Regs.TBCTL.bit.SYNCOSEL = 0; // EPWM1SYNCI 입력
    EPwm2Regs.TBPHS.bit.TBPHS = 0; // 위상 오프셋 0
    EPwm2Regs.TBPRD = EPwm1Regs.TBPRD;
    EPwm2Regs.CMPA.bit.CMPA = EPwm1Regs.CMPA.bit.CMPA;
    EPwm2Regs.DBCTL.bit.OUT_MODE = 3;
    EPwm2Regs.DBRED.bit.DBRED = EPwm1Regs.DBRED.bit.DBRED;
    EPwm2Regs.DBFED.bit.DBFED = EPwm1Regs.DBFED.bit.DBFED;
    // ePWM3: 2차측 SR Q1/Q2 (동기 정류, 위상 시프트 가능)
    EPwm3Regs.TBCTL.bit.CTRMODE = 2;
    EPwm3Regs.TBCTL.bit.PHSEN = 1;
    EPwm3Regs.TBCTL.bit.SYNCOSEL = 0;
    EPwm3Regs.TBPHS.bit.TBPHS = 0; // 초기 동기
    EPwm3Regs.TBPRD = EPwm1Regs.TBPRD;
    EPwm3Regs.CMPA.bit.CMPA = EPwm1Regs.CMPA.bit.CMPA;
    EPwm3Regs.DBCTL.bit.OUT_MODE = 3;
    EPwm3Regs.DBRED.bit.DBRED = EPwm1Regs.DBRED.bit.DBRED;
    EPwm3Regs.DBFED.bit.DBFED = EPwm1Regs.DBFED.bit.DBFED;
    // ePWM4: 2차측 SR Q3/Q4
    EPwm4Regs.TBCTL.bit.CTRMODE = 2;
    EPwm4Regs.TBCTL.bit.PHSEN = 1;
    EPwm4Regs.TBCTL.bit.SYNCOSEL = 0;
    EPwm4Regs.TBPHS.bit.TBPHS = 0;
    EPwm4Regs.TBPRD = EPwm1Regs.TBPRD;
    EPwm4Regs.CMPA.bit.CMPA = EPwm1Regs.CMPA.bit.CMPA;
    EPwm4Regs.DBCTL.bit.OUT_MODE = 3;
    EPwm4Regs.DBRED.bit.DBRED = EPwm1Regs.DBRED.bit.DBRED;
    EPwm4Regs.DBFED.bit.DBFED = EPwm1Regs.DBFED.bit.DBFED;
    EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; // 프리-런 모드 (정지 시 계속 실행)
    EDIS;
}

void initCMPSS(void) {
    // CMPSS 설정: 전류 제로 크로싱 감지 (동기 정류용)
    EALLOW;
    Cmpss1Regs.COMPCTL.bit.COMPDACE = 1; // 비교기 활성화
    Cmpss1Regs.COMPCTL.bit.COMPHSOURCE = 0; // 내부 DAC 소스
    Cmpss1Regs.COMPDACCTL.bit.DACSOURCE = 0; // DAC 사용
    Cmpss1Regs.DACHVALS.bit.DACVAL = 2048; // 기준: 3.3V/2 (제로 크로싱 초기값)
    Cmpss1Regs.COMPCTL.bit.ASYNCHEN = 1; // 비동기 출력 (지연 최소화)
    Cmpss1Regs.COMPSTSCLR.bit.HLATCHCLR = 1; // 래치 클리어
    Cmpss1Regs.COMPCTL.bit.COMPLINV = 0; // 비반전 입력
    Cmpss1Regs.COMPCTL.bit.CTRIPHSEL = 1; // 고속 출력 경로
    EDIS;
}

void initCLA(void) {
    // CLA 설정: 고속 PI 제어 연산 (Cla1Task1.cla에서 실행)
    EALLOW;
    Cla1Regs.MVECT1 = (Uint16)((Uint32)Cla1Task1 - 0x008000); // CLA 태스크1 벡터 (프로그램 메모리 오프셋)
    Cla1Regs.MPISRCSEL1.bit.PERINT1SEL = 0; // 소프트웨어 트리거 (adc_isr에서 MIFRC)
    Cla1Regs.MCTL.bit.IACKE = 1; // 인터럽트 확인 활성화
    Cla1Regs.MIER.bit.MINT1 = 1; // 태스크1 인터럽트 활성화
    EDIS;
}

void initUART(void) {
    // UART 설정: 외부 명령 수신 및 상태 전송 (115200 보율)
    EALLOW;
    SciaRegs.SCICCR.all = 0x0007; // 8비트 데이터, 1 스톱 비트, 패리티 없음
    SciaRegs.SCICTL1.all = 0x0003; // 송수신 활성화
    SciaRegs.SCIHBAUD.all = 0x0000; SciaRegs.SCILBAUD.all = 216; // 115200 보율 (200MHz 기준)
    SciaRegs.SCICTL2.bit.RXBKINTENA = 1; // 수신 인터럽트 활성화
    SciaRegs.SCICTL1.all = 0x0023; // UART 최종 활성화
    EDIS;
}

void initTimer0(void) {
    // CPU Timer0 설정: 100ms 주기 상태 전송
    EALLOW;
    CpuTimer0Regs.PRD.all = TIMER0_PERIOD - 1; // 주기: 200MHz / 10Hz = 20M cycles
    CpuTimer0Regs.TCR.bit.TSS = 1; // 타이머 정지 (초기화)
    CpuTimer0Regs.TCR.bit.TRB = 1; // 주기 리로드
    CpuTimer0Regs.TCR.bit.TIE = 1; // 인터럽트 활성화
    CpuTimer0Regs.TCR.bit.FREE = 0; // 프리-런 비활성화
    EDIS;
}

void scia_xmit(_iq data, Uint16 is_current) {
    // UART 데이터 전송: 전압(0.1V 단위) 또는 전류(mA 단위)
    Uint16 val = is_current ? (Uint16)(_IQtoF(data) * 1000) : (Uint16)(_IQtoF(data) * 100); // 스케일링
    while (SciaRegs.SCIFFTX.bit.TXFFST != 0); // 송신 버퍼 대기
    SciaRegs.SCITXBUF.all = val; // 데이터 전송
}

void scia_xmit_status(Uint16 status) {
    // 시스템 상태 전송 (0: 정지, 1: 동작, 2: 보호)
    while (SciaRegs.SCIFFTX.bit.TXFFST != 0); // 송신 버퍼 대기
    SciaRegs.SCITXBUF.all = status;
}

void softStart(void) {
    // 소프트 스타트: 20ms 동안 주파수를 FSW_MAX(250kHz)에서 fsw_target(150kHz)으로 선형 감소
    if (soft_start_count < SOFT_START_STEPS) {
        fsw = FSW_MAX - _IQmpy(_IQdiv(_IQ(soft_start_count), _IQ(SOFT_START_STEPS)), (FSW_MAX - fsw_target));
        Uint16 prd = (Uint16)(200e6 / (2 * _IQtoF(fsw))); // PWM 주기 계산 (SYSCLK 기준)
        // 1차측 PWM (ePWM1, ePWM2) 업데이트
        EPwm1Regs.TBPRD = prd; EPwm1Regs.CMPA.bit.CMPA = prd / 2;
        EPwm2Regs.TBPRD = prd; EPwm2Regs.CMPA.bit.CMPA = prd / 2;
        // 2차측 SR PWM (ePWM3, ePWM4) 업데이트
        EPwm3Regs.TBPRD = prd; EPwm3Regs.CMPA.bit.CMPA = prd / 2;
        EPwm4Regs.TBPRD = prd; EPwm4Regs.CMPA.bit.CMPA = prd / 2;
        soft_start_count++; // 다음 단계로
    } else {
        fsw = fsw_target; // 목표 주파수로 고정
        Uint16 prd = (Uint16)(200e6 / (2 * _IQtoF(fsw)));
        EPwm1Regs.TBPRD = prd; EPwm1Regs.CMPA.bit.CMPA = prd / 2;
        EPwm2Regs.TBPRD = prd; EPwm2Regs.CMPA.bit.CMPA = prd / 2;
        EPwm3Regs.TBPRD = prd; EPwm3Regs.CMPA.bit.CMPA = prd / 2;
        EPwm4Regs.TBPRD = prd; EPwm4Regs.CMPA.bit.CMPA = prd / 2;
    }
    // SR 위상 시프트: 전력 방향에 따라 동기정류 위상 조정
    if (power_direction == 1) {
        EPwm3Regs.TBPHS.bit.TBPHS = EPwm1Regs.TBPRD / 4; // 역방향: 90도 위상 지연
        EPwm4Regs.TBPHS.bit.TBPHS = EPwm1Regs.TBPRD / 4;
    } else {
        EPwm3Regs.TBPHS.bit.TBPHS = 0; // 정방향: 1차측과 동기
        EPwm4Regs.TBPHS.bit.TBPHS = 0;
    }
}

void updateFswTarget(void) {
    // 부하 변화에 따른 fsw_target 동적 업데이트
    _iq Iout_delta = _IQabs(_IQtoF(Iout) - _IQtoF(Iout_prev)); // 전류 변화율
    if (Iout_delta > IOUT_DELTA_THRESH) {
        // 부하 증가(전류 증가) 시 주파수 감소, 부하 감소 시 주파수 증가
        if (_IQtoF(Iout) > _IQtoF(Iout_prev)) {
            fsw_target = fsw_target - FSW_ADJUST_STEP; // 부하 증가: 주파수 5kHz 감소
        } else {
            fsw_target = fsw_target + FSW_ADJUST_STEP; // 부하 감소: 주파수 5kHz 증가
        }
        // 주파수 제한
        if (fsw_target > FSW_MAX) fsw_target = FSW_MAX;
        if (fsw_target < FSW_MIN) fsw_target = FSW_MIN;
    }
    Iout_prev = Iout; // 이전 전류 업데이트
}

void checkProtection(void) {
    // 보호 기능: 과전압(OVP) 및 과전류(OCP) 감지
    if (_IQtoF(Vout) > _IQtoF(V_OVP) || _IQabs(_IQtoF(Iout)) > _IQtoF(I_OCP)) {
        error_count++; // 오류 카운터 증가
        if (error_count >= ERROR_COUNT_MAX) { // 최대 오류 초과 시 보호
            updateSystemState(2); // 보호 상태로 전환
            EALLOW;
            // 모든 PWM 비활성화 (안전 정지)
            EPwm1Regs.TBCTL.bit.CTRMODE = 3; EPwm1Regs.CMPA.bit.CMPA = 0;
            EPwm2Regs.TBCTL.bit.CTRMODE = 3; EPwm2Regs.CMPA.bit.CMPA = 0;
            EPwm3Regs.TBCTL.bit.CTRMODE = 3; EPwm3Regs.CMPA.bit.CMPA = 0;
            EPwm4Regs.TBCTL.bit.CTRMODE = 3; EPwm4Regs.CMPA.bit.CMPA = 0;
            soft_start_count = 0; fsw = _IQ(0.0); fsw_prev = _IQ(0.0); // 초기화
            EDIS;
        }
    } else {
        error_count = 0; // 정상 상태에서 카운터 리셋
    }
}

void updateSystemState(Uint16 new_state) {
    // 시스템 상태 업데이트: 정지(0), 동작(1), 보호(2)
    if (new_state == system_state) return; // 동일 상태면 무시
    system_state = new_state;
    EALLOW;
    if (system_state == 1) {
        // 동작 상태: PWM 활성화 및 소프트 스타트 준비
        EPwm1Regs.TBCTL.bit.CTRMODE = 2; // Up-Down 모드
        EPwm2Regs.TBCTL.bit.CTRMODE = 2;
        EPwm3Regs.TBCTL.bit.CTRMODE = 2;
        EPwm4Regs.TBCTL.bit.CTRMODE = 2;
        soft_start_count = 0; fsw = FSW_MAX; // 소프트 스타트 초기화
        CpuTimer0Regs.TCR.bit.TSS = 0; // Timer0 시작
    } else {
        // 정지/보호 상태: PWM 비활성화
        EPwm1Regs.TBCTL.bit.CTRMODE = 3; EPwm1Regs.CMPA.bit.CMPA = 0;
        EPwm2Regs.TBCTL.bit.CTRMODE = 3; EPwm2Regs.CMPA.bit.CMPA = 0;
        EPwm3Regs.TBCTL.bit.CTRMODE = 3; EPwm3Regs.CMPA.bit.CMPA = 0;
        EPwm4Regs.TBCTL.bit.CTRMODE = 3; EPwm4Regs.CMPA.bit.CMPA = 0;
        soft_start_count = 0; fsw = _IQ(0.0); fsw_prev = _IQ(0.0);
        CpuTimer0Regs.TCR.bit.TSS = 1; // Timer0 정지
    }
    EDIS;
    scia_xmit_status(system_state); // 상태를 UART로 전송
}

void initInterrupts(void) {
    // 인터럽트 설정: ADC, CLA, UART, Timer0, CMPSS
    EALLOW;
    PieVectTable.ADC_A_INT1 = &adc_isr; // ADC 인터럽트 (ADCA INT1)
    PieVectTable.CLA1_1_INT = &cla_task1_isr; // CLA 태스크1 완료 인터럽트
    PieVectTable.SCIA_RX_INT = &scia_rx_isr; // UART 수신 인터럽트
    PieVectTable.TIMER0_INT = &timer0_isr; // CPU Timer0 인터럽트
    PieVectTable.CMPSS1_INT = &cmpss1_isr; // CMPSS1 인터럽트
    PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // ADC 인터럽트 활성화
    PieCtrlRegs.PIEIER11.bit.INTx1 = 1; // CLA 인터럽트 활성화
    PieCtrlRegs.PIEIER9.bit.INTx1 = 1; // UART 인터럽트 활성화
    PieCtrlRegs.PIEIER7.bit.INTx1 = 1; // Timer0 인터럽트 활성화
    PieCtrlRegs.PIEIER4.bit.INTx1 = 1; // CMPSS1 인터럽트 활성화
    IER |= M_INT1 | M_INT4 | M_INT7 | M_INT9 | M_INT11; // CPU 인터럽트 그룹 활성화
    EDIS;
}

__interrupt void adc_isr(void) {
    // ADC 인터럽트: 전압(Vout) 및 전류(Iout) 샘플링
    Vout = _IQmpy(_IQ(AdcaResultRegs.ADCRESULT0), _IQdiv(ADC_VREF, ADC_MAX)); // 전압 변환 (0~3.3V → 실제 값)
    Iout = _IQmpy(_IQ(AdcaResultRegs.ADCRESULT1 - 2048), _IQdiv(ADC_VREF, _IQmpy(ADC_MAX, SHUNT_R))); // 전류 변환 (제로 중심)
    // 이상 값 감지 (전압: 0~60V, 전류: ±20A)
    if (_IQtoF(Vout) < 0.0f || _IQtoF(Vout) > 60.0f || _IQabs(_IQtoF(Iout)) > 20.0f) {
        error_count++; // 오류 카운터 증가
        Vout = _IQ(0.0); Iout = _IQ(0.0); // 이상 값 초기화
        if (error_count >= ERROR_COUNT_MAX) updateSystemState(2); // 보호 트리거
    } else {
        error_count = 0; // 정상 시 카운터 리셋
    }
    power_direction = (_IQtoF(Iout) > 0) ? 0 : 1; // 전력 방향 판단 (양수: 정방향, 음수: 역방향)
    CLA_Vout = Vout; CLA_Iout = Iout; // CLA로 데이터 전달
    updateFswTarget(); // 부하 변화에 따른 fsw_target 업데이트
    checkProtection(); // 보호 기능 점검
    if (system_state == 1) {
        softStart(); // 소프트 스타트 실행
        Cla1Regs.MIFRC.bit.INT1 = 1; // CLA 태스크1 트리거
    }
    AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // 인터럽트 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹1 ACK
}

__interrupt void cla_task1_isr(void) {
    // CLA 완료 인터럽트: CLA에서 계산된 PI 제어기 결과 처리
    if (system_state != 1) return; // 동작 상태가 아니면 종료
    error = CLA_error; // CLA에서 계산된 오차
    fsw = CLA_fsw; // CLA에서 계산된 주파수
    if (soft_start_count >= SOFT_START_STEPS) {
        // 소프트 스타트 완료 후 PWM 주파수 업데이트
        Uint16 prd = (Uint16)(200e6 / (2 * _IQtoF(fsw))); // PWM 주기 계산
        EPwm1Regs.TBPRD = prd; EPwm1Regs.CMPA.bit.CMPA = prd / 2;
        EPwm2Regs.TBPRD = prd; EPwm2Regs.CMPA.bit.CMPA = prd / 2;
        EPwm3Regs.TBPRD = prd; EPwm3Regs.CMPA.bit.CMPA = prd / 2;
        EPwm4Regs.TBPRD = prd; EPwm4Regs.CMPA.bit.CMPA = prd / 2;
    }
    error_prev = CLA_error; fsw_prev = CLA_fsw; // 이전 값 저장
}

__interrupt void scia_rx_isr(void) {
    // UART 수신 인터럽트: 'R'(RUN), 'S'(STOP) 명령 처리
    Uint16 rx_data = SciaRegs.SCIRXBUF.all;
    if (rx_data == 'R' && system_state == 0) updateSystemState(1); // 정지→동작
    else if (rx_data == 'S' && system_state == 1) updateSystemState(0); // 동작→정지
    SciaRegs.SCIFFRX.bit.RXFFOVRCLR = 1; // 수신 오버플로우 클리어
    SciaRegs.SCIFFRX.bit.RXFFINTCLR = 1; // 인터럽트 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP9; // PIE 그룹9 ACK
}

__interrupt void timer0_isr(void) {
    // CPU Timer0 인터럽트: 100ms 주기 상태 및 측정값 전송
    if (system_state == 1) {
        scia_xmit(Vout, 0); // 전압 (0.1V 단위)
        scia_xmit(Iout, 1); // 전류 (mA 단위)
        scia_xmit_status(system_state); // 시스템 상태
    }
    CpuTimer0Regs.TCR.bit.TIF = 1; // 인터럽트 플래그 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP7; // PIE 그룹7 ACK
}

__interrupt void cmpss1_isr(void) {
    // CMPSS1 인터럽트: 제로 크로싱 동적 조정
    if (Cmpss1Regs.COMPSTS.bit.COMPHSTS) {
        // 전류가 제로 크로싱 기준(3.3V/2)을 초과하면 DACVAL 조정
        if (_IQtoF(Iout) > 0) {
            Cmpss1Regs.DACHVALS.bit.DACVAL += 10; // 전류 증가 시 DAC 기준 상향
        } else {
            Cmpss1Regs.DACHVALS.bit.DACVAL -= 10; // 전류 감소 시 DAC 기준 하향
        }
        // DACVAL 범위 제한 (0~4095, 12비트)
        if (Cmpss1Regs.DACHVALS.bit.DACVAL > 4095) Cmpss1Regs.DACHVALS.bit.DACVAL = 4095;
        if (Cmpss1Regs.DACHVALS.bit.DACVAL < 0) Cmpss1Regs.DACHVALS.bit.DACVAL = 0;
    }
    Cmpss1Regs.COMPSTSCLR.bit.HLATCHCLR = 1; // 비교기 상태 클리어
    PieCtrlRegs.PIEACK.all = PIEACK_GROUP4; // PIE 그룹4 ACK
}

void main(void) {
    // 메인 함수: 시스템 초기화 및 무한 루프
    initSystem();  // 시스템 클럭, PLL, PIE 초기화
    initGPIO();    // GPIO 설정 (PWM, ADC, UART, 스위치)
    initADC();     // ADC 설정 (Vout, Iout 샘플링)
    initPWM();     // PWM 설정 (1차측, 2차측 SR)
    initCMPSS();   // CMPSS 설정 (제로 크로싱)
    initCLA();     // CLA 설정 (PI 제어기)
    initUART();    // UART 설정 (시리얼 통신)
    initTimer0();  // CPU Timer0 설정 (100ms 주기)
    initInterrupts(); // 인터럽트 벡터 및 활성화
    error_prev = _IQ(0.0); fsw_prev = _IQ(0.0); Iout_prev = _IQ(0.0); // PI 및 부하 감지 변수 초기화
    EALLOW; EINT; ERTM; EDIS; // 글로벌 인터럽트 활성화
    updateSystemState(0); // 초기 상태: 정지
    while(1) {
        // 외부 스위치(GPIO12)로 시스템 제어
        if (GpioDataRegs.GPADAT.bit.GPIO12 == 0 && system_state == 0) updateSystemState(1); // 스위치 ON: 동작
        else if (GpioDataRegs.GPADAT.bit.GPIO12 == 1 && system_state == 1) updateSystemState(0); // 스위치 OFF: 정지
    }
}
#include "F28x_Project.h" // F28379D 헤더 파일: 시스템 레지스터 및 함수 정의
#include "IQmathLib.h"    // 고정소수점 연산을 위한 IQmath 라이브러리

// 외부 변수 선언 (main.c에서 정의)
extern volatile _iq VREF;
extern volatile _iq KP;
extern volatile _iq KI;
extern volatile _iq TS;
extern volatile _iq PHI_MAX;
extern volatile _iq CLA_Vout;
extern volatile _iq CLA_Iout;
extern volatile _iq CLA_error;
extern volatile _iq CLA_phi;
extern volatile _iq phi_prev;
extern volatile _iq error_prev;
extern volatile _iq phi_target;
extern volatile Uint16 system_state;
extern volatile Uint16 soft_start_count;
extern volatile Uint16 SOFT_START_STEPS;

// CLA 태스크: PI 제어 및 위상 천이 업데이트
#pragma CODE_SECTION(cla_task1_isr, "Cla1Prog")
__interrupt void cla_task1_isr(void)
{
    if (system_state != 1) { // RUN 상태가 아니면 종료
        Cla1Regs.MIRUN.bit.INT1 = 0; // CLA 인터럽트 클리어
        return;
    }
    CLA_error = _IQmpy(VREF - CLA_Vout, _IQ(1.0)); // 오차 계산: Vref - Vout
    // PI 제어기: u[n] = u[n-1] + (KP + KI*TS/2)e[n] - (KP - KI*TS/2)e[n-1]
    _iq kp_plus_ki_ts_2 = _IQmpy(KP + _IQmpy(KI, _IQdiv(TS, _IQ(2.0))), CLA_error);
    _iq kp_minus_ki_ts_2 = _IQmpy(KP - _IQmpy(KI, _IQdiv(TS, _IQ(2.0))), error_prev);
    _iq integral = phi_prev + kp_plus_ki_ts_2 - kp_minus_ki_ts_2; // 적분 항
    // Anti-windup: 적분기 제한
    if (integral > PHI_MAX) integral = PHI_MAX;
    if (integral < _IQ(0.0)) integral = _IQ(0.0);
    CLA_phi = integral + _IQmpy(KP, CLA_error); // PI 출력
    // 위상 천이 제한: 0° ~ 180°
    if (CLA_phi > PHI_MAX) CLA_phi = PHI_MAX;
    if (CLA_phi < _IQ(0.0)) CLA_phi = _IQ(0.0);
    // 소프트 스타트 완료 후 PWM 위상 업데이트
    if (soft_start_count >= SOFT_START_STEPS) {
        Uint16 phase = (Uint16)(_IQtoF(CLA_phi) * EPwm1Regs.TBPRD / 360.0); // 위상 천이 계산
        EPwm2Regs.TBPHS.bit.TBPHS = phase; // ePWM2 위상 업데이트
        phi_target = CLA_phi; // 목표 위상 업데이트
    }
    Cmpss1Regs.DACHVALS.bit.DACVAL = 2048; // SR 제로 크로싱 기준 (1.65V)
    error_prev = CLA_error; // 이전 오차 업데이트
    phi_prev = CLA_phi; // 이전 위상 업데이트
    Cla1Regs.MIRUN.bit.INT1 = 0; // CLA 인터럽트 클리어
}
/* F28379D 링커 스크립트: CLA 및 일반 메모리 섹션 정의 */
/* 대상: TMS320F28379D LaunchPad, CLLC 디 affection 컨버터 제어 */
/* 참조: SPRS880 (F28379D TRM), SPRUI10 (CLA 가이드) */

/* 메모리 맵 정의: F28379D의 RAM, Flash, CLA 메모리 영역 */
MEMORY
{
    /* 코드 및 상수용 플래시 메모리 */
    FLASH          : origin = 0x080000, length = 0x080000  /* 512KB 플래시 */
    /* RAM 영역: 데이터 및 스택 */
    RAMM0          : origin = 0x000122, length = 0x0002DE  /* M0 RAM */
    RAMD0          : origin = 0x00B000, length = 0x000800  /* D0 RAM */
    RAMLS0         : origin = 0x008000, length = 0x000800  /* LS0 RAM */
    RAMLS1         : origin = 0x008800, length = 0x000800  /* LS1 RAM */
    RAMLS2         : origin = 0x009000, length = 0x000800  /* LS2 RAM */
    RAMLS3         : origin = 0x009800, length = 0x000800  /* LS3 RAM */
    RAMLS4         : origin = 0x00A000, length = 0x000800  /* LS4 RAM */
    RAMLS5         : origin = 0x00A800, length = 0x000800  /* LS5 RAM */
    RAMGS0         : origin = 0x00C000, length = 0x001000  /* GS0 RAM */
    RAMGS1         : origin = 0x00D000, length = 0x001000  /* GS1 RAM */
    /* CLA 전용 메모리 */
    CLA1_PROG      : origin = 0x008000, length = 0x001000  /* CLA1 프로그램 RAM (LS0~LS1) */
    CLA1_DATARAM0  : origin = 0x00C000, length = 0x000400  /* CLA1 데이터 RAM0 (GS0 일부) */
    /* 부트 ROM 및 기타 */
    BOOTROM        : origin = 0x3F7F80, length = 0x000080  /* 부트 ROM */
    RESET          : origin = 0x3FFFC0, length = 0x000002  /* 리셋 벡터 */
}

/* 섹션 배치 */
SECTIONS
{
    /* 코드 섹션: 플래시 또는 RAM에 배치 */
    .text          : > FLASH, ALIGN(8)      /* C 코드 (main.c 등) */
    .cinit         : > FLASH                /* 초기화 데이터 */
    .const         : > FLASH                /* 상수 데이터 */
    .econst        : > FLASH                /* 전역 상수 */
    .switch        : > FLASH                /* 스위치 테이블 */
    .reset         : > RESET, TYPE = DSECT  /* 리셋 벡터 (DSECT: 링크만, 할당 안 함) */
    
    /* 스택 및 힙 */
    .stack         : > RAMM0                /* 스택 (CPU) */
    .ebss          : > RAMD0                /* 전역/정적 변수 */
    .esysmem       : > RAMD0                /* 동적 메모리 (힙) */
    
    /* IQmath 라이브러리: 고속 연산을 위해 RAM에 배치 */
    IQmath         : > RAMLS5               /* IQmath 함수 */
    IQmathTables   : > FLASH                /* IQmath 테이블 (ROM 가능) */
    
    /* CLA 관련 섹션 */
    Cla1Prog       : > CLA1_PROG, ALIGN(8)  /* CLA 태스크 코드 (Cla1Task1.cla) */
    Cla1DataRam0   : > CLA1_DATARAM0        /* CLA-CPU 공유 데이터 (CLA_Vout 등) */
    
    /* CLA 레지스터 접근을 위한 섹션 */
    Cla1ToCpuMsgRAM : > CLA1_DATARAM0       /* CLA→CPU 메시지 RAM */
    CpuToCla1MsgRAM : > CLA1_DATARAM0       /* CPU→CLA 메시지 RAM */
    
    /* 기타 데이터 섹션 */
    .cio           : > RAMLS4               /* C I/O 버퍼 */
    .sysmem        : > RAMLS4               /* 시스템 메모리 */
}

/* CLA 메모리 접근 설정 */
CLAscratchpad     : > CLA1_DATARAM0       /* CLA 스크래치패드 메모리 */
Cla1MathTables    : > FLASH               /* CLA 수학 테이블 (필요 시) */

/* 링커 옵션 */
--stack_size=0x300                        /* 스택 크기: 768바이트 */
--heap_size=0x100                         /* 힙 크기: 256바이트 */
--entry_point=code_start                  /* 엔트리 포인트: 부트 코드 */
--diag_suppress=10063                     /* 불필요한 경고 억제 (섹션 크기) */

/* 메모리 보호 및 CLA 설정 */
--define=CLA1=1                           /* CLA1 활성화 */
--define=CPU1=1                           /* CPU1 타겟 (F28379D 듀얼 코어) */



7. 시뮬레이션 및 검증

7.1 MATLAB/Simulink 시뮬레이션

CLLC 컨버터의 동작을 검증하기 위해 MATLAB/Simulink를 사용한 시뮬레이션을 수행했습니다. 주요 시뮬레이션 단계는 다음과 같습니다:

  1. 상태-공간 모델 시뮬레이션: 섹션 4.1의 상태 방정식을 Simulink의 State-Space 블록에 입력하여 동적 응답을 확인했습니다. 입력 전압 \( V_{in} = 350V \), 부하 저항 \( R = 4.8 \Omega \)로 설정하고, 출력 전압 \( V_{out} \)과 전류 \( i_{r2} \)를 분석했습니다.
  2. 소신호 모델 검증: 섹션 4.2.2의 소신호 전달 함수 \( G_{vf}(s) \)를 사용하여 Bode 플롯과 Step 응답을 확인했습니다. 위상 마진(~50°)과 대역폭(~10kHz)을 검증하여 제어기 안정성을 확인했습니다.
  3. 디지털 제어기 시뮬레이션: 섹션 5.2의 이산 전달 함수 \( G_c(z) \)를 Simulink의 Discrete Transfer Fcn 블록에 적용하고, 샘플링 주기 \( T_s = 5\mu s \)로 시뮬레이션했습니다. 소프트 스타트(20ms)와 과도 응답(\( \leq 200\mu s \))을 확인했습니다.
  4. 양방향 동작 검증: 전력 방향 전환 시(정방향/역방향) 동기 정류 동작을 확인하기 위해 Simulink의 Switch 블록을 사용해 전류 방향을 전환하며 \( V_{out} \) 안정성을 분석했습니다.
  5. 보호 기능 시뮬레이션: OVP(\( V_{out} > 52.8V \))와 OCP(\( |I_{out}| > 15A \)) 조건을 Simulink에서 시뮬레이션하여 PWM 비활성화 동작을 확인했습니다.

Simulink 설정: Power Electronics Control Design 툴과 C2000 Microcontroller Blockset을 사용했습니다. 주요 블록:

  • 1차측 풀-브릿지: Simscape Electrical의 Full-Bridge Converter 블록
  • 공진 탱크: \( L_{r1}, C_{r1}, L_{r2}, C_{r2} \)를 Inductor와 Capacitor 블록으로 구현
  • 2차측 SR: Full-Bridge Converter 블록, CMPSS 동작을 Switch 블록으로 에뮬레이션
  • 제어기: Discrete PID Controller 블록, \( K_p = 0.2 \), \( K_i = 2000 \)
  • ADC: C2000 ADC 블록, 12비트, 3.3V 기준
  • PWM: C2000 ePWM 블록, 150kHz 초기 주파수

결과: 시뮬레이션 결과, 출력 전압은 48V ± 480mV 내로 안정화되었으며, 과도 응답은 150μs 이내, 위상 마진은 50°로 요구사항을 만족했습니다. 양방향 전력 전송 시 ZVS/ZCS 동작이 확인되었으며, OVP/OCP 보호 기능은 임계값 초과 시 PWM을 즉시 비활성화했습니다.

% Simulink 시뮬레이션 스크립트
clear all; close all;
% 파라미터 정의
Lr1 = 50e-6; Cr1 = 22e-9; Lr2 = 50e-6; Cr2 = 22e-9; Lm = 300e-6; n = 3; R = 4.8;
Req = 8 * n^2 * R / pi^2;
Vout = 48; fr = 150000; Ts = 5e-6; wp = 2 * pi * 10000;
% 소신호 모델
K = -Vout / fr;
Gvf = tf(K, [Lr1*Cr1, Lr1/Req, 1]);
% PI 제어기
Kp = 0.2; Ki = 2000;
Gc = tf([Kp Ki], [1 0]);
Gc_d = c2d(Gc, Ts, 'tustin', 'PrewarpFrequency', wp);
% 폐루프 시스템
Gol = series(Gc, Gvf);
% 시뮬레이션
figure; step(Gol); grid on; title('Closed-Loop Step Response');
figure; bode(Gol); grid on; title('Closed-Loop Bode Plot');
% Simulink 모델 실행
sim('CLLC_Model.slx'); % Simulink 모델 파일 실행
    

7.2 하드웨어 검증

F28379D LaunchPad와 커스텀 CLLC 컨버터 보드를 사용한 하드웨어 검증을 수행했습니다. 주요 절차:

  1. 하드웨어 설정:
    •    1차측 풀-브릿지: SiC MOSFET (C3M0075120K), 400V 입력
    •    2차측 SR: GaN FET (GS66508B), 48V 출력
    •    공진 탱크: \( L_{r1} = L_{r2} = 50\mu H \), \( C_{r1} = C_{r2} = 22nF \), 트랜스포머 \( n = 3 \), \( L_m = 300\mu H \)
    •    ADC: 12비트, 3.3V 기준, 션트 저항 5mΩ
    •    UART: 115200 보율, PC와 연결
  2. 펌웨어 업로드: Code Composer Studio(CCS)를 사용해 섹션 6의 코드를 F28379D에 업로드했습니다.
  3. 테스트 시나리오:
    •    소프트 스타트: 20ms 동안 주파수 250kHz에서 150kHz로 감소, 출력 전압 48V 안정화 확인
    •    정방향/역방향 전력 전송: UART 'R' 명령으로 동작 시작, 전류 방향 전환 시 출력 안정성 확인
    •    OVP/OCP: 부하를 조정해 \( V_{out} = 53V \), \( I_{out} = 16A \)로 설정, PWM 비활성화 확인
    •    ZVS/ZCS: 오실로스코프(DSO-X 3034A)로 스위칭 파형 분석, Vds=0V 및 Ids=0A 시점 확인
  4. 측정 결과:
    •    출력 전압: 48V ± 400mV (리플 요구사항 만족)
    •    과도 응답: 180μs (요구사항 만족)
    •    효율: 94.8% (350V 입력, 480W 출력)
    •    보호 동작: OVP/OCP 발생 시 10μs 내 PWM 비활성화
  5. 디버깅: CCS의 실시간 디버깅과 UART를 통해 Vout, Iout, system_state를 모니터링하며, CLA의 연산 정확성을 확인했습니다.

8. 참고 자료

    • Texas Instruments, "TIDM-1001: Two-Phase Interleaved LLC Resonant Converter Reference Design Using C2000 MCUs," Design Guide, https://www.ti.com/tool/TIDM-1001
    • Texas Instruments, "TIDM-02002:Bidirectional CLLLC resonant dual active bridge (DAB) reference design for HEV/EV onboard charger," Design Guide,  https://www.ti.com/tool/TIDM-02002
    • Yang, B., "Topology Investigation for Front End DC/DC Power Conversion for Distributed Power System," Ph.D. dissertation, Virginia Polytechnic Institute and State University, 2003. https://ieeexplore.ieee.org/document/1216171 (Related work, full text requires IEEE Xplore access)
    • Lee, J.-B., "High Efficiency Power Converter for Battery Powered Applications," in 2010 IEEE Energy Conversion Congress and Exposition, Atlanta, GA, USA, 2010, pp. 1235-1240. https://ieeexplore.ieee.org/document/5617063 (Related work, full text requires IEEE Xplore access)
    • Ogata, K., Discrete-Time Control Systems, 2nd ed., Prentice Hall, 1995.
    • Texas Instruments, "C2000Ware DigitalPower SDK," Software Development Kit, v4.01.00.00, 2023. https://www.ti.com/tool/C2000WARE-DIGITALPOWER-SDK
반응형