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차측 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} \]
- 1차측 KCL: \[ i_{r1} = C_{r1} \frac{d v_{Cr1}}{dt}, \quad \frac{d v_{Cr1}}{dt} = \frac{1}{C_{r1}} i_{r1} \]
- 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} \]
- 2차측 KCL: \[ i_{r2} = C_{r2} \frac{d v_{Cr2}}{dt}, \quad \frac{d v_{Cr2}}{dt} = \frac{1}{C_{r2}} i_{r2} \]
- 자화 인덕터: \[ n v_{Cr2} = L_m \frac{d i_m}{dt}, \quad \frac{d i_m}{dt} = \frac{n}{L_m} v_{Cr2} \]
- 부하 전류: \[ 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를 사용한 시뮬레이션을 수행했습니다. 주요 시뮬레이션 단계는 다음과 같습니다:
- 상태-공간 모델 시뮬레이션: 섹션 4.1의 상태 방정식을 Simulink의 State-Space 블록에 입력하여 동적 응답을 확인했습니다. 입력 전압 \( V_{in} = 350V \), 부하 저항 \( R = 4.8 \Omega \)로 설정하고, 출력 전압 \( V_{out} \)과 전류 \( i_{r2} \)를 분석했습니다.
- 소신호 모델 검증: 섹션 4.2.2의 소신호 전달 함수 \( G_{vf}(s) \)를 사용하여 Bode 플롯과 Step 응답을 확인했습니다. 위상 마진(~50°)과 대역폭(~10kHz)을 검증하여 제어기 안정성을 확인했습니다.
- 디지털 제어기 시뮬레이션: 섹션 5.2의 이산 전달 함수 \( G_c(z) \)를 Simulink의 Discrete Transfer Fcn 블록에 적용하고, 샘플링 주기 \( T_s = 5\mu s \)로 시뮬레이션했습니다. 소프트 스타트(20ms)와 과도 응답(\( \leq 200\mu s \))을 확인했습니다.
- 양방향 동작 검증: 전력 방향 전환 시(정방향/역방향) 동기 정류 동작을 확인하기 위해 Simulink의 Switch 블록을 사용해 전류 방향을 전환하며 \( V_{out} \) 안정성을 분석했습니다.
- 보호 기능 시뮬레이션: 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차측 풀-브릿지: 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와 연결
- 펌웨어 업로드: Code Composer Studio(CCS)를 사용해 섹션 6의 코드를 F28379D에 업로드했습니다.
- 테스트 시나리오:
- 소프트 스타트: 20ms 동안 주파수 250kHz에서 150kHz로 감소, 출력 전압 48V 안정화 확인
- 정방향/역방향 전력 전송: UART 'R' 명령으로 동작 시작, 전류 방향 전환 시 출력 안정성 확인
- OVP/OCP: 부하를 조정해 \( V_{out} = 53V \), \( I_{out} = 16A \)로 설정, PWM 비활성화 확인
- ZVS/ZCS: 오실로스코프(DSO-X 3034A)로 스위칭 파형 분석, Vds=0V 및 Ids=0A 시점 확인
- 측정 결과:
- 출력 전압: 48V ± 400mV (리플 요구사항 만족)
- 과도 응답: 180μs (요구사항 만족)
- 효율: 94.8% (350V 입력, 480W 출력)
- 보호 동작: OVP/OCP 발생 시 10μs 내 PWM 비활성화
- 디버깅: 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
'Power Electronics > DC-DC변환' 카테고리의 다른 글
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 컨버터 디지털 제어기 설계-VMC (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 |