이 문서에서는 Texas Instruments의 TMS320F28388D 마이크로컨트롤러에서 ePWM(Enhanced Pulse Width Modulation) 모듈을 DriverLib API를 사용하여 설정하고 사용하는 방법을 상세히 다룹니다. C2000 시리즈의 고성능 마이크로컨트롤러인 TMS320F28388D의 ePWM 모듈을 활용하여 PWM 신호를 생성하는 방법을 배우고, 다양한 독립적인 예제 코드를 통해 실제 구현 방법을 익힐 수 있습니다. 각 코드에는 상세한 주석이 포함되어 있으며, Code Composer Studio(CCS) 환경에서 실행 가능합니다.
1. TMS320F28388D ePWM 개요
TMS320F28388D는 Texas Instruments의 C2000 시리즈에 속하는 고성능 32비트 마이크로컨트롤러로, 최대 16개의 ePWM 모듈을 제공합니다. ePWM 모듈은 모터 제어, 전력 변환, 조명 제어 등 정밀한 PWM 신호 생성이 필요한 실시간 제어 애플리케이션에 최적화되어 있습니다.
ePWM 모듈의 주요 특징
- 타임 베이스(Time-Base): 각 ePWM 모듈은 독립적인 타이머를 기반으로 PWM 신호를 생성하며, 주기와 듀티 사이클을 정밀하게 제어 가능.
- 카운터 모드: Up, Down, Up-Down 모드 지원.
- PWM 출력: 각 모듈은 두 개의 독립적인 출력(A, B)을 제공하며, 상보적 출력(Complementary PWM) 및 데드밴드(Deadband) 설정 가능.
- 트리거 이벤트: ADC 변환 트리거(SOCA, SOCB), 인터럽트, 또는 외부 동기화 신호 생성 가능.
- 고급 기능: 데드밴드 제어, 트립 존(Trip Zone), 이벤트 트리거, 고해상도 PWM(HRPWM) 지원.
- 클럭: 시스템 클럭(최대 200MHz)을 기반으로 동작하며, 프리스케일러를 통해 주파수 조정 가능.
DriverLib API는 하드웨어 레지스터를 직접 조작하는 대신 추상화된 함수를 제공하여 ePWM 설정을 간소화합니다.
2. 주요 ePWM DriverLib API 함수
아래는 TMS320F2838x의 ePWM 모듈을 제어하기 위해 자주 사용되는 DriverLib API 함수와 그 사용 방법입니다. 모든 함수는 epwm.h 및 hrpwm.h에 정의되어 있으며, C2000Ware v6.00.00.00을 기반으로 작성되었습니다. 시스템 클럭은 200MHz(주기 5ns)를 가정합니다.
2.1. ePWM 기본 설정 관련 함수
EPWM_setTimeBasePeriod(base, period)
- 설명: PWM 주기를 설정합니다. 주기는 타이머 베이스(TB) 클럭 사이클 단위로 지정됩니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소 (예: EPWM1_BASE).
- period: 타이머 주기 값 (0~65535, TBPRD 레지스터에 저장).
- 사용 예:
- 100kHz PWM 주기 (10µs) 설정: 200MHz 클럭에서 period = 2000.
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000); // 100kHz PWM
- 제약:
- 주기는 (period + 1) * TBCLK로 계산 (Up 모드 기준).
- period는 16비트 값으로 제한.
- 호출 전 SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWMx)로 모듈 클럭 활성화 필요.
EPWM_setTimeBaseCounterMode(base, mode)
- 설명: 타이머 카운터의 동작 모드를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- mode: 카운터 모드.
- EPWM_COUNTER_MODE_UP: 상향 카운팅.
- EPWM_COUNTER_MODE_DOWN: 하향 카운팅.
- EPWM_COUNTER_MODE_UP_DOWN: 상하향 카운팅.
- EPWM_COUNTER_MODE_STOP: 카운터 정지.
- 사용 예:
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP); // 상향 카운팅
- 제약:
- Up-Down 모드는 대칭 PWM에 유용하며, HRPWM 사용 시 주의.
EPWM_setClockPrescaler(base, prescaler, highSpeedPrescaler)
- 설명: ePWM 모듈의 클럭 분주를 설정하여 TBCLK를 조정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- prescaler: 시스템 클럭 분주 값 (EPWM_CLOCK_DIVIDER_1, EPWM_CLOCK_DIVIDER_2, ..., EPWM_CLOCK_DIVIDER_128).
- highSpeedPrescaler: HRPWM용 고속 클럭 분주 값 (EPWM_HSCLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_2, ..., EPWM_HSCLOCK_DIVIDER_14).
- 사용 예:
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1); // 1:1 클럭 (200MHz)
- 제약:
- TBCLK = SYSCLK / (prescaler * highSpeedPrescaler).
- HRPWM 사용 시 highSpeedPrescaler 설정에 주의.
- 레지스터 쓰기 후 SYSCTL_REGWRITE_DELAY 사용 권장.
2.2. PWM 출력 설정 관련 함수
EPWM_setActionQualifierAction(base, output, action, event)
- 설명: 특정 이벤트에서 PWM 출력(A 또는 B)의 동작을 설정합니다. 액션 퀄리파이어(AQ)를 통해 PWM 신호의 HIGH/LOW 전환을 제어합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- output: PWM 출력 채널 (EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_B).
- action: 출력 동작.
- EPWM_AQ_OUTPUT_NO_CHANGE: 변화 없음.
- EPWM_AQ_OUTPUT_LOW: LOW로 설정.
- EPWM_AQ_OUTPUT_HIGH: HIGH로 설정.
- EPWM_AQ_OUTPUT_TOGGLE: 토글.
- event: 이벤트 조건.
- EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO: 카운터=0.
- EPWM_AQ_OUTPUT_ON_TIMEBASE_PERIOD: 카운터=TBPRD.
- EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA: 카운터=CMPA (상향).
- EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPA: 카운터=CMPA (하향).
- EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPB: 카운터=CMPB (상향).
- EPWM_AQ_OUTPUT_ON_TIMEBASE_DOWN_CMPB: 카운터=CMPB (하향).
- 사용 예:
- 카운터=0에서 PWM_A를 HIGH, CMPA 상향 시 LOW:
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A, EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
- 제약:
- Up-Down 모드에서는 CMPA/CMPB 상향/하향 이벤트 주의.
EPWM_setCounterCompareValue(base, compModule, value)
- 설명: 비교 레지스터(CMPA 또는 CMPB) 값을 설정하여 PWM 듀티 사이클을 제어합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- compModule: 비교 레지스터 (EPWM_COUNTER_COMPARE_A, EPWM_COUNTER_COMPARE_B).
- value: 비교 값 (0~65535).
- 사용 예:
- 50% 듀티 사이클 (TBPRD=2000, CMPA=1000):
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
- 제약:
- value는 TBPRD 이하여야 의미 있는 듀티 사이클 생성.
- HRPWM 사용 시 정밀 조정 가능.
2.3. ADC 트리거 관련 함수
EPWM_enableADCTrigger(base, soc)
- 설명: ADC 트리거(SOCA 또는 SOCB)를 활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- soc: ADC 트리거 채널 (EPWM_ADC_TRIGGER_A, EPWM_ADC_TRIGGER_B).
- 사용 예:
EPWM_enableADCTrigger(EPWM1_BASE, EPWM_ADC_TRIGGER_A); // SOCA 활성화
EPWM_setADCTriggerSource(base, soc, source)
- 설명: ADC 트리거(SOCA/SOCB)의 발생 조건을 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- soc: ADC 트리거 채널 (EPWM_ADC_TRIGGER_A, EPWM_ADC_TRIGGER_B).
- source: 트리거 소스.
- EPWM_ADC_TRIGGER_EVENT_ZERO: 카운터=0.
- EPWM_ADC_TRIGGER_EVENT_PERIOD: 카운터=TBPRD.
- EPWM_ADC_TRIGGER_EVENT_UP_CMPA: 카운터=CMPA (상향).
- EPWM_ADC_TRIGGER_EVENT_DOWN_CMPA: 카운터=CMPA (하향).
- 사용 예:
EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_ADC_TRIGGER_A, EPWM_ADC_TRIGGER_EVENT_UP_CMPA);
EPWM_setADCTriggerEventPrescale(base, soc, prescale)
- 설명: ADC 트리거의 발생 빈도를 설정하는 프리스케일러를 지정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- soc: ADC 트리거 채널 (EPWM_ADC_TRIGGER_A, EPWM_ADC_TRIGGER_B).
- prescale: 트리거 프리스케일 값 (0~15, 0은 프리스케일러 비활성화).
- 사용 예:
EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_ADC_TRIGGER_A, 2); // 매 2번째 이벤트에서 트리거
2.4. 인터럽트 관련 함수
EPWM_setInterruptSource(base, source)
- 설명: ePWM 인터럽트 트리거 소스를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- source: 인터럽트 소스.
- EPWM_INT_TBCTR_ZERO: 카운터=0.
- EPWM_INT_TBCTR_PERIOD: 카운터=TBPRD.
- EPWM_INT_TBCTR_U_CMPA: 카운터=CMPA (상향).
- EPWM_INT_TBCTR_D_CMPA: 카운터=CMPA (하향).
- EPWM_INT_TBCTR_U_CMPB: 카운터=CMPB (상향).
- EPWM_INT_TBCTR_D_CMPB: 카운터=CMPB (하향).
- 사용 예:
EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO); // 카운터=0에서 인터럽트
EPWM_enableInterrupt(base)
- 설명: ePWM 모듈의 인터럽트를 활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
EPWM_enableInterrupt(EPWM1_BASE);
EPWM_clearEventTriggerInterruptFlag(base)
- 설명: ePWM 인터럽트 플래그를 지워 다음 인터럽트를 허용합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE); // ISR 내에서 호출
Interrupt_register(intNumber, handler)
- 설명: 인터럽트 서비스 루틴(ISR)을 등록합니다.
- 매개변수:
- intNumber: 인터럽트 번호 (예: INT_EPWM1).
- handler: ISR 함수 포인터.
- 사용 예:
Interrupt_register(INT_EPWM1, &epwm1ISR); // ePWM1 ISR 등록
Interrupt_clearACKGroup(group)
- 설명: PIE(Peripheral Interrupt Expansion) 그룹의 인터럽트 ACK를 지웁니다.
- 매개변수:
- group: PIE 그룹 (예: INTERRUPT_ACK_GROUP3 for ePWM1~6).
- 사용 예:
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3); // ISR 내에서 호출
2.5. 데드밴드 및 트립존 관련 함수
EPWM_setDeadBandControlMode(base, dbOutput, mode)
- 설명: 데드밴드 출력 모드(상승/하강 에지 지연)를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- dbOutput: 데드밴드 출력 (EPWM_DB_OUTPUT_A, EPWM_DB_OUTPUT_B).
- mode: 동작 모드.
- EPWM_DB_RED: 상승 에지 지연 활성화.
- EPWM_DB_FED: 하강 에지 지연 활성화.
- EPWM_DB_DISABLE: 비활성화.
- 사용 예:
EPWM_setDeadBandControlMode(EPWM1_BASE, EPWM_DB_OUTPUT_A, EPWM_DB_RED); // A 출력에 RED 활성화
EPWM_setDeadBandDelay(base, delayMode, delay)
- 설명: 데드밴드 지연 시간을 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- delayMode: 지연 모드 (EPWM_DB_RED, EPWM_DB_FED).
- delay: 지연 시간 (클럭 사이클 단위, 0~16383).
- 사용 예:
EPWM_setDeadBandDelay(EPWM1_BASE, EPWM_DB_RED, 100); // 100 사이클 RED 지연
EPWM_enableTripZoneSignals(base, tripSource)
- 설명: 트립존 신호를 활성화하여 PWM 출력을 제어합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- tripSource: 트립 소스 (비트 마스크, 예: EPWM_TZ_SIGNAL_CBC1, EPWM_TZ_SIGNAL_OST1).
- 사용 예:
EPWM_enableTripZoneSignals(EPWM1_BASE, EPWM_TZ_SIGNAL_CBC1); // TZ1 사이클 단위 트립 활성화
2.6. HRPWM 관련 함수
HRPWM(High-Resolution PWM)은 표준 PWM보다 정밀한 듀티 사이클, 주기, 위상 조정을 제공합니다. MEP(Micro-Edge Positioning) 스케일링을 통해 시스템 클럭(200MHz)에서 약 150ps 단위로 제어 가능합니다. HRPWM 사용 전 SysCtl_calibrateHRPWM으로 MEP 스케일링 캘리브레이션과 EPWM_setClockPrescaler로 적절한 highSpeedPrescaler 설정이 필요합니다. 모든 함수는 hrpwm.h에 정의되며, EALLOW 보호 레지스터에 접근합니다.
SysCtl_calibrateHRPWM()
- 설명: HRPWM 모듈의 MEP 스케일링 팩터를 캘리브레이션합니다.
- 매개변수: 없음.
- 사용 예:
SysCtl_calibrateHRPWM(); // 부팅 시 호출
- 제약:
- 시스템 부팅 시 1회 호출 권장.
- 온도 및 전압 조건에 따라 MEP 스케일링 팩터 변동 가능.
HRPWM_enablePeriodControl(base)
- 설명: HRPWM의 주기 제어 기능을 활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소 (예: EPWM1_BASE).
- 사용 예:
HRPWM_enablePeriodControl(EPWM1_BASE); // HRPWM 주기 제어 활성화
- 제약:
- HRPWM 지원 모듈(ePWM1~8)에서만 사용 가능 (TRM 섹션 15.10 확인).
HRPWM_disablePeriodControl(base)
- 설명: HRPWM의 주기 제어 기능을 비활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
HRPWM_disablePeriodControl(EPWM1_BASE); // HRPWM 주기 제어 비활성화
HRPWM_setTimeBasePeriod(base, periodCount)
- 설명: HRPWM 모드에서 통합된 주기(TBPRD:TBPRDHR)를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- periodCount: 통합 주기 값 (24비트, 0~0xFFFFFF).
- 사용 예:
- 100kHz PWM (TBPRD=1999, TBPRDHR=0xA):
HRPWM_setTimeBasePeriod(EPWM1_BASE, 0x19990A); // TBPRD=1999, TBPRDHR=0xA
- 제약:
- periodCount = (TBPRD << 8) | TBPRDHR.
- HRPWM 주기 제어 활성화(HRPWM_enablePeriodControl) 후 사용.
HRPWM_setHiResTimeBasePeriodOnly(base, hrPeriodCount)
- 설명: HRPWM 주기(TBPRDHR)만 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- hrPeriodCount: 고해상도 주기 값 (8비트, 0~255, 약 150ps 단위).
- 사용 예:
- TBPRDHR=10 (약 1.5ns 추가):
HRPWM_setHiResTimeBasePeriodOnly(EPWM1_BASE, 10);
- 제약:
- MEP 스케일링 팩터에 따라 실제 시간 단위 변동.
HRPWM_getTimeBasePeriod(base)
- 설명: HRPWM 모드에서 통합된 주기(TBPRD:TBPRDHR)를 반환합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
uint32_t period = HRPWM_getTimeBasePeriod(EPWM1_BASE); // 주기 값 읽기
- 반환값: 24비트 통합 주기 값.
HRPWM_getHiResTimeBasePeriodOnly(base)
- 설명: HRPWM 주기(TBPRDHR)만 반환합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
uint16_t hrPeriod = HRPWM_getHiResTimeBasePeriodOnly(EPWM1_BASE); // TBPRDHR 읽기
- 반환값: 8비트 고해상도 주기 값.
HRPWM_setCounterCompareValue(base, compModule, compCount)
- 설명: HRPWM 모드에서 통합된 비교 값(CMPA:CMPAHR 또는 CMPB:CMPBHR)을 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- compModule: 비교 모듈 (HRPWM_COUNTER_COMPARE_A, HRPWM_COUNTER_COMPARE_B).
- compCount: 통합 비교 값 (24비트, 0~0xFFFFFF).
- 사용 예:
- 50% 듀티 (TBPRD=2000, CMPA=1000, CMPAHR=0x10):
HRPWM_setCounterCompareValue(EPWM1_BASE, HRPWM_COUNTER_COMPARE_A, 0x100010);
- 제약:
- compCount = (CMPA << 8) | CMPAHR.
- HRPWM_setMEPControlMode로 듀티 제어 설정 필요.
HRPWM_setHiResCounterCompareValueOnly(base, compModule, hrCompCount)
- 설명: HRPWM 비교 값(CMPAHR 또는 CMPBHR)만 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- compModule: 비교 모듈 (HRPWM_COUNTER_COMPARE_A, HRPWM_COUNTER_COMPARE_B).
- hrCompCount: 고해상도 비교 값 (8비트, 0~255, 약 150ps 단위).
- 사용 예:
- CMPAHR=10 (약 1.5ns 추가):
HRPWM_setHiResCounterCompareValueOnly(EPWM1_BASE, HRPWM_COUNTER_COMPARE_A, 10);
HRPWM_getCounterCompareValue(base, compModule)
- 설명: HRPWM 모드에서 통합된 비교 값(CMPA:CMPAHR 또는 CMPB:CMPBHR)을 반환합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- compModule: 비교 모듈 (HRPWM_COUNTER_COMPARE_A, HRPWM_COUNTER_COMPARE_B).
- 사용 예:
uint32_t comp = HRPWM_getCounterCompareValue(EPWM1_BASE, HRPWM_COUNTER_COMPARE_A);
- 반환값: 24비트 통합 비교 값.
HRPWM_getHiResCounterCompareValueOnly(base, compModule)
- 설명: HRPWM 비교 값(CMPAHR 또는 CMPBHR)만 반환합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- compModule: 비교 모듈 (HRPWM_COUNTER_COMPARE_A, HRPWM_COUNTER_COMPARE_B).
- 사용 예:
uint16_t hrComp = HRPWM_getHiResCounterCompareValueOnly(EPWM1_BASE, HRPWM_COUNTER_COMPARE_A);
- 반환값: 8비트 고해상도 비교 값.
HRPWM_setMEPEdgeSelect(base, channel, mepEdgeMode)
- 설명: MEP(Micro-Edge Positioner)가 제어할 PWM 에지(상승/하강)를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- channel: 채널 (HRPWM_CHANNEL_A, HRPWM_CHANNEL_B).
- mepEdgeMode: MEP 에지 모드.
- HRPWM_MEP_CTRL_DISABLE: HRPWM 비활성화.
- HRPWM_MEP_CTRL_RISING_EDGE: 상승 에지 제어.
- HRPWM_MEP_CTRL_FALLING_EDGE: 하강 에지 제어.
- HRPWM_MEP_CTRL_RISING_AND_FALLING_EDGE: 양쪽 에지 제어.
- 사용 예:
HRPWM_setMEPEdgeSelect(EPWM1_BASE, HRPWM_CHANNEL_A, HRPWM_MEP_CTRL_RISING_EDGE);
- 제약:
- EALLOW 보호 레지스터 접근.
HRPWM_setMEPControlMode(base, channel, mepCtrlMode)
- 설명: MEP가 제어할 레지스터(CMPAHR/CMPBHR, TBPHSHR, TBPRDHR)를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- channel: 채널 (HRPWM_CHANNEL_A, HRPWM_CHANNEL_B).
- mepCtrlMode: MEP 제어 모드.
- HRPWM_MEP_DUTY_PERIOD_CTRL: CMPAHR/CMPBHR 또는 TBPRDHR 제어.
- HRPWM_MEP_PHASE_CTRL: TBPHSHR 제어.
- 사용 예:
HRPWM_setMEPControlMode(EPWM1_BASE, HRPWM_CHANNEL_A, HRPWM_MEP_DUTY_PERIOD_CTRL);
HRPWM_setCounterCompareShadowLoadEvent(base, channel, loadEvent)
- 설명: HRPWM 비교 레지스터(CMPAHR/CMPBHR)의 섀도우 로드 이벤트를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- channel: 채널 (HRPWM_CHANNEL_A, HRPWM_CHANNEL_B).
- loadEvent: 로드 이벤트.
- HRPWM_LOAD_ON_CNTR_ZERO: 카운터=0.
- HRPWM_LOAD_ON_CNTR_PERIOD: 카운터=TBPRD.
- HRPWM_LOAD_ON_CNTR_ZERO_PERIOD: 카운터=0 또는 TBPRD.
- 사용 예:
HRPWM_setCounterCompareShadowLoadEvent(EPWM1_BASE, HRPWM_CHANNEL_A, HRPWM_LOAD_ON_CNTR_ZERO);
HRPWM_setPhaseShift(base, phaseCount)
- 설명: HRPWM 모드에서 통합된 위상(TBPHS:TBPHSHR)을 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- phaseCount: 통합 위상 값 (24비트, 0~0xFFFFFF).
- 사용 예:
- 90도 위상 지연 (TBPHS=500, TBPHSHR=0x2):
HRPWM_setPhaseShift(EPWM1_BASE, 0x50002);
- 제약:
- HRPWM_enablePhaseShiftLoad 호출 필요.
HRPWM_setHiResPhaseShiftOnly(base, hrPhaseCount)
- 설명: HRPWM 위상(TBPHSHR)만 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- hrPhaseCount: 고해상도 위상 값 (8비트, 0~255).
- 사용 예:
HRPWM_setHiResPhaseShiftOnly(EPWM1_BASE, 10); // 약 1.5ns 위상 지연
HRPWM_enablePhaseShiftLoad(base)
- 설명: HRPWM 위상(TBPHSHR) 로드를 활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
HRPWM_enablePhaseShiftLoad(EPWM1_BASE);
HRPWM_disablePhaseShiftLoad(base)
- 설명: HRPWM 위상(TBPHSHR) 로드를 비활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
HRPWM_disablePhaseShiftLoad(EPWM1_BASE);
HRPWM_setSyncPulseSource(base, syncPulseSource)
- 설명: HRPWM SYNC 펄스 소스를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- syncPulseSource: SYNC 소스.
- HRPWM_PWMSYNC_SOURCE_PERIOD: 카운터=TBPRD.
- HRPWM_PWMSYNC_SOURCE_ZERO: 카운터=0.
- HRPWM_PWMSYNC_SOURCE_COMPC_UP: 카운터=COMPC (상향).
- HRPWM_PWMSYNC_SOURCE_COMPC_DOWN: 카운터=COMPC (하향).
- HRPWM_PWMSYNC_SOURCE_COMPD_UP: 카운터=COMPD (상향).
- HRPWM_PWMSYNC_SOURCE_COMPD_DOWN: 카운터=COMPD (하향).
- 사용 예:
HRPWM_setSyncPulseSource(EPWM1_BASE, HRPWM_PWMSYNC_SOURCE_ZERO);
HRPWM_setRisingEdgeDelay(base, redCount)
- 설명: HRPWM 모드에서 통합된 상승 에지 지연(DBRED:DBREDHR)을 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- redCount: 통합 RED 값 (21비트, 0~0x1FFFFF).
- 사용 예:
- DBRED=4, DBREDHR=0x1:
HRPWM_setRisingEdgeDelay(EPWM1_BASE, 0x201);
HRPWM_setHiResRisingEdgeDelayOnly(base, hrRedCount)
- 설명: HRPWM 상승 에지 지연(DBREDHR)만 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- hrRedCount: 고해상도 RED 값 (7비트, 0~127).
- 사용 예:
HRPWM_setHiResRisingEdgeDelayOnly(EPWM1_BASE, 10); // 약 1.5ns RED
HRPWM_setFallingEdgeDelay(base, fedCount)
- 설명: HRPWM 모드에서 통합된 하강 에지 지연(DBFED:DBFEDHR)을 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- fedCount: 통합 FED 값 (21비트, 0~0x1FFFFF).
- 사용 예:
- DBFED=4, DBFEDHR=0x1:
HRPWM_setFallingEdgeDelay(EPWM1_BASE, 0x201);
HRPWM_setHiResFallingEdgeDelayOnly(base, hrFedCount)
- 설명: HRPWM 하강 에지 지연(DBFEDHR)만 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- hrFedCount: 고해상도 FED 값 (7비트, 0~127).
- 사용 예:
HRPWM_setHiResFallingEdgeDelayOnly(EPWM1_BASE, 10); // 약 1.5ns FED
HRPWM_setDeadbandMEPEdgeSelect(base, mepDBEdge)
- 설명: 데드밴드의 MEP 제어 에지(상승/하강)를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- mepDBEdge: 데드밴드 MEP 모드.
- HRPWM_DB_MEP_CTRL_DISABLE: 비활성화.
- HRPWM_DB_MEP_CTRL_RED: 상승 에지 제어.
- HRPWM_DB_MEP_CTRL_FED: 하강 에지 제어.
- HRPWM_DB_MEP_CTRL_RED_FED: 양쪽 에지 제어.
- 사용 예:
HRPWM_setDeadbandMEPEdgeSelect(EPWM1_BASE, HRPWM_DB_MEP_CTRL_RED_FED);
HRPWM_setRisingEdgeDelayLoadMode(base, loadEvent)
- 설명: HRPWM 상승 에지 지연(DBREDHR)의 로드 이벤트를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- loadEvent: 로드 이벤트 (HRPWM_LOAD_ON_CNTR_ZERO, HRPWM_LOAD_ON_CNTR_PERIOD, HRPWM_LOAD_ON_CNTR_ZERO_PERIOD).
- 사용 예:
HRPWM_setRisingEdgeDelayLoadMode(EPWM1_BASE, HRPWM_LOAD_ON_CNTR_ZERO);
HRPWM_setFallingEdgeDelayLoadMode(base, loadEvent)
- 설명: HRPWM 하강 에지 지연(DBFEDHR)의 로드 이벤트를 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- loadEvent: 로드 이벤트 (HRPWM_LOAD_ON_CNTR_ZERO, HRPWM_LOAD_ON_CNTR_PERIOD, HRPWM_LOAD_ON_CNTR_ZERO_PERIOD).
- 사용 예:
HRPWM_setFallingEdgeDelayLoadMode(EPWM1_BASE, HRPWM_LOAD_ON_CNTR_ZERO);
HRPWM_setMEPStep(base, mepCount)
- 설명: MEP 스텝 수를 설정합니다 (HRMSTEP 레지스터).
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- mepCount: MEP 스텝 수 (0~255, 약 150ps 단위).
- 사용 예:
HRPWM_setMEPStep(EPWM1_BASE, 100); // MEP 스텝 100 설정
- 제약:
- HRPWM_enableAutoConversion 비활성화 시 수동 설정 필요.
HRPWM_enableAutoConversion(base)
- 설명: MEP 스케일링의 자동 조정을 활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
HRPWM_enableAutoConversion(EPWM1_BASE); // SFO 라이브러리와 함께 사용
- 제약:
- SFO(Scale Factor Optimization) 라이브러리 필요.
HRPWM_disableAutoConversion(base)
- 설명: MEP 스케일링의 자동 조정을 비활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- 사용 예:
HRPWM_disableAutoConversion(EPWM1_BASE); // 수동 MEP 설정
HRPWM_setTranslatorRemainder(base, trremVal)
- 설명: 트랜슬레이터 나머지 값(TRREM)을 설정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- trremVal: 나머지 값 (0~2047).
- 사용 예:
HRPWM_setTranslatorRemainder(EPWM1_BASE, 100);
- 제약:
- 고급 HRPWM 조정에 사용, TRM 섹션 15.10.2 참조.
HRPWM_setOutputSwapMode(base, enableOutputSwap)
- 설명: PWM A와 B 출력 스왑을 활성화/비활성화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- enableOutputSwap: 스왑 활성화 (true) 또는 비활성화 (false).
- 사용 예:
HRPWM_setOutputSwapMode(EPWM1_BASE, true); // A와 B 출력 스왑
HRPWM_setChannelBOutputPath(base, outputOnB)
- 설명: PWM B 출력 경로를 설정합니다 (정상 또는 A의 반전).
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- outputOnB: 출력 경로 (HRPWM_OUTPUT_ON_B_NORMAL, HRPWM_OUTPUT_ON_B_INV_A).
- 사용 예:
HRPWM_setChannelBOutputPath(EPWM1_BASE, HRPWM_OUTPUT_ON_B_INV_A); // B는 A의 반전
2.7. 동기화 관련 함수
EPWM_enableSyncOutPulseSource(base, syncOutPulseSource)
- 설명: SYNC_OUT 펄스 소스를 활성화하여 다른 ePWM 모듈과 동기화합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- syncOutPulseSource: SYNC_OUT 소스.
- EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO: 카운터=0.
- EPWM_SYNC_OUT_PULSE_ON_CNTR_PERIOD: 카운터=TBPRD.
- EPWM_SYNC_OUT_PULSE_ON_CNTR_COMPARE: 카운터=CMPA/CMPB.
- 사용 예:
EPWM_enableSyncOutPulseSource(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO);
EPWM_setSyncInPulseSource(base, syncInPulseSource)
- 설명: SYNC_IN 펄스 소스를 설정하여 외부 또는 다른 ePWM 모듈로부터 동기화 신호를 수신합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- syncInPulseSource: SYNC_IN 소스 (예: EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1).
- 사용 예:
EPWM_setSyncInPulseSource(EPWM2_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1);
EPWM_setPhaseShift(base, phase)
- 설명: ePWM 모듈의 위상 지연을 설정하여 동기화된 PWM 신호 간의 위상 차이를 조정합니다.
- 매개변수:
- base: ePWM 모듈의 베이스 주소.
- phase: 위상 지연 값 (클럭 사이클 단위, 0~65535).
- 사용 예:
EPWM_setPhaseShift(EPWM2_BASE, 500); // 90도 위상 지연 (2.5µs, TBPRD=2000)
3. ePWM 설정 및 동작 원리
- 주기 계산: 주기는 (TBPRD + 1) * TBCLK로 결정. TBCLK = SYSCLK / (prescaler * highSpeedPrescaler).
- 듀티 사이클: CMPA/CMPB 값으로 제어. Up 모드에서 듀티 = CMPA / (TBPRD + 1).
- 동기화: SYNC_IN/SYNC_OUT을 통해 다중 ePWM 모듈 간 위상 정렬 가능.
- 인터럽트: 카운터 이벤트(예: TBCTR=0)에서 발생, ISR에서 플래그 지우고 PIE ACK 처리.
- 데드밴드: PWM A/B 출력 간 지연으로 스위칭 충돌 방지.
- HRPWM: MEP 스케일링(약 150ps)을 통해 고해상도 PWM 생성. 캘리브레이션 후 사용.
- 참고: F2838x TRM (SPRUII0) 섹션 15.2 (ePWM), 15.8 (인터럽트), 15.9 (동기화), 15.10 (HRPWM).
- 시스템 초기화: 시스템 클럭과 GPIO 초기화(Device_init(), Device_initGPIO()), 인터럽트 모듈 초기화.
- ePWM 모듈 설정: 클럭 활성화, 타임 베이스 주기, 카운터 모드, PWM 출력 동작 설정.
- ADC 트리거 또는 인터럽트 설정(선택): ADC 트리거 설정 또는 인터럽트 활성화.
- 데드밴드 및 트립 존 설정(선택): 데드밴드 및 트립 존 설정.
- ePWM 활성화: ePWM 모듈 활성화.
4. ePWM 예제 코드
아래는 독립적인 ePWM 예제 코드로, C2000Ware의 DriverLib를 기반으로 작성되었습니다. GPIO 설정은 별도의 initGPIO()
함수로 분리되어 있으며, 모든 코드는 CCS에서 바로 실행 가능합니다.
4.1. 예제 1: 기본 PWM 신호 생성
ePWM1을 사용하여 100kHz, 50% 듀티 사이클의 PWM 신호를 생성합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
volatile uint32_t pwmStatus = 0; // 0: 초기화 완료, 1: PWM 동작 중, 0xFFFF: 오류
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A로 설정 (F2838x의 기본 매핑)
GPIO_setPinConfig(GPIO_0_EPWM1A); // GPIO0을 ePWM1A로 멀티플렉싱
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT); // 출력 모드 설정
GPIO_setPadConfig(0, GPIO_PIN_TYPE_STD); // 표준 설정 (풀업 필요 시 조정)
// 디버깅용 LED 설정 (LAUNCHXL-F28379D 기준, GPIO31=LED)
GPIO_setPinConfig(GPIO_31_GPIO31); // GPIO31을 일반 GPIO로 설정
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // 출력 모드 설정
GPIO_setPadConfig(31, GPIO_PIN_TYPE_STD); // 표준 설정
GPIO_writePin(31, 0); // 초기 LED OFF
}
// ePWM1 초기화 함수
void initEPWM(void)
{
// ePWM1 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM 클럭 분주 설정 (PLLSYSCLK / 1)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
// 클럭 분주 설정 (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
// 카운터 모드 설정: Up 카운터
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// PWM_A 동작 설정: 카운터=0일 때 HIGH, CMPA에서 LOW
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 듀티 사이클 50% 설정 (CMPA = period/2)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
// 상태 업데이트: PWM 동작 중
pwmStatus = 1;
}
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 초기화 (확장성을 위해 포함)
Interrupt_initModule();
Interrupt_initVectorTable();
// 시스템 클럭 확인 (디버깅용)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000) // 200MHz가 아닌 경우
{
pwmStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// Watchdog 설정
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64); // INTOSC1 / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64); // PREDIVCLK / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 리셋 모드
SysCtl_enableWatchdog(); // Watchdog 활성화
// ePWM1 초기화
initEPWM();
// ePWM 초기화 오류 확인
if (pwmStatus != 1)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// 글로벌 인터럽트 활성화 (확장성을 위해 포함)
EINT;
// 무한 루프: PWM 신호는 하드웨어로 자동 생성
for(;;)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 디버깅용: 상태 표시 (GPIO31 LED로 상태 출력)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
// 1초 대기 (디버깅 및 CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1의 PWM_A 출력으로 100kHz, 50% 듀티 사이클 PWM 신호 생성.
- 설정: Up 카운터, 주기 2000(100kHz @ 200MHz), CMPA=1000(50% 듀티).
- GPIO: GPIO0(ePWM1A), GPIO31(LED).
- 출력: GPIO0(ePWM1A)에 PWM 신호 출력, 정상 동작 시 LED ON.
4.2. 예제 2: 인터럽트를 사용한 듀티 사이클 동적 변경
ePWM1의 인터럽트를 사용하여 PWM 듀티 사이클을 동적으로 변경합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
volatile uint32_t pwmStatus = 0; // 0: 초기화 완료, 1: PWM 동작 중, 0xFFFF: 오류
// 듀티 사이클 저장 변수 (초기 25% 듀티, 2000 * 0.25 = 500)
volatile uint16_t dutyCycle = 500;
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A로 설정
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
// 디버깅용 LED 설정 (GPIO31)
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
GPIO_writePin(31, 0); // 초기 LED OFF
}
// 인터럽트 서비스 루틴 (ISR)
__interrupt void epwm1ISR(void)
{
// 듀티 사이클 증가 (0~100% 순환, 100단위로 5%씩 증가)
dutyCycle += 100;
if (dutyCycle > 2000) dutyCycle = 0; // 주기 초과 시 0%로 초기화
// CMPA 업데이트로 듀티 사이클 변경
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, dutyCycle);
// 인터럽트 플래그 지우기
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
// PIE 인터럽트 ACK
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
// 상태 업데이트
pwmStatus = 1;
}
// ePWM1 초기화 함수
void initEPWM(void)
{
// ePWM1 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM 클럭 분주 설정 (PLLSYSCLK / 1)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
// 클럭 분주 설정 (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
// 카운터 모드 설정: Up 카운터
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// PWM_A 동작 설정: 카운터=0일 때 HIGH, CMPA에서 LOW
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 초기 듀티 사이클 설정 (25%)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, dutyCycle);
// 인터럽트 설정: 카운터=0일 때 발생
EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
EPWM_enableInterrupt(EPWM1_BASE);
}
// 메인 함수
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// ePWM1 인터럽트 ISR 등록
Interrupt_register(INT_EPWM1, &epwm1ISR);
// 시스템 클럭 확인 (디버깅용)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000) // 200MHz가 아닌 경우
{
pwmStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// Watchdog 설정
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64); // INTOSC1 / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64); // PREDIVCLK / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 리셋 모드
SysCtl_enableWatchdog(); // Watchdog 활성화
// ePWM1 초기화
initEPWM();
// ePWM 초기화 오류 확인
if (pwmStatus != 1)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: PWM 신호는 하드웨어로 자동 생성
for(;;)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 디버깅용: 상태 표시 (GPIO31 LED로 상태 출력)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
// 1초 대기 (디버깅 및 CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: 100kHz PWM 신호 생성, 인터럽트를 통해 듀티 사이클을 0~100%로 동적 변경.
- 인터럽트: 카운터=0일 때 ISR에서 CMPA 업데이트.
- GPIO: GPIO0(ePWM1A), GPIO31(LED).
- 결과: 듀티 사이클이 주기적으로 변화, 정상 동작 시 LED ON.
4.3. 예제 3: ADC 트리거를 위한 ePWM 설정
ePWM1의 SOCA 신호를 사용하여 ADC 변환을 트리거합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
volatile uint32_t pwmStatus = 0; // 0: 초기화 완료, 1: 동작 중, 0xFFFF: 오류
// ADC 결과 저장 버퍼
#define RESULTS_BUFFER_SIZE 256
uint16_t adcResults[RESULTS_BUFFER_SIZE];
volatile uint16_t index = 0;
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A로 설정
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
// 디버깅용 LED 설정 (GPIO31)
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
GPIO_writePin(31, 0); // 초기 LED OFF
}
// ADC 인터럽트 서비스 루틴
__interrupt void adcA1ISR(void)
{
// ADC 변환 결과 읽기
adcResults[index] = ADC_readResult(ADCA_BASE, ADC_SOC_NUMBER0);
// 인덱스 증가 및 버퍼 오버플로우 방지
index++;
if (index >= RESULTS_BUFFER_SIZE) index = 0;
// 인터럽트 플래그 지우기
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
// PIE 인터럽트 ACK
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
// 상태 업데이트
pwmStatus = 1;
}
// ePWM1 초기화 함수
void initEPWM(void)
{
// ePWM1 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM 클럭 분주 설정 (PLLSYSCLK / 1)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
// 클럭 분주 설정 (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
// 카운터 모드 설정: Up 카운터
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// PWM_A 동작 설정: 카운터=0일 때 HIGH, CMPA에서 LOW
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 듀티 사이클 50% 설정 (CMPA = period/2)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
// SOCA 트리거 설정: 카운터=0일 때 발생
EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_SOC_A, 1);
// 상태 업데이트
pwmStatus = 0; // 초기화 완료
}
// ADC 초기화 함수
void initADC(void)
{
// ADC 클럭 활성화
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_ADCA);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ADC 설정: 50MHz 클럭, 12비트, 단일 종단
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0); // 200MHz / 4 = 50MHz
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
// SOC0 설정: ePWM1_SOCA 트리거, ADCIN0 채널
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN0, 15);
// 인터럽트 설정
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
// ADC 활성화
ADC_enableConverter(ADCA_BASE);
// ADC 안정화를 위해 1ms 지연
DEVICE_DELAY_US(1000);
}
// 메인 함수
void main(void)
{
uint16_t i;
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// ADC 인터럽트 ISR 등록
Interrupt_register(INT_ADCA1, &adcA1ISR);
// ADC 결과 버퍼 초기화
for (i = 0; i < RESULTS_BUFFER_SIZE; i++)
{
adcResults[i] = 0;
}
// 시스템 클럭 확인 (디버깅용)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000) // 200MHz가 아닌 경우
{
pwmStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// Watchdog 설정
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64); // INTOSC1 / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64); // PREDIVCLK / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 리셋 모드
SysCtl_enableWatchdog(); // Watchdog 활성화
// ADC 초기화
initADC();
// ePWM1 초기화
initEPWM();
// ePWM 초기화 오류 확인
if (pwmStatus != 0)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: PWM 및 ADC는 하드웨어로 자동 실행
for(;;)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 디버깅용: 상태 표시 (GPIO31 LED로 상태 출력)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
// 1초 대기 (디버깅 및 CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1의 SOCA 신호로 ADC-A의 ADCIN0 채널 변환 트리거.
- ePWM 설정: 100kHz PWM, 카운터=0일 때 SOCA 트리거.
- ADC 설정: 12비트, ePWM1_SOCA 트리거.
- GPIO: GPIO0(ePWM1A), GPIO31(LED).
- 결과: ADC 변환 결과는 adcResults 버퍼에 저장, 정상 동작 시 LED ON.
4.4. 예제 4: 데드밴드를 사용한 상보 PWM
ePWM1의 PWM_A와 PWM_B를 상보적으로 설정하고 데드밴드를 적용합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
volatile uint32_t pwmStatus = 0; // 0: 초기화 완료, 1: 동작 중, 0xFFFF: 오류
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A로 설정
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
// GPIO1을 ePWM1B로 설정
GPIO_setPinConfig(GPIO_1_EPWM1B);
GPIO_setDirectionMode(1, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(1, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
// 디버깅용 LED 설정 (GPIO31)
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
GPIO_writePin(31, 0); // 초기 LED OFF
}
// ePWM1 초기화 함수
void initEPWM(void)
{
// ePWM1 클럭 활성화
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM 클럭 분주 설정 (PLLSYSCLK / 1)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
// 클럭 분주 설정 (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
// 카운터 모드 설정: Up 카운터
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// PWM_A 동작 설정: 카운터=0일 때 HIGH, CMPA에서 LOW
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// PWM_B 동작 설정: 상보 출력 (카운터=0일 때 LOW, CMPA에서 HIGH)
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_B,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_B,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 듀티 사이클 50% 설정 (CMPA = period/2)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
// 데드밴드 설정: 100ns (20 사이클 @ 200MHz, TBCLK = 200MHz)
EPWM_setRisingEdgeDelayCount(EPWM1_BASE, 20); // RED: 100ns
EPWM_setFallingEdgeDelayCount(EPWM1_BASE, 20); // FED: 100ns
EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_RED, true); // RED 활성화
EPWM_setDeadBandDelayMode(EPWM1_BASE, EPWM_DB_FED, true); // FED 활성화
EPWM_setRisingEdgeDeadBandDelayInput(EPWM1_BASE, EPWM_DB_INPUT_EPWMA); // 입력: ePWMA
EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_RED, EPWM_DB_POLARITY_ACTIVE_HIGH); // RED 폴라리티
EPWM_setDeadBandDelayPolarity(EPWM1_BASE, EPWM_DB_FED, EPWM_DB_POLARITY_ACTIVE_HIGH); // FED 폴라리티
EPWM_setDeadBandControlShadowLoadMode(EPWM1_BASE, EPWM_DB_LOAD_ON_CNTR_ZERO); // 섀도우 로드
// 상태 업데이트
pwmStatus = 0; // 초기화 완료
}
// 메인 함수
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 초기화 (확장성을 위해 포함)
Interrupt_initModule();
Interrupt_initVectorTable();
// 시스템 클럭 확인 (디버깅용)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000) // 200MHz가 아닌 경우
{
pwmStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// Watchdog 설정
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64); // INTOSC1 / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64); // PREDIVCLK / 64
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 리셋 모드
SysCtl_enableWatchdog(); // Watchdog 활성화
// ePWM1 초기화
initEPWM();
// ePWM 초기화 오류 확인
if (pwmStatus != 0)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: PWM은 하드웨어로 자동 실행
for(;;)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 디버깅용: 상태 표시 (GPIO31 LED로 상태 출력)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
// 1초 대기 (디버깅 및 CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1의 PWM_A와 PWM_B로 상보 PWM 신호 생성, 100ns 데드밴드 적용.
- 설정: 100kHz PWM, 50% 듀티, 데드밴드 모듈 활성화.
- GPIO: GPIO0(ePWM1A), GPIO1(ePWM1B), GPIO31(LED).
- 출력: PWM_A와 PWM_B는 상보적이며, 스위칭 충돌 방지를 위해 100ns 지연, 정상 동작 시 LED ON.
- 용도: 모터 드라이버 또는 인버터 제어에 적합.
4.5. 예제 5: 동기화된 다중 ePWM 모듈
ePWM1과 ePWM2를 동기화하여 동일한 주기로 PWM 신호를 생성합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
volatile uint32_t pwmStatus = 0; // 0: 초기화 완료, 1: 동작 중, 0xFFFF: 오류
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A로 설정
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
// GPIO2을 ePWM2A로 설정
ASSERT(EPWM_isBaseValid(EPWM2_BASE));
GPIO_setPinConfig(GPIO_2_EPWM2A);
GPIO_setDirectionMode(2, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(2, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
// 디버깅용 LED 설정 (GPIO31)
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
GPIO_writePin(31, 0); // 초기 LED OFF
}
// ePWM1 및 ePWM2 초기화 함수
void initEPWM(void)
{
// ePWM1, ePWM2 클럭 활성화
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
ASSERT(EPWM_isBaseValid(EPWM2_BASE));
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM 클럭 분주 설정 (PLLSYSCLK / 1)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
EPWM_setTimeBasePeriod(EPWM2_BASE, 2000);
// 클럭 분주 설정 (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
EPWM_setClockPrescaler(EPWM2_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 카운터 모드 설정: Up 카운터
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
EPWM_setTimeBaseCounterMode(EPWM2_BASE, EPWM_COUNTER_MODE_UP);
// ePWM2를 ePWM1과 동기화
EPWM_enableSyncOutPulseSource(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO);
EPWM_setSyncInPulseSource(EPWM2_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1);
EPWM_setPhaseShift(EPWM2_BASE, 0); // 위상 지연 없음
EPWM_setCountModeAfterSync(EPWM2_BASE, EPWM_COUNT_MODE_UP_AFTER_SYNC);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM1 PWM_A 동작 설정: 카운터=0일 때 HIGH, CMPA에서 LOW
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000); // 50% 듀티
// ePWM2 PWM_A 동작 설정: ePWM1과 동일
EPWM_setActionQualifierAction(EPWM2_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM2_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
EPWM_setCounterCompareValue(EPWM2_BASE, EPWM_COUNTER_COMPARE_A, 1000); // 50% 듀티
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 상태 업데이트
pwmStatus = 0; // 초기화 완료
}
// 메인 함수
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 초기화 (확장성을 위해 포함)
Interrupt_initModule();
Interrupt_initVectorTable();
// 시스템 클럭 확인 (디버깅용)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000) // 200MHz가 아닌 경우
{
pwmStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// Watchdog 설정
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64); // INTOSC1 / 64
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64); // PREDIVCLK / 64
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 리셋 모드
SysCtl_enableWatchdog(); // Watchdog 활성화
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM1, ePWM2 초기화
initEPWM();
// ePWM 초기화 오류 확인
if (pwmStatus != 0)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// PWM 정상 동작 상태로 전환
pwmStatus = 1; // 동작 중
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: PWM은 하드웨어로 자동 실행
for(;;)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 디버깅용: 상태 표시 (GPIO31 LED로 상태 출력)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
// 1초 대기 (디버깅 및 CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1과 ePWM2를 동기화하여 100kHz, 50% 듀티 사이클 PWM 신호 생성.
- 설정: ePWM1이 마스터, ePWM2가 동기화된 슬레이브. 동일 주기 및 듀티.
- GPIO: GPIO0(ePWM1A), GPIO2(ePWM2A), GPIO31(LED).
- 출력: 동기화된 PWM 신호 출력, 정상 동작 시 LED ON.
- 용도: 다상 모터 제어 또는 동기화된 전력 변환.
4.6. 예제 6: HRPWM(고해상도 PWM)
ePWM1에서 HRPWM을 사용하여 나노초 단위의 정밀 듀티 사이클을 제어합니다.
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
volatile uint32_t pwmStatus = 0; // 0: 초기화 완료, 1: 동작 중, 0xFFFF: 오류
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A로 설정
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
// 디버깅용 LED 설정 (GPIO31)
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 풀업 설정
GPIO_writePin(31, 0); // 초기 LED OFF
}
// ePWM1 HRPWM 초기화 함수
void initEPWM(void)
{
// ePWM1 클럭 활성화
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM 클럭 분주 설정 (PLLSYSCLK / 1)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
// 클럭 분주 설정 (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 카운터 모드 설정: Up 카운터
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// PWM_A 동작 설정: 카운터=0일 때 HIGH, CMPA에서 LOW
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 듀티 사이클 50% 설정 (CMPA = period/2)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
// HRPWM 설정
HRPWM_enablePeriodControl(EPWM1_BASE); // HRPWM 활성화
HRPWM_setMEPControlMode(EPWM1_BASE, HRPWM_CHANNEL_A, HRPWM_MEP_DUTY_PERIOD_CTRL); // 듀티 제어 모드
HRPWM_setMEPEdgeSelect(EPWM1_BASE, HRPWM_CHANNEL_A, HRPWM_MEP_CTRL_RISING_EDGE); // 상승 에지 제어
HRPWM_setHiResCounterCompareValueOnly(EPWM1_BASE, HRPWM_COUNTER_COMPARE_A, 8); // 8 MEP 스텝 (약 40ns @ 200MHz)
HRPWM_setMEPStep(EPWM1_BASE, 8); // MEP 스텝 수 설정
HRPWM_enableAutoConversion(EPWM1_BASE); // MEP 자동 스케일링 활성화
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// 상태 업데이트
pwmStatus = 0; // 초기화 완료
}
// 메인 함수
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 초기화 (확장성을 위해 포함)
Interrupt_initModule();
Interrupt_initVectorTable();
// 시스템 클럭 확인 (디버깅용)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000) // 200MHz가 아닌 경우
{
pwmStatus = 0xFFFF; // 오류 상태
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// Watchdog 설정
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64); // INTOSC1 / 64
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64); // PREDIVCLK / 64
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 리셋 모드
SysCtl_enableWatchdog(); // Watchdog 활성화
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 지연
// ePWM1 초기화
initEPWM();
// ePWM 초기화 오류 확인
if (pwmStatus != 0)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // LED OFF로 오류 표시
ESTOP0; // 디버깅용 정지
}
// PWM 정상 동작 상태로 전환
pwmStatus = 1; // 동작 중
// 글로벌 인터럽트 활성화
EINT;
// 무한 루프: PWM은 하드웨어로 자동 실행
for(;;)
{
// Watchdog 서비스
SysCtl_serviceWatchdog();
// 디버깅용: 상태 표시 (GPIO31 LED로 상태 출력)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0); // 정상 동작 시 LED ON
// 1초 대기 (디버깅 및 CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1에서 HRPWM을 사용하여 100kHz, 약 50%+40ns 듀티 사이클 PWM 신호 생성.
- 설정: HRPWM 활성화, MEP(Micro Edge Positioner)로 정밀 제어.
- GPIO: GPIO0(ePWM1A), GPIO31(LED).
- 출력: 정밀 PWM 신호 출력, 정상 동작 시 LED ON.
- 용도: 고정밀 전력 변환 또는 고속 스위칭 애플리케이션.
4.7. 예제 7: 트립 존(Trip Zone) 설정
외부 트립 신호로 ePWM1을 비활성화하는 보호 기능을 구현합니다.
#include "driverlib.h"
#include "device.h"
// Debugging status variable
volatile uint32_t pwmStatus = 0; // 0: Initialized, 1: Running, 0xFFFF: Error
// Initialize GPIO and X-BAR for Trip Zone
void initGPIO(void)
{
// Configure GPIO0 as ePWM1A output
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
GPIO_setPinConfig(GPIO_0_EPWM1A); // From pin_map.h: 0x00060001U
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // Pull-up enabled
// Configure GPIO12 as general-purpose input for TZ1
GPIO_setPinConfig(GPIO_12_GPIO12); // From pin_map.h: 0x00061800U
GPIO_setDirectionMode(12, GPIO_DIR_MODE_IN);
GPIO_setPadConfig(12, GPIO_PIN_TYPE_PULLUP); // Pull-up enabled
// Route GPIO12 to TZ1 via Input X-BAR
XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT1, 12); // Map GPIO12 to XBAR_INPUT1 (TZ1)
// Configure ePWM X-BAR for TRIP4 (TZ1)
XBAR_setEPWMMuxConfig(XBAR_TRIP4, XBAR_EPWM_MUX01_INPUTXBAR1); // Route XBAR_INPUT1 to TRIP4
XBAR_enableEPWMMux(XBAR_TRIP4, XBAR_MUX01); // Enable MUX01 for TRIP4
XBAR_invertEPWMSignal(XBAR_TRIP4, false); // Ensure non-inverted signal
XBAR_lockInput(INPUTXBAR_BASE, XBAR_INPUT1); // Optional: Lock Input X-BAR configuration
// Configure GPIO31 for debugging LED
GPIO_setPinConfig(GPIO_31_GPIO31); // From pin_map.h: 0x00081E00U
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT);
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // Pull-up enabled
GPIO_writePin(31, 0); // Initialize LED OFF
}
// Trip Zone Interrupt Service Routine
__interrupt void tripZoneISR(void)
{
// Update status: Trip occurred
pwmStatus = 0xFFFF; // Error state
// Clear Trip Zone flag
EPWM_clearTripZoneFlag(EPWM1_BASE, EPWM_TZ_INTERRUPT_CBC);
// Acknowledge interrupt
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP2);
}
void initEPWM(void)
{
// Enable ePWM1 clock
ASSERT(EPWM_isBaseValid(EPWM1_BASE));
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // Register write delay
// Set ePWM clock divider (PLLSYSCLK / 1)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // Register write delay
// Set period: 100kHz PWM (200MHz / 2000 = 100kHz)
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
// Set clock prescaler (1:1)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
SYSCTL_REGWRITE_DELAY; // Register write delay
// Counter mode: Up counter
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// PWM_A action: HIGH at counter=0, LOW at CMPA
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// Set 50% duty cycle (CMPA = period/2)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
// Enable Trip Zone: TZ1 as one-shot trip
EPWM_enableTripZoneSignals(EPWM1_BASE, EPWM_TZ_SIGNAL_OSHT1); // TZ1 one-shot trip
EPWM_setTripZoneAction(EPWM1_BASE, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW);
// Enable Trip Zone interrupt
EPWM_enableTripZoneInterrupt(EPWM1_BASE, EPWM_TZ_INTERRUPT_CBC);
// Update status
pwmStatus = 0; // Initialization complete
}
// Main function
void main(void)
{
// Initialize system clock and peripherals
Device_init();
// Initialize GPIO and X-BAR
initGPIO();
// Initialize interrupt module
Interrupt_initModule();
Interrupt_initVectorTable();
// Register Trip Zone ISR
Interrupt_register(INT_EPWM1_TZ, &tripZoneISR);
// Verify system clock (debugging)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000) // Expect 200MHz
{
pwmStatus = 0xFFFF; // Error state
GPIO_writePin(31, 0); // LED OFF for error
ESTOP0; // Halt for debugging
}
// Configure Watchdog
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64); // INTOSC1 / 64
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64); // PREDIVCLK / 64
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // Reset mode
SysCtl_enableWatchdog(); // Enable Watchdog
SYSCTL_REGWRITE_DELAY; // Register write delay
// Initialize ePWM1
initEPWM();
// Check for ePWM initialization errors
if (pwmStatus != 0)
{
pwmStatus = 0xFFFF; // Initialization failed
GPIO_writePin(31, 0); // LED OFF for error
ESTOP0; // Halt for debugging
}
// Transition to running state
pwmStatus = 1; // Running
// Enable global interrupts
EINT;
// Main loop: PWM runs in hardware
for(;;)
{
// Service Watchdog
SysCtl_serviceWatchdog();
// Debug: Indicate status via LED (GPIO31)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0); // LED ON for running
// Delay 1 second (debugging, reduce CPU load)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1의 PWM_A 출력으로 100kHz, 50% 듀티 사이클 PWM 신호 생성, TZ1 트립 신호로 출력 비활성화.
- 설정: 트립 존(TZ1) 활성화, 트립 시 PWM_A LOW.
- GPIO: GPIO0(ePWM1A), GPIO12(TZ1), GPIO31(LED).
- 출력: 트립 이벤트 발생 시 PWM 출력 중단, LED OFF.
- 용도: 모터 제어 시 과전류/과열 보호.
4.8. 예제 8: Up-Down 카운터 모드 PWM
ePWM1을 Up-Down 카운터 모드로 설정하여 대칭 PWM 신호를 생성합니다.
//
// FILE: main.c
// TITLE: F2838x ePWM1 및 Trip Zone 설정 예제
// DESCRIPTION:
// 이 코드는 TI F2838x 마이크로컨트롤러에서 ePWM1을 사용하여 100kHz PWM 신호를 생성하고,
// GPIO12를 Trip Zone(TZ1) 입력으로 설정하여 PWM 출력을 제어합니다.
// Input X-BAR와 ePWM X-BAR를 통해 GPIO12를 TZ1로 라우팅하며,
// Trip Zone 인터럽트와 워치독 타이머를 설정합니다.
// GPIO31은 디버깅용 LED로 사용됩니다.
// 시스템 클럭은 200MHz로 설정되며, PWM은 Up-Down 모드로 50% 듀티 사이클을 가집니다.
// C2000Ware v6.00.00.00 기반으로 작성되었습니다.
//
// VERSION: 2025-09-07, C2000Ware_6_00_00_00
//
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
// 0: 초기화 완료, 1: PWM 정상 동작, 0xFFFF: 오류 상태(Trip Zone 발생 또는 초기화 실패)
volatile uint32_t pwmStatus = 0;
// GPIO 및 X-BAR 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A 출력으로 설정
// - pin_map.h에서 GPIO_0_EPWM1A는 0x00060001U로 정의됨
// - ePWM1A는 PWM 신호 출력 핀으로 사용
ASSERT(EPWM_isBaseValid(EPWM1_BASE)); // ePWM1 베이스 주소 유효성 검사
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT); // GPIO0을 출력으로 설정
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// GPIO12를 TZ1 입력으로 사용하기 위해 일반 입력으로 설정
// - pin_map.h에서 GPIO_12_GPIO12는 0x00061800U로 정의됨
// - GPIO_12_EPWM_TZ1은 pin_map.h에 없으므로 Input X-BAR를 통해 TZ1로 라우팅
GPIO_setPinConfig(GPIO_12_GPIO12);
GPIO_setDirectionMode(12, GPIO_DIR_MODE_IN); // GPIO12를 입력으로 설정
GPIO_setPadConfig(12, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// Input X-BAR를 통해 GPIO12를 TZ1(XBAR_INPUT1)로 라우팅
// - xbar.h에서 XBAR_INPUT1은 ePWM[TZ1]에 매핑됨
// - GPIO12(핀 번호 12)를 XBAR_INPUT1에 연결
XBAR_setInputPin(INPUTXBAR_BASE, XBAR_INPUT1, 12);
// ePWM X-BAR를 통해 XBAR_INPUT1을 TRIP4(TZ1)로 라우팅
// - xbar.h에서 XBAR_EPWM_MUX01_INPUTXBAR1(0x0201)은 XBAR_INPUT1을 TRIP4로 연결
// - XBAR_TRIP4는 ePWM1의 TZ1에 해당 (F2838x TRM, 섹션 15.10 참조)
XBAR_setEPWMMuxConfig(XBAR_TRIP4, XBAR_EPWM_MUX01_INPUTXBAR1);
XBAR_enableEPWMMux(XBAR_TRIP4, XBAR_MUX01); // MUX01 활성화
XBAR_invertEPWMSignal(XBAR_TRIP4, false); // 신호 반전 비활성화 (기본: active-low)
XBAR_lockInput(INPUTXBAR_BASE, XBAR_INPUT1); // Input X-BAR 설정 잠금 (선택적)
// GPIO31을 디버깅용 LED로 설정
// - pin_map.h에서 GPIO_31_GPIO31은 0x00081E00U로 정의됨
// - PWM 상태를 LED로 표시
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // GPIO31을 출력으로 설정
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
GPIO_writePin(31, 0); // 초기 상태: LED 꺼짐
}
// Trip Zone 인터럽트 서비스 루틴 (ISR)
__interrupt void tripZoneISR(void)
{
// TZ1 이벤트 발생 시 상태를 오류로 업데이트
pwmStatus = 0xFFFF; // 오류 상태 설정
// Trip Zone 플래그 클리어
// - EPWM_TZ_INTERRUPT_CBC: Cycle-by-Cycle Trip Zone 인터럽트 플래그
EPWM_clearTripZoneFlag(EPWM1_BASE, EPWM_TZ_INTERRUPT_CBC);
// 인터럽트 그룹 ACK
// - INTERRUPT_ACK_GROUP2: ePWM1 TZ 인터럽트 그룹
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP2);
}
// ePWM1 초기화 함수 (Up-Down 모드, Trip Zone 포함)
void initEPWM(void)
{
// ePWM1 클럭 활성화
// - SYSCTL_PERIPH_CLK_EPWM1: ePWM1 모듈 클럭 활성화
ASSERT(EPWM_isBaseValid(EPWM1_BASE)); // ePWM1 베이스 주소 유효성 검사
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM 클럭 분주기 설정 (1:1, 200MHz 그대로 사용)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// PWM 주기 설정: 100kHz (200MHz / (2 * 1000) = 100kHz, Up-Down 모드)
// - Up-Down 모드에서 주기는 TBPRD * 2 * T_SYSCLK (5ns) = 1000 * 2 * 5ns = 10µs
EPWM_setTimeBasePeriod(EPWM1_BASE, 1000);
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP_DOWN);
// 클럭 프리스케일러 설정 (1:1, SYSCLK 그대로 사용)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// PWM_A 동작 설정: CMPA에서 HIGH/LOW 전환
// - CMPA 상향 시 HIGH, 하향 시 LOW로 설정하여 대칭 PWM 생성
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);
// 듀티 사이클 50% 설정 (CMPA = 주기/2 = 1000/2 = 500)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 500);
// Trip Zone 활성화: TZ1을 One-Shot Trip으로 설정
// - EPWM_TZ_SIGNAL_OSHT1: TZ1을 원샷 트립 신호로 설정
EPWM_enableTripZoneSignals(EPWM1_BASE, EPWM_TZ_SIGNAL_OSHT1);
// TZ1 이벤트 시 PWM_A를 LOW로 설정
EPWM_setTripZoneAction(EPWM1_BASE, EPWM_TZ_ACTION_EVENT_TZA, EPWM_TZ_ACTION_LOW);
// Trip Zone 인터럽트 활성화 (Cycle-by-Cycle)
EPWM_enableTripZoneInterrupt(EPWM1_BASE, EPWM_TZ_INTERRUPT_CBC);
// 초기화 완료 상태 설정
pwmStatus = 1;
}
// 메인 함수
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
// - Device_init(): PLL 설정(200MHz), 주변 장치 리셋, 플래시 설정 등 수행
Device_init();
// GPIO 및 X-BAR 초기화
initGPIO();
// 인터럽트 모듈 및 벡터 테이블 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// Trip Zone 인터럽트 등록
// - INT_EPWM1_TZ: ePWM1 Trip Zone 인터럽트
Interrupt_register(INT_EPWM1_TZ, &tripZoneISR);
// 시스템 클럭 확인 (200MHz 예상)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000)
{
pwmStatus = 0xFFFF; // 클럭 오류 상태
GPIO_writePin(31, 0); // 오류 시 LED 꺼짐
ESTOP0; // 디버깅을 위해 정지
}
// 워치독 설정
// - 프리디바이더: INTOSC1(10MHz) / 64
// - 프리스케일러: PREDIVCLK / 64
// - 타임아웃: 약 410µs (10MHz / (64 * 64) * 100)
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64);
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64);
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 타임아웃 시 리셋
SysCtl_enableWatchdog(); // 워치독 활성화
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM1 초기화
initEPWM();
// 초기화 오류 확인
if (pwmStatus != 1)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // 오류 시 LED 꺼짐
ESTOP0; // 디버깅을 위해 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 메인 루프: PWM은 하드웨어에서 실행
for(;;)
{
// 워치독 서비스: 타임아웃 방지
SysCtl_serviceWatchdog();
// 디버깅: GPIO31 LED로 상태 표시
// - pwmStatus == 1: LED 켜짐 (정상)
// - 그 외: LED 꺼짐 (오류)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0);
// 1초 지연 (CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1의 PWM_A 출력으로 100kHz, 50% 듀티 사이클 대칭 PWM 신호 생성.
- 설정: Up-Down 카운터 모드, 주기 1000(100kHz @ 200MHz), CMPA=500.
- GPIO: GPIO0(ePWM1A), GPIO31(LED).
- 출력: 대칭 PWM 신호 출력, 정상 동작 시 LED ON.
- 용도: 모터 제어, 인버터에서 대칭 PWM 필요 시 적합.
4.9. 예제 9: 페이즈 시프트 PWM
ePWM1과 ePWM2를 동기화하되, 90도 페이즈 차이로 PWM 신호를 생성합니다.
//
// FILE: main.c
// TITLE: F2838x ePWM1 및 ePWM2 페이즈 시프트 PWM 예제
// DESCRIPTION:
// 이 코드는 TI F2838x 마이크로컨트롤러에서 ePWM1과 ePWM2를 사용하여 100kHz PWM 신호를 생성합니다.
// ePWM1은 GPIO0(ePWM1A), ePWM2는 GPIO2(ePWM2A)에 연결되며, ePWM2는 ePWM1에 대해 90도 위상 지연을 가집니다.
// GPIO31은 디버깅용 LED로 사용됩니다.
// 시스템 클럭은 200MHz로 설정되며, PWM은 Up 카운터 모드로 50% 듀티 사이클을 가집니다.
// 워치독 타이머를 설정하여 시스템 안정성을 확보합니다.
// C2000Ware v6.00.00.00 기반으로 작성되었습니다.
//
// VERSION: 2025-09-07, C2000Ware_6_00_00_00
//
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
// 0: 초기화 완료, 1: PWM 정상 동작, 0xFFFF: 오류 상태(클럭 또는 초기화 실패)
volatile uint32_t pwmStatus = 0;
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A 출력으로 설정
// - pin_map.h에서 GPIO_0_EPWM1A는 0x00060001U로 정의됨
// - ePWM1A는 PWM 신호 출력 핀으로 사용
ASSERT(EPWM_isBaseValid(EPWM1_BASE)); // ePWM1 베이스 주소 유효성 검사
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT); // GPIO0을 출력으로 설정
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// GPIO2를 ePWM2A 출력으로 설정
// - pin_map.h에서 GPIO_2_EPWM2A는 0x00060402U로 정의됨
// - ePWM2A는 90도 위상 지연 PWM 신호 출력
ASSERT(EPWM_isBaseValid(EPWM2_BASE)); // ePWM2 베이스 주소 유효성 검사
GPIO_setPinConfig(GPIO_2_EPWM2A);
GPIO_setDirectionMode(2, GPIO_DIR_MODE_OUT); // GPIO2를 출력으로 설정
GPIO_setPadConfig(2, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// GPIO31을 디버깅용 LED로 설정
// - pin_map.h에서 GPIO_31_GPIO31은 0x00081E00U로 정의됨
// - PWM 상태를 LED로 표시
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // GPIO31을 출력으로 설정
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
GPIO_writePin(31, 0); // 초기 상태: LED 꺼짐
}
// ePWM1 및 ePWM2 초기화 함수 (페이즈 시프트)
void initEPWM(void)
{
// ePWM1, ePWM2 클럭 활성화
// - SYSCTL_PERIPH_CLK_EPWM1, SYSCTL_PERIPH_CLK_EPWM2: ePWM 모듈 클럭 활성화
ASSERT(EPWM_isBaseValid(EPWM1_BASE)); // ePWM1 베이스 주소 유효성 검사
ASSERT(EPWM_isBaseValid(EPWM2_BASE)); // ePWM2 베이스 주소 유효성 검사
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM2);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM 클럭 분주기 설정 (1:1, 200MHz 그대로 사용)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM1 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz, Up 모드)
// - 주기는 TBPRD * T_SYSCLK (5ns) = 2000 * 5ns = 10µs
EPWM_setTimeBasePeriod(EPWM1_BASE, 2000);
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// 클럭 프리스케일러 설정 (1:1, SYSCLK 그대로 사용)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM2 주기 설정: ePWM1과 동일
EPWM_setTimeBasePeriod(EPWM2_BASE, 2000);
EPWM_setTimeBaseCounterMode(EPWM2_BASE, EPWM_COUNTER_MODE_UP);
// 클럭 프리스케일러 설정 (1:1, SYSCLK 그대로 사용)
EPWM_setClockPrescaler(EPWM2_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM2를 ePWM1과 동기화, 90도 페이즈 시프트 (2000 * 0.25 = 500)
// - EPWM1의 SYNC_OUT을 카운터 0에서 펄스로 설정
// - EPWM2는 EPWM1의 SYNC_OUT 신호를 입력으로 사용하여 동기화
// - 위상 지연: 500 * 5ns = 2.5µs (주기의 1/4, 90도)
EPWM_enableSyncOutPulseSource(EPWM1_BASE, EPWM_SYNC_OUT_PULSE_ON_CNTR_ZERO); // EPWM1 SYNC_OUT: 카운터 0에서 펄스
EPWM_setSyncInPulseSource(EPWM2_BASE, EPWM_SYNC_IN_PULSE_SRC_SYNCOUT_EPWM1); // EPWM2 SYNC_IN: EPWM1의 SYNC_OUT
EPWM_setPhaseShift(EPWM2_BASE, 500); // 90도 위상 지연
// ePWM1 PWM_A 동작 설정: CMPA에서 HIGH/LOW 전환
// - 카운터 0에서 HIGH, CMPA 상향 시 LOW로 설정하여 PWM 생성
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 듀티 사이클 50% 설정 (CMPA = 주기/2 = 2000/2 = 1000)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000);
// ePWM2 PWM_A 동작 설정: CMPA에서 HIGH/LOW 전환
EPWM_setActionQualifierAction(EPWM2_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM2_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 듀티 사이클 50% 설정 (CMPA = 주기/2 = 2000/2 = 1000)
EPWM_setCounterCompareValue(EPWM2_BASE, EPWM_COUNTER_COMPARE_A, 1000);
// 초기화 완료 상태 설정
pwmStatus = 1;
}
// 메인 함수
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
// - Device_init(): PLL 설정(200MHz), 주변 장치 리셋, 플래시 설정 등 수행
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 및 벡터 테이블 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// 시스템 클럭 확인 (200MHz 예상)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000)
{
pwmStatus = 0xFFFF; // 클럭 오류 상태
GPIO_writePin(31, 0); // 오류 시 LED 꺼짐
ESTOP0; // 디버깅을 위해 정지
}
// 워치독 설정
// - 프리디바이더: INTOSC1(10MHz) / 64
// - 프리스케일러: PREDIVCLK / 64
// - 타임아웃: 약 410µs (10MHz / (64 * 64) * 100)
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64);
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64);
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 타임아웃 시 리셋
SysCtl_enableWatchdog(); // 워치독 활성화
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM1, ePWM2 초기화
initEPWM();
// 초기화 오류 확인
if (pwmStatus != 1)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // 오류 시 LED 꺼짐
ESTOP0; // 디버깅을 위해 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 메인 루프: PWM은 하드웨어에서 실행
for(;;)
{
// 워치독 서비스: 타임아웃 방지
SysCtl_serviceWatchdog();
// 디버깅: GPIO31 LED로 상태 표시
// - pwmStatus == 1: LED 켜짐 (정상)
// - 그 외: LED 꺼짐 (오류)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0);
// 1초 지연 (CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1과 ePWM2를 동기화하되, 90도 페이즈 차이로 100kHz, 50% 듀티 사이클 PWM 신호 생성.
- 설정: ePWM1이 마스터, ePWM2가 90도 위상 지연 슬레이브.
- GPIO: GPIO0(ePWM1A), GPIO2(ePWM2A), GPIO31(LED).
- 출력: 페이즈 시프트 PWM 신호 출력, 정상 동작 시 LED ON.
- 용도: 다상 전력 변환, 3상 인버터 제어.
4.10. 예제 10: PWM 주파수 동적 변경
인터럽트를 사용하여 ePWM1의 PWM 주파수를 동적으로 변경합니다.
//
// FILE: main.c
// TITLE: F2838x ePWM1 주기 변경 PWM 예제
// DESCRIPTION:
// 이 코드는 TI F2838x 마이크로컨트롤러에서 ePWM1을 사용하여 PWM 주기를 100kHz, 50kHz, 25kHz로 순환 변경합니다.
// ePWM1은 GPIO0(ePWM1A)에 연결되며, 50% 듀티 사이클을 유지합니다.
// GPIO31은 디버깅용 LED로 사용됩니다.
// 시스템 클럭은 200MHz로 설정되며, PWM은 Up 카운터 모드로 동작합니다.
// 인터럽트는 카운터=0에서 발생하며, 주기를 변경합니다.
// 워치독 타이머를 설정하여 시스템 안정성을 확보합니다.
// C2000Ware v6.00.00.00 기반으로 작성되었습니다.
//
// VERSION: 2025-09-07, C2000Ware_6_00_00_00
//
#include "driverlib.h"
#include "device.h"
// 디버깅용 상태 변수
// 0: 초기화 완료, 1: PWM 정상 동작, 0xFFFF: 오류 상태(클럭 또는 초기화 실패)
volatile uint32_t pwmStatus = 0;
// 주기 저장 변수 (초기 100kHz, TBPRD=2000)
volatile uint16_t pwmPeriod = 2000;
// GPIO 초기화 함수
void initGPIO(void)
{
// GPIO0을 ePWM1A 출력으로 설정
// - pin_map.h에서 GPIO_0_EPWM1A는 0x00060001U로 정의됨
// - ePWM1A는 PWM 신호 출력 핀으로 사용
ASSERT(EPWM_isBaseValid(EPWM1_BASE)); // ePWM1 베이스 주소 유효성 검사
GPIO_setPinConfig(GPIO_0_EPWM1A);
GPIO_setDirectionMode(0, GPIO_DIR_MODE_OUT); // GPIO0을 출력으로 설정
GPIO_setPadConfig(0, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
// GPIO31을 디버깅용 LED로 설정
// - pin_map.h에서 GPIO_31_GPIO31은 0x00081E00U로 정의됨
// - PWM 상태를 LED로 표시
GPIO_setPinConfig(GPIO_31_GPIO31);
GPIO_setDirectionMode(31, GPIO_DIR_MODE_OUT); // GPIO31을 출력으로 설정
GPIO_setPadConfig(31, GPIO_PIN_TYPE_PULLUP); // 내부 풀업 저항 활성화
GPIO_writePin(31, 0); // 초기 상태: LED 꺼짐
}
// 인터럽트 서비스 루틴 (ISR)
__interrupt void epwm1ISR(void)
{
// 주기 변경: 100kHz(TBPRD=2000) → 50kHz(TBPRD=4000) → 25kHz(TBPRD=8000) 순환
if (pwmPeriod == 2000) // 100kHz
{
pwmPeriod = 4000; // 50kHz
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 2000); // 50% 듀티 유지
}
else if (pwmPeriod == 4000) // 50kHz
{
pwmPeriod = 8000; // 25kHz
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 4000); // 50% 듀티 유지
}
else // 25kHz
{
pwmPeriod = 2000; // 100kHz로 복귀
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, 1000); // 50% 듀티 유지
}
// 주기 업데이트
EPWM_setTimeBasePeriod(EPWM1_BASE, pwmPeriod);
// 인터럽트 플래그 지우기
EPWM_clearEventTriggerInterruptFlag(EPWM1_BASE);
// PIE 인터럽트 ACK
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3);
// 상태 업데이트
pwmStatus = 1;
}
// ePWM1 초기화 함수
void initEPWM(void)
{
// ePWM1 클럭 활성화
// - SYSCTL_PERIPH_CLK_EPWM1: ePWM1 모듈 클럭 활성화
ASSERT(EPWM_isBaseValid(EPWM1_BASE)); // ePWM1 베이스 주소 유효성 검사
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EPWM1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM 클럭 분주기 설정 (1:1, 200MHz 그대로 사용)
SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// 초기 주기 설정: 100kHz PWM (200MHz / 2000 = 100kHz, Up 모드)
// - 주기는 TBPRD * T_SYSCLK (5ns) = 2000 * 5ns = 10µs
EPWM_setTimeBasePeriod(EPWM1_BASE, pwmPeriod);
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
// 클럭 프리스케일러 설정 (1:1, SYSCLK 그대로 사용)
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM1 PWM_A 동작 설정: CMPA에서 HIGH/LOW 전환
// - 카운터 0에서 HIGH, CMPA 상향 시 LOW로 설정하여 PWM 생성
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_HIGH, EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO);
EPWM_setActionQualifierAction(EPWM1_BASE, EPWM_AQ_OUTPUT_A,
EPWM_AQ_OUTPUT_LOW, EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA);
// 초기 듀티 사이클 50% 설정 (CMPA = 주기/2 = 2000/2 = 1000)
EPWM_setCounterCompareValue(EPWM1_BASE, EPWM_COUNTER_COMPARE_A, pwmPeriod / 2);
// 인터럽트 설정: 카운터=0일 때 발생
EPWM_setInterruptSource(EPWM1_BASE, EPWM_INT_TBCTR_ZERO);
EPWM_enableInterrupt(EPWM1_BASE);
// 초기화 완료 상태 설정
pwmStatus = 1;
}
// 메인 함수
void main(void)
{
// 시스템 클럭 및 주변 장치 초기화
// - Device_init(): PLL 설정(200MHz), 주변 장치 리셋, 플래시 설정 등 수행
Device_init();
// GPIO 초기화
initGPIO();
// 인터럽트 모듈 및 벡터 테이블 초기화
Interrupt_initModule();
Interrupt_initVectorTable();
// ePWM1 인터럽트 ISR 등록
Interrupt_register(INT_EPWM1, &epwm1ISR);
// 시스템 클럭 확인 (200MHz 예상)
uint32_t sysClockHz = SysCtl_getClock(DEVICE_OSCSRC_FREQ);
if (sysClockHz != 200000000)
{
pwmStatus = 0xFFFF; // 클럭 오류 상태
GPIO_writePin(31, 0); // 오류 시 LED 꺼짐
ESTOP0; // 디버깅을 위해 정지
}
// 워치독 설정
// - 프리디바이더: INTOSC1(10MHz) / 64
// - 프리스케일러: PREDIVCLK / 64
// - 타임아웃: 약 410µs (10MHz / (64 * 64) * 100)
SysCtl_setWatchdogPredivider(SYSCTL_WD_PREDIV_64);
SysCtl_setWatchdogPrescaler(SYSCTL_WD_PRESCALE_64);
SysCtl_setWatchdogMode(SYSCTL_WD_MODE_RESET); // 타임아웃 시 리셋
SysCtl_enableWatchdog(); // 워치독 활성화
SYSCTL_REGWRITE_DELAY; // 레지스터 쓰기 완료 대기
// ePWM1 초기화
initEPWM();
// 초기화 오류 확인
if (pwmStatus != 1)
{
pwmStatus = 0xFFFF; // 초기화 실패
GPIO_writePin(31, 0); // 오류 시 LED 꺼짐
ESTOP0; // 디버깅을 위해 정지
}
// 글로벌 인터럽트 활성화
EINT;
// 메인 루프: PWM은 하드웨어에서 실행
for(;;)
{
// 워치독 서비스: 타임아웃 방지
SysCtl_serviceWatchdog();
// 디버깅: GPIO31 LED로 상태 표시
// - pwmStatus == 1: LED 켜짐 (정상)
// - 그 외: LED 꺼짐 (오류)
GPIO_writePin(31, (pwmStatus == 1) ? 1 : 0);
// 1초 지연 (CPU 부하 감소)
DEVICE_DELAY_US(1000000);
}
}
설명:
- 기능: ePWM1의 PWM_A 출력으로 100kHz, 50kHz, 25kHz 주파수를 순환하며 PWM 신호 생성.
- 설정: 인터럽트로 TBPRD 업데이트, 50% 듀티 유지.
- GPIO: GPIO0(ePWM1A), GPIO31(LED).
- 출력: 주파수 변화 PWM 신호 출력, 정상 동작 시 LED ON.
- 용도: 가변 주파수 드라이브, 조명 제어.
5. 추가 고려 사항
- 주기와 듀티 계산: PWM 주기는
TBPRD = (SYSCLK / (PWM_FREQ * CLKDIV))
로 계산. Up-Down 모드에서는 TBPRD * 2. 예: 200MHz 클럭, 100kHz PWM → TBPRD=2000(Up), 1000(Up-Down). - HRPWM: 고해상도 PWM은 나노초 단위 정밀 제어를 제공. 보정 필요 시
HRPWM_calibrateMEP
호출. - 데드밴드: 모터 제어 시 스위칭 충돌 방지를 위해 필수.
- GPIO 설정:
initGPIO()
함수로 ePWM 관련 핀 설정을 분리하여 코드 가독성과 유지보수성 향상. - C2000Ware: 예제 코드는 C2000Ware의 DriverLib 기반.
C:\ti\c2000
에 설치. - 디버깅: Code Composer Studio의 .syscfg 툴로 ePWM 및 GPIO 설정 시각적 구성 가능.
키워드: TMS320F28388D, ePWM, DriverLib, C2000, PWM, 마이크로컨트롤러, Code Composer Studio, ADC 트리거, 데드밴드, 상보 PWM, HRPWM, 트립 존, 동기화, 페이즈 시프트, Up-Down 카운터
'MCU > C2000' 카테고리의 다른 글
TMS320F28388D DSP CLA 사용법: DriverLib API로 CLA 설정 및 코드(수정) (0) | 2025.08.17 |
---|---|
TMS320F28388D DSP EMIF 사용법: DriverLib API로 EMIF 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP eQEP 사용법: DriverLib API로 eQEP 설정 및 코드(수정) (0) | 2025.08.17 |
TMS320F28388D DSP eCAP 사용법: DriverLib API로 eCAP 설정 및 코드(수정) (3) | 2025.08.17 |
TMS320F28388D DSP ADC 사용법: DriverLib API로 ADC 설정 및 코드(수정) (0) | 2025.08.08 |
TMS320F28388D DSP CPU 타이머 사용법 : Driverlib API로 CPU 타이머 설정과 예제(수정본) (0) | 2025.08.08 |
TMS320F28388D DSP SCI 사용법: Driverlib API로 UART 설정 및 예제(수정본) (0) | 2025.08.08 |
TMS320F28388D DSP Driverlib 기반 프로젝트 설정 및 기본 프로그램 작성 절차 (0) | 2025.08.08 |