본문 바로가기
Power Electronics

디지탈 전력변환 -제 1장 TMS320F28P65x 아키텍처 및 시스템 구조

by linuxgo 2026. 6. 13.

1.1 서론

TI C2000 패밀리는 전력 변환 디지털 제어 분야의 표준 플랫폼으로 30년 가까이 자리해왔다. 그 최신 세대인 TMS320F28P65x는 전력전자 응용에 특화된 핵심 기능들을 대폭 강화하였으며, 본서는 이 디바이스를 기준 플랫폼으로 삼는다.

F28P65x 핵심 차별점:

  • 36채널 HRPWM: 150ps 분해능, 전 채널 MINDB(최소 데드밴드)·ICL(금지조합차단)·DE(다이오드 에뮬레이션) 내장
  • ADC 하드웨어 가속: SYSCLK에서 직접 유도되는 클록, 16-bit/12-bit 소프트웨어 선택, 최대 128배 오버샘플링
  • 듀얼코어 + CLA: CPU1/CPU2 각 200 MIPS + CLA 코프로세서, 록스텝 안전 옵션
  • 기능안전 인증: ISO 26262 ASIL B / IEC 61508 SIL 2

1.2 디바이스 패밀리 개요

1.2.1 파트번호 체계

파트번호  코어 구성 EtherCat 록스텝 비고
F28P650DK CPU1+CLA, CPU2 본서 기준
F28P650SK CPU1+CLA 싱글코어
F28P659DK-Q1 CPU1+CLA, CPU2 차량용 Q1

1.2.2 핵심 사양

항목 사양
CPU 코어 C28x × 2, 각 200 MIPS
CLA CPU1.CLA, 200 MIPS
FPU IEEE 754 단정밀도(32-bit)
ePWM 36채널 (전 채널 150ps HRPWM)
ADC 3개 모듈(A/B/C), 16/12-bit 소프트웨어 선택
Flash 최대 5뱅크, 부팅 시 CPU1/CPU2 동적 할당
RAM LS×10 + GS×5 + 전용(M0/M1/Dx) + MSGRAM
기능안전 ISO 26262 ASIL B / IEC 61508 SIL 2

1.3 C28x 프로세서 코어

1.3.1 부동소수점 유닛(FPU)

F28P65x의 FPU는 IEEE 754 단정밀도(32-bit) 부동소수점을 지원한다. 8개의 32-bit 결과 레지스터(R0H~R7H), 상태 레지스터(STF), 반복블록 레지스터(RB)가 추가되며, RB를 제외한 모든 FPU 레지스터는 섀도잉되어 고우선순위 인터럽트에서 빠른 컨텍스트 전환이 가능하다.

1.3.2 TMU — 명령어별 사이클

명령어 C 등가 연산 사이클
MPY2PIF32 a = b × 2π 2/3
DIV2PIF32 a = b / 2π 2/3
DIVF32 a = b/c 5
SQRTF32 a = sqrt(b) 5
SINPUF32 a = sin(b×2π) 4
COSPUF32 a = cos(b×2π) 4
ATANPUF32 a = atan(b)/2π 4
QUADF32 ATANPU2 보조 5

IEXP2F32(지수), LOG2F32(로그) 명령어로 비선형 PID(NLPID)의 거듭제곱 연산을 약 300사이클(라이브러리 에뮬레이션)에서 10사이클 미만으로 단축한다.

FOC Park 변환:

$$\begin{bmatrix} V_d \ V_q \end{bmatrix} = \begin{bmatrix} \cos\theta_r & \sin\theta_r \ -\sin\theta_r & \cos\theta_r \end{bmatrix} \begin{bmatrix} V_\alpha \ V_\beta \end{bmatrix}, \qquad \theta_{PU} = \frac{\theta_{rad}}{2\pi}$$

SINPUF32+COSPUF32 사용 시 최대 8사이클(@200MHz, 40ns)이며, 이는 C 표준 sinf()/cosf()(약 50~80사이클) 대비 대폭 단축된 수치다.

1.3.3 VCRC 유닛

CRC 종류 다항식
CRC8 0x07
CRC16 0x8005 / 0x1021
CRC24 0x5D6DCB
CRC32 0x04C11DB7 / 0x1EDC6F41

바이트당 1사이클(표준 다항식) 또는 3사이클(사용자 정의 다항식)로 연산한다.

1.4 클록 시스템

 

그림 1-1. 클록 분배 트리

1.4.1 클록 소스 4종

소스 주파수 용도
INTOSC2 10 MHz 리셋 기본값, Boot ROM 구동
INTOSC1 10 MHz Watchdog/MCD 백업 전용
XTAL 사용자 결정 외부 수정/레조네이터(X1/X2, GPIO220/221)
AUXCLKIN 사용자 결정 GPIO133, USB/CAN/통신용

클록 소스는 CLKSRCCTL1[OSCCLKSRCSEL] 레지스터로 선택한다: 00=INTOSC2(기본), 01=XTAL, 10=INTOSC1.

설계 규칙: 클록 소스 변경 시 SYSPLLMULT가 자동으로 0이 되며 PLL이 바이패스된다. 다음 SYSPLLMULT 쓰기 전 최소 10 OSCCLK 사이클을 대기해야 한다.

1.4.2 SYSPLLMULT 레지스터와 PLL 주파수 공식

비트  필드 의미
28:24 REFDIV 실제 분주비 = REFDIV + 1
20:16 ODIV 실제 분주비 = ODIV + 1 (레지스터값 1 이상 권장)
7:0 IMULT 레지스터 값 자체가 배율(1~127)

PLL 주파수 공식:

$$\boxed{f_{PLLRAWCLK} = f_{OSCCLK} \times \frac{IMULT}{(REFDIV+1)\times(ODIV+1)}}$$

SYSPLLMULT 레지스터는 쓰기 후 다음 쓰기까지 69 SYSCLK 사이클의 지연이 필요하다.

설계 예 — XTAL 20MHz로 SYSCLK 200MHz를 만드는 경우:

먼저 PLLRAWCLK를 400MHz로 설정한 뒤 SYSCLKDIVSEL로 ÷2하여 200MHz를 얻는다. REFDIV=0(실제÷1), ODIV=1(실제÷2)로 두면:

$$400\text{MHz} = 20\text{MHz} \times \frac{IMULT}{(0+1)\times(1+1)} \Rightarrow IMULT=40$$

레지스터 기록값 의미
IMULT 40 배율 ×40
REFDIV 0 실제 분주비 1
ODIV 1 실제 분주비 2

 설계에서는 위 절차를 직접 구현하는 C2000Ware Driverlib의 SysCtl_setClock() 함수 사용이 권장된다.

1.4.3 시스템 PLL 설정 절차

1. PLLCLKEN=0, 120사이클 대기        5. SYSPLLMULT 32-bit 동시기록
2. PLLEN=0, 60사이클 대기                (다음쓰기까지 69 SYSCLK 대기)
3. OSCCLKSRCSEL 선택, 300사이클 대기   6. SYSPLLSTS.LOCKS=1 폴링
4. PLLSYSCLKDIV=0(÷1, 최고속)        7. DCC로 PLLRAWCLK 검증
                                     8. 분주를 한 단계 높여 재설정

1.4.4 클록 도메인

도메인 적용대상
PLLSYSCLK 시스템 제어 레지스터, GS0-4 RAM, IPC
CPUx.CPUCLK CPU, 코프로세서, 전용RAM(M0/M1/Dx), Flash래퍼
CPUx.SYSCLK CLA, DMA, ePIE, LS0-9 RAM
PERx.SYSCLK ADC, CMPSS, DAC, eCAP, eQEP, EPWM/HRPWM
PERx.LSPCLK SPI, SCI
AUXPLLCLK USB(60MHz 고정)

1.5 메모리 아키텍처

그림 1-2. 메모리 분류 전체도

1.5.1 메모리 분류 4종

분류 RAM 접근 주체
전용(Dedicated) M0, M1, Dx 해당 CPU만
로컬 공유(LSx) LS0~LS9 (10개) CPU + 해당 CPU의 CLA
글로벌 공유(GSx) GS0~GS4 (5개) CPU + 양쪽 CPU의 DMA
메시지(MSGRAM) CPU1↔CPU2 통신 전용

1.5.2 확인된 정확한 주소

블럭 주소 범위 크기
LS0 0x8000–0x87FF 2 KW
LS1 0x8800–0x8FFF 2 KW
D2(CPU2 로컬) 0x8000–0x9FFF 8 KW
D3(CPU2 로컬) 0xA000–0xCFFF 12 KW

LS2~LS9, GS0~GS4 개별 주소 및 Flash 뱅크 정확한 크기는 데이터시트(SPRSP69D)의 메모리맵 표 또는 C2000Ware 링커 .cmd 예제 파일에서 확인한다.

1.5.3 전용 RAM(Dx)의 소유권

D0-D1은 CPU1 전용으로 고정되어 있다. D2-D5는 MCUCNF1 레지스터 설정에 따라 CPU1 또는 CPU2 중 한쪽에 동적으로 매핑된다.

1.5.4 메모리 에러 보호

항목 내용
전용/LSx RAM ECC(SECDED), 단일비트 정정
GSx 등 공유 RAM Parity, 정정 불가 시 NMI 발생
초기화 INIT 비트 세트 후 INITDONE 폴링 필수. 완료 전 해당 RAM 접근 금지

1.5.5 Flash — 뱅크 구성과 Wait State

Flash는 최대 5개 뱅크(Bank0~4)로 구성되며, 부팅 시점에 CPU1 또는 CPU2에 동적으로 할당된다(BANKxMUXSEL 레지스터). 두 CPU가 서로 다른 뱅크를 동시에 읽을 수 있고, 한 뱅크를 프로그램/소거하는 동안 다른 뱅크는 읽기가 가능하다.

Wait State 공식:

$$\boxed{RWAIT = \lceil f_{SYSCLK}/f_{FCLK} - 1 \rceil}, \qquad t_{access}=(RWAIT+1)\times T_{SYSCLK}$$

항목
리셋 기본값 RWAIT = 15(최악 케이스)
USER-OTP 접근 11 SYSCLK 사이클 고정
Flash 설정 코드 반드시 RAM에서 실행

Prefetch(128-bit 단위 선읽기)와 Data Cache(128-bit, 데이터 읽기 전용)는 리셋 시 비활성화 상태이며, Flash_enablePrefetch()/Flash_enableCache() Driverlib 함수로 활성화한다. 두 기능 모두 RWAIT=0일 때는 자동으로 우회된다.

1.6 인터럽트 시스템 — PIE

1.6.1 3단계 전파 구조

인터럽트는 주변장치 → PIE → CPU의 3단계를 모두 통과해야 처리된다.

① 주변장치: 고유 신호 발생, 상태 레지스터로 원인 구분
② PIE: PIEIER(인에이블)/PIEIFR(플래그)/PIEACK(그룹마스크) — 그룹당 16채널, 낮은 채널 우선
③ CPU: IER/IFR/INTM(ST1 레지스터 비트) — IER/INTM 쓰기는 원자적(atomic)

인터럽트 엔트리 시퀀스(11단계):

1. PIEIFRx.y 래치          7. 파이프라인 D2 이후 명령어 완료
2. PIEIERx.y 확인 시 전파    8. 컨텍스트 스택 저장
3. PIEACK 확인 후 세트       9. IFR/IER 클리어, INTM 세트
4. IFR.x 래치              10. PIE에서 ISR 벡터 페치, PIEIFRx.y 클리어
5. IER.x 확인 시 전파        11. ISR로 분기
6. INTM 클리어 시 CPU 수신

1.6.2 인터럽트 레이턴시

종류 최소 latency 200MHz 환산
내부 주변장치(ePWM 등) 14 사이클 70 ns
외부 GPIO(XINT) 16 사이클 80 ns

20kHz 제어 루프(50μs) 대비 내부 인터럽트 레이턴시 비율은 $70\text{ns}/50\mu\text{s}=0.14%$로 무시 가능한 수준이다. C28x RPT(반복) 명령어로 생성된 루프는 인터럽트가 불가능하므로, ISR 내에서 긴 RPT 루프 사용에 주의해야 한다.

1.6.3 인터럽트 비활성화 절차

1. DINT(전역 비활성화)      4. 해당 PIE 그룹 IFR 클리어
2. PIEIER 비트 클리어       5. 해당 PIE 그룹 PIEACK 클리어
3. 5 사이클 대기            6. EINT(전역 재활성화)

 

중요: PIEIFR 비트는 소프트웨어에서 절대 직접 클리어해서는 안 된다. read/modify/write 동작 중 들어오는 인터럽트가 유실될 수 있기 때문이다. PIEIFR을 안전하게 클리어하는 유일한 방법은 CPU가 해당 인터럽트를 실제로 처리(ISR 실행)하는 것이다.

1.6.4 PIE 채널 매핑 — 전력 제어 관련

PIE 그룹 매핑  비고
INT2.y EPWM1_TZ ~ EPWM16_TZ ePWM Trip-Zone(보호)
INT3.y EPWM1 ~ EPWM16 ePWM 주기 인터럽트 — 제어 루프 핵심
INT4.y ECAP1~7, FSI
INT5.y EQEP1~4, CLB1~4, SDFM1/2

 

1.7 ePWM 모듈

1.7.1 PWM 주기·주파수 공식

$$\text{업/다운 단일카운트}: T_{PWM}=(TBPRD+1)\times T_{TBCLK}$$

$$\text{대칭 업다운카운트}: T_{PWM}=2\times TBPRD \times T_{TBCLK}$$

설계 예 — TBCLK 100MHz, 20kHz 대칭 PWM:

$$TBPRD = \frac{100\times10^6}{2\times20\times10^3} = 2500$$

1.7.2 데드밴드

$$FED=DBFED\times T_{TBCLK}, \qquad RED=DBRED\times T_{TBCLK}$$

10-bit 레지스터이며, half-cycle 모드 사용 시 분주값이 절반이 된다.

1.7.3 Trip-Zone

각 ePWM 모듈은 6개의 트립존 입력(TZ1~TZ6)을 가진다.

신호 소스
TZ1-3 GPIO 입력 X-BAR
TZ4 EQEPx 에러(반전)
TZ5 시스템 클록 실패 로직
TZ6 CPU EMUSTOP(에뮬레이션 정지)

트립 발생 시 출력은 High/Low/High-impedance/무동작 중 선택 가능하며, One-Shot(영구 정지)과 Cycle-By-Cycle(자동 복귀) 두 가지 모드를 지원한다.

1.7.4 MINDB / ICL

MINDB(Minimum Dead-Band): 신호의 하강 에지를 검출한 후 BLOCK 신호를 생성하여 반대편 신호의 천이를 차단함으로써, 게이트 드라이버 내부 지연을 보상하는 최소 데드타임을 하드웨어가 보장한다.

ICL(Illegal Combo Logic): 3입력(IN1/IN2/IN3) LUT(Look-Up Table) 구조로, 정의된 조합에 따라 출력을 강제한다. 기본값은 바이패스이며, 활성화 시에만 동작한다. 매트릭스 컨버터나 3레벨 NPC 인버터의 금지된 스위칭 조합을 하드웨어 수준에서 차단하는 데 사용된다.

1.7.5 다중 ePWM 모듈 클록 동기화

1. 개별 ePWM 모듈 클록 활성화
2. TBCLKSYNC = 0  → 모든 ePWM 타임베이스 클록 정지
3. 프리스케일러 값 및 원하는 ePWM 모드 설정
4. TBCLKSYNC = 1  → 모든 ePWM 타임베이스 클록을 동시에 시작

동기화를 위해서는 각 ePWM 모듈의 프리스케일러 비트가 동일하게 설정되어야 한다.

1.8 ADC 모듈

1.8.1 모듈 구성과 클록

ADC-A/B/C 3개 모듈을 가지며, 각각 16-bit 또는 12-bit 분해능을 소프트웨어로 선택할 수 있다.

ADC 변환 클록(ADCCLK)은 SYSCLK에서 직접 유도되며, ADCCTL2 레지스터의 PRESCALE 필드로 분주비를 결정한다.

1.8.2 PRESCALE — 분주비 환산표

PRESCALE 분주비  PRESCALE  분주비
0 ÷1 8 ÷5
2 ÷2 9 ÷5.5
3 ÷2.5 10 ÷6
4 ÷3 11 ÷6.5
5 ÷3.5 12 ÷7
6 ÷4 13 ÷7.5
7 ÷4.5 14, 15 ÷8, ÷8.5

1.8.3 변환 시간

12-bit 모드에서는 약 10.5 ADCCLK 사이클, 16-bit 모드에서는 약 29.5 ADCCLK 사이클이 소요된다.

PRESCALE  분주비  12-bit 변환시간(SYSCLK 사이클) 16-bit
0 ÷1 11 31
6 ÷4 41 119
15 ÷8.5 86 252

200MHz, PRESCALE=0, 12-bit 기준 변환시간: $11/200\text{MHz}=55\text{ns}$

1.8.4 샘플홀드(S+H) 윈도우

$$t_{S+H} = (ACQPS+1)\times T_{SYSCLK}$$

S+H 시간은 최소 1 ADCCLK 주기와 데이터시트가 규정하는 최소 S+H 시간을 모두 충족해야 한다.

1.8.5 전원 인가 절차

1. PCLKCR13에서 해당 ADC 클록 활성화
2. ADCCTL2.PRESCALE에 원하는 분주비 설정
3. ADCCTL1.ADCPWDNZ=1로 전원 ON
4. 샘플링 전 지연 (정확한 시간은 데이터시트 참조)

1.8.6 설정 시 주의사항

ADC 분해능은 반드시 Driverlib ADC_setMode() 함수를 통해 설정해야 한다. 이 함수가 내부적으로 올바른 트림(trim) 값을 함께 로드하기 때문이며, ADCCTL2 레지스터를 직접 조작해서는 안 된다.

1.9 Driverlib 기반 코드 구현

1.9.1 시스템 클록 초기화

/*==============================================================================
 * 파일   : sys_init.c
 * 목적   : TMS320F28P650DK SYSCLK 200MHz 초기화
 *============================================================================*/

#include "driverlib.h"
#include "device.h"

/*--- 방법 A: Device_init() — 신규 프로젝트 권장 ---
 * 내부에서 SysCtl_setClock(), ADC 트림 로드(Device_cal()),
 * Flash wait state 자동 설정을 일괄 처리한다.                           */
void System_Init(void)
{
    Device_init();
    Device_initGPIO();
}

/*--- 방법 B: SysCtl_setClock() 직접 호출 ---
 * XTAL 20MHz -> SYSCLK 200MHz:
 *   PLLRAWCLK = 20MHz x IMULT / [(REFDIV+1)x(ODIV+1)] = 400MHz
 *   REFDIV=0(실제÷1), ODIV=1(실제÷2) -> IMULT=40
 *   이후 SYSCLKDIVSEL=÷2 적용 -> SYSCLK = 200MHz                       */
void System_Init_Manual(void)
{
    SysCtl_setClock(SYSCTL_OSCSRC_XTAL  |
                    SYSCTL_IMULT(40)     |
                    SYSCTL_REFDIV(1)     |
                    SYSCTL_ODIV(2)       |
                    SYSCTL_SYSDIV(2)     |
                    SYSCTL_PLL_ENABLE);

    Flash_initModule(FLASH0CTRL_BASE, FLASH0ECC_BASE, DEVICE_FLASH_WAITSTATES);

    SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_2);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
}

1.9.2 ePWM1 초기화 — 20kHz 상보 PWM

/*==============================================================================
 * 파일   : epwm_init.c
 * 목적   : ePWM1 20kHz 대칭 PWM, 상보 출력, 데드밴드, ADC/ISR 트리거
 *============================================================================*/

#include "driverlib.h"
#include "device.h"

#define EPWM1_TBPRD      2500U   /* 100MHz/(2x20kHz)=2500 */
#define EPWM1_DEADBAND   20U     /* 200ns @ TBCLK=100MHz  */

void EPWM1_Init(void)
{
    /*--- 타임베이스 ---*/
    EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
    EPWM_setTimeBasePeriod(EPWM1_BASE, EPWM1_TBPRD);
    EPWM_setTimeBaseCounter(EPWM1_BASE, 0U);
    EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);

    /*--- 카운터 비교 ---*/
    EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, EPWM1_TBPRD/2);
    EPWM_setCounterCompareShadowLoadMode(EPWM1_BASE, EPWM_COUNTER_COMPARE_A,
                                         EPWM_COMP_LOAD_ON_CNTR_ZERO);

    /*--- 액션 퀄리파이어: 업카운트 CMPA→HIGH, 다운카운트 CMPA→LOW ---*/
    EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
        EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
    EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
        EPWM_AQ_OUTPUT_LOW,  EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA);

    /*--- 데드밴드: FED=DBFED×TTBCLK, RED=DBRED×TTBCLK ---*/
    EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_RED, true);
    EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH);
    EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_FED, true);
    EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_LOW);
    EPWM_setRisingEdgeDelay(EPWM1_BASE,  EPWM1_DEADBAND);
    EPWM_setFallingEdgeDelay(EPWM1_BASE, EPWM1_DEADBAND);

    /*--- ADC SOC 및 ISR 트리거: 카운터=0 시점 ---*/
    EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
    EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_SOC_A, 1U);
    EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);

    EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
    EPWM_setInterruptEventCount(EPWM1_BASE, 1U);
    EPWM_enableInterrupt(EPWM1_BASE);
}

1.9.3 ADC 초기화

/*==============================================================================
 * 파일   : adc_init.c
 * 목적   : ADCA 12-bit Single-ended 초기화, ePWM1 SOCA 트리거
 *============================================================================*/

#include "driverlib.h"
#include "device.h"

void ADCA_Init(void)
{
    ADC_enableConverter(ADCA_BASE);
    DEVICE_DELAY_US(1000U);   /* 전원 ON 후 안정화 대기 */

    /* 분해능은 반드시 ADC_setMode()로 설정 (트림값 동시 로드) */
    ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);

    /* PRESCALE=2 → ÷2.0 분주 */
    ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_2_0);

    /* SOC0: ePWM1 SOCA 트리거, S+H=(ACQPS+1)×T_SYSCLK */
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0,
                 ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN0, 15U);

    ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
}

/* 12-bit 전압 변환: V = raw/4096 × VREFHI */
float ADCA_Read_12bit(void)
{
    uint16_t raw = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
    return ((float)raw / 4096.0f) * 3.3f;
}

1.9.4 인터럽트 초기화 및 제어 루프 ISR

/*==============================================================================
 * 파일   : main_cpu1.c
 * 목적   : CPU1 메인 — 시스템 초기화 + 20kHz 제어 루프 ISR
 *============================================================================*/

#include "driverlib.h"
#include "device.h"

volatile float g_v_bus = 0.0f, g_duty = 0.5f, g_setpoint = 48.0f;
__interrupt void epwm1_isr(void);

void main(void)
{
    Device_init();
    Device_initGPIO();

    GPIO_setPadConfig(0U, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_0_EPWM1_A);
    GPIO_setPadConfig(1U, GPIO_PIN_TYPE_STD);
    GPIO_setPinConfig(GPIO_1_EPWM1_B);

    Interrupt_initModule();
    Interrupt_initVectorTable();
    Interrupt_register(INT_EPWM1, &epwm1_isr);

    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
    SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    EPWM1_Init();
    ADCA_Init();

    SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC);

    Interrupt_enable(INT_EPWM1);
    Interrupt_enableGlobal();
    ERTM;

    while(1)
    {
        /* 백그라운드: 통신, CPU2 IPC 등 비실시간 처리 */
    }
}

/* 제어 루프 ISR — 실행 주기 20kHz(50μs), 최소 레이턴시 14사이클(70ns) */
__interrupt void epwm1_isr(void)
{
    /*--- ADC 결과 읽기 ---*/
    uint16_t adc_raw = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
    g_v_bus = ((float)adc_raw / 4096.0f) * 3.3f;

    /*--- 제어 알고리즘 삽입 위치 (이후 장에서 구현) ---*/

    /*--- PWM 듀티비 업데이트 ---*/
    uint16_t cmpa = (uint16_t)(g_duty * (float)EPWM1_TBPRD);
    if(cmpa > EPWM1_TBPRD) cmpa = EPWM1_TBPRD;
    EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, cmpa);

    /*--- [필수①] ePWM ET 인터럽트 플래그 클리어 ---*/
    EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);

    /*--- [필수②] ePIE 그룹3 ACK 클리어 ---
     * PIEIFR 비트는 절대 직접 클리어하지 않는다.
     * PIEACK 클리어만이 안전한 방법이다.                                 */
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
}

1.10 개발 환경 구성

1.10.1 필수 소프트웨어

도구 권장 버전 용도
Code Composer Studio 12.x 이상 IDE, 디버거, Flash 프로그래머
C2000Ware 5.x 이상 F28P65x Driverlib, 예제, 문서
TI C28x CGT Compiler 22.6 이상 C/C++ → C28x 기계어
LAUNCHXL-F28P65X 평가 보드

1.10.2 컴파일러 핵심 옵션

[Optimization]
  -O2                    : 최적화 레벨 2

[Advanced Options]
  --fp_mode=relaxed      : FPU 활성화
  --tmu_support=tmu0     : TMU 삼각함수 가속

[Predefined Symbols]
  CPU1
  _LAUNCHXL_F28P65X

[Linker]
  ${C2000WARE}/driverlib/f28p65x/driverlib/Debug/driverlib.lib

 

참고문헌

  1. Texas Instruments, TMS320F28P65x Real-Time Microcontrollers Technical Reference Manual, SPRUIZ1B, July 2023 – Revised August 2024.
  2. Texas Instruments, TMS320F28P65x Real-Time Microcontrollers Data Sheet, SPRSP69D, Revised August 2025.
  3. Texas Instruments, F28P65x Peripheral Driver Library API Guide, v5.04.00.00.
  4. Texas Instruments, TMS320C28x CPU and Instruction Set Reference Guide.
  5. Texas Instruments, TMS320C28x Extended Instruction Sets Technical Reference Manual.