소개
TMS320F28377D는 Texas Instruments의 C2000 Delfino 시리즈 마이크로컨트롤러로, 고성능 ADC(아날로그-디지털 변환기)를 통해 실시간 제어 애플리케이션에 최적화된 성능을 제공합니다. ADC의 트리거 모드는 아날로그 신호 샘플링을 효율적으로 제어하는 핵심 기능입니다. 이 글에서는 소프트웨어 트리거, ePWM 트리거, CPU 타이머 트리거, GPIO 트리거, 버스트 모드를 상세히 설명하고, F28x_Project.h
를 사용한 비트 필드 레지스터 조작 예제 코드를 제공합니다. 전력 변환기, 모터 제어, 센서 인터페이스 등 다양한 프로젝트에 바로 적용할 수 있는 실용적인 가이드를 목표로 합니다.
TMS320F28377D ADC 개요
TMS320F28377D는 4개의 12비트/16비트 ADC 모듈(ADCA, ADCB, ADCC, ADCD)을 포함하며, 각 모듈은 최대 16개 채널을 지원합니다. ADC는 단일 엔드 또는 차동 모드로 동작하며, SOC(Start of Conversion)를 통해 특정 채널을 트리거로 샘플링합니다. 트리거 모드는 ADC 변환을 시작하는 신호를 정의하며, 소프트웨어, 하드웨어(ePWM, 타이머, GPIO), 내부 이벤트 등 다양한 소스를 지원합니다. 이 가이드에서는 각 트리거 모드의 동작 원리와 설정 방법을 설명합니다.
ADC 트리거 모드별 설명
1. 소프트웨어 트리거
- 설명: CPU가
ADCSOCFRC1
레지스터를 직접 설정하여 ADC 변환을 시작합니다. - 장점: 간단하고 디버깅에 적합.
- 사용 사례: 단일 샘플링, 비주기적 변환.
- 설정:
ADCSOCFRC1.bit.SOCx = 1
로 SOC 강제 트리거.
2. ePWM 트리거
- 설명: ePWM 모듈의 SOCA/SOCB 이벤트를 사용하여 주기적으로 ADC 변환을 트리거합니다.
- 장점: 정밀한 타이밍, CPU 부하 감소.
- 사용 사례: 전력 변환기, 모터 제어.
- 설정:
ADCSOCxCTL.bit.TRIGSEL
에 ePWM 이벤트 지정(예:TRIGSEL=5
).
3. CPU 타이머 트리거
- 설명: CPU 타이머(0, 1, 2)를 사용하여 주기적 트리거 생성.
- 장점: ePWM과 독립적인 주기적 샘플링.
- 사용 사례: 주기적 데이터 수집.
- 설정:
ADCSOCxCTL.bit.TRIGSEL=1
로 타이머 0 선택.
4. GPIO 트리거
- 설명: GPIO 핀의 상승/하락 에지를 Input X-BAR를 통해 ADC 트리거로 사용.
- 장점: 외부 이벤트 기반 샘플링.
- 사용 사례: 센서 신호의 제로 크로싱 감지.
- 설정:
InputXbarRegs.INPUTxSELECT
와ADCXBARSEL
설정.
5. 버스트 모드
- 설명: 단일 트리거로 다중 SOC(예: SOC0~SOC3)를 순차적으로 샘플링.
- 장점: 다중 채널 고속 샘플링.
- 사용 사례: 복잡한 신호 분석.
- 설정:
ADCBURSTCTL
로 버스트 크기와 트리거 소스 지정.
예제 코드
1. 소프트웨어 트리거 예제
// File: adc_simple.c
// Description: TMS320F28377D ADCINA0 채널 소프트웨어 트리거 예제 (Bitfield 구조)
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28377D
// C2000Ware Version: 6.0.0.0
#include "F28x_Project.h"
// ADC 인터럽트 핸들러 선언
interrupt void adc_isr(void);
// ADC 결과 저장용 전역 변수
volatile Uint16 adcResult = 0; // SOC0 결과 (ADCINA0)
// ADC 초기화 함수
void InitAdc(void) {
EALLOW; // 보호된 레지스터 접근 허용
CpuSysRegs.PCLKCR13.bit.ADC_A = 1; // ADCA 모듈 클럭 활성화
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 코어 전원 켜기
AdcaRegs.ADCCTL2.bit.PRESCALE = 0; // ADC 클럭 = SYSCLK/4 (50MHz at 200MHz SYSCLK)
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); // 12비트, 단일 입력 모드
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // SOC0의 EOC에서 ADCINT1 인터럽트 발생
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // ADCINT1 인터럽트 활성화
AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 1; // 연속 인터럽트 모드 활성화
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 초기화
EDIS;
DELAY_US(1000); // ADC 안정화를 위한 1ms 대기
}
// ADC SOC 설정 함수
void InitAdcSoc(void) {
EALLOW; // 보호된 레지스터 접근 허용
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // SOC0에 ADCINA0 채널 선택
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // 샘플링 윈도우 15 SYSCLK (75ns at 200MHz)
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 0; // 소프트웨어 트리거 선택 (TRIGSEL=0)
EDIS;
}
// 메인 함수
void main(void) {
// 시스템 초기화
InitSysCtrl(); // 시스템 클럭 및 PLL 초기화
InitGpio(); // GPIO 초기화
Device_cal(); // ADC 캘리브레이션 호출 (오프셋 보정)
DINT; // 전역 인터럽트 비활성화
InitPieCtrl(); // PIE 제어 레지스터 초기화
IER = 0x0000; // 인터럽트 마스크 레지스터 초기화
IFR = 0x0000; // 인터럽트 플래그 레지스터 클리어
InitPieVectTable(); // PIE 벡터 테이블 초기화
// ADC 인터럽트 벡터 등록
EALLOW;
PieVectTable.ADCA1_INT = &adc_isr; // ADCINT1 인터럽트 핸들러 등록
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // PIE 그룹 1, ADCINT1 활성화
IER |= M_INT1; // CPU 인터럽트 1 활성화
EDIS;
// ADC 및 SOC 초기화
InitAdc(); // ADC 초기화
InitAdcSoc(); // ADC SOC 설정
// 글로벌 인터럽트 및 실시간 디버깅 활성화
EINT; // 글로벌 인터럽트 활성화
ERTM; // 실시간 디버깅 모드 활성화
// 무한 루프: 소프트웨어 트리거로 반복 변환
for(;;) {
EALLOW;
AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1; // SOC0 변환 강제 시작
EDIS;
DELAY_US(1000); // 1ms 대기 후 다음 변환
}
}
// ADC 인터럽트 서비스 루틴
interrupt void adc_isr(void) {
adcResult = AdcaResultRegs.ADCRESULT0; // SOC0 변환 결과 읽기
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
2. ePWM 트리거 예제 (100kHz)
// File: adc_epwm_trigger.c
// Description: TMS320F28377D ADCINA0 채널 ePWM1 SOCA 트리거 예제 (Bitfield 구조)
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28377D
// C2000Ware Version: 6.0.0.0
#include "F28x_Project.h"
// ADC 인터럽트 핸들러 선언
interrupt void adc_isr(void);
// ADC 결과 저장용 전역 변수
volatile Uint16 adcResult = 0; // SOC0 결과 (ADCINA0)
// ADC 초기화 함수
void InitAdc(void) {
EALLOW; // 보호된 레지스터 접근 허용
CpuSysRegs.PCLKCR13.bit.ADC_A = 1; // ADCA 모듈 클럭 활성화
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 코어 전원 켜기
AdcaRegs.ADCCTL2.bit.PRESCALE = 0; // ADC 클럭 = SYSCLK/4 (50MHz at 200MHz SYSCLK)
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); // 12비트, 단일 입력 모드
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // SOC0의 EOC에서 ADCINT1 발생
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // ADCINT1 인터럽트 활성화
AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 1; // 연속 인터럽트 모드 활성화
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 초기화
EDIS;
DELAY_US(1000); // ADC 안정화를 위한 1ms 대기
}
// ADC SOC 설정 함수
void InitAdcSoc(void) {
EALLOW; // 보호된 레지스터 접근 허용
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // SOC0에 ADCINA0 채널 선택
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // 샘플링 윈도우 15 SYSCLK (75ns at 200MHz)
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // ePWM1 SOCA 트리거 선택 (TRIGSEL=5)
EDIS;
}
// ePWM 초기화 함수 (100kHz 주기)
void InitEPwm(void) {
EALLOW; // 보호된 레지스터 접근 허용
CpuSysRegs.PCLKCR2.bit.EPWM1 = 1; // ePWM1 모듈 클럭 활성화
EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UPDOWN; // 업-다운 카운트 모드
EPwm1Regs.TBPRD = 1000; // 주기 = 1000 TBCLK (100kHz, 200MHz/1000/2)
EPwm1Regs.TBCTL.bit.PHSEN = 0; // 페이즈 동기화 비활성화
EPwm1Regs.TBCTL.bit.PRDLD = TB_SHADOW; // 주기 레지스터 섀도우 모드
EPwm1Regs.TBCTL.bit.SYNCOSEL = TB_SYNC_DISABLE; // 동기화 출력 비활성화
EPwm1Regs.TBCTL.bit.HSPCLKDIV = 0; // TBCLK = SYSCLK (200MHz)
EPwm1Regs.TBCTL.bit.CLKDIV = 0; // TBCLK 분주 비율 1
EPwm1Regs.ETSEL.bit.SOCASEL = ET_CTR_ZERO; // TBCTR=0일 때 SOCA 발생
EPwm1Regs.ETSEL.bit.SOCAEN = 1; // SOCA 트리거 활성화
EPwm1Regs.ETPS.bit.SOCAPRD = 1; // 매 주기마다 SOCA 발생
EPwm1Regs.TBCTR = 0; // 타이머 카운터 초기화
EPwm1Regs.TBCTL.bit.FREE_SOFT = 2; // 자유 실행 모드
EDIS;
}
// 메인 함수
void main(void) {
// 시스템 초기화
InitSysCtrl(); // 시스템 클럭 및 PLL 초기화
InitGpio(); // GPIO 초기화
InitEPwm1Gpio(); // ePWM1 GPIO 초기화 (GPIO0/1을 ePWM1A/1B로 설정)
Device_cal(); // ADC 캘리브레이션 호출 (오프셋 보정)
DINT; // 전역 인터럽트 비활성화
InitPieCtrl(); // PIE 제어 레지스터 초기화
IER = 0x0000; // 인터럽트 마스크 초기화
IFR = 0x0000; // 인터럽트 플래그 클리어
InitPieVectTable(); // PIE 벡터 테이블 초기화
// ADC 인터럽트 벡터 등록
EALLOW;
PieVectTable.ADCA1_INT = &adc_isr; // ADCINT1 인터럽트 핸들러 등록
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // PIE 그룹 1, ADCINT1 활성화
IER |= M_INT1; // CPU 인터럽트 1 활성화
EDIS;
// ADC 및 ePWM 초기화
InitAdc(); // ADC 초기화
InitAdcSoc(); // ADC SOC 설정
InitEPwm(); // ePWM 초기화
// 글로벌 인터럽트 및 실시간 디버깅 활성화
EINT; // 글로벌 인터럽트 활성화
ERTM; // 실시간 디버깅 모드 활성화
// 무한 루프: ePWM1이 ADC 변환 트리거
for(;;) {
// ePWM1이 자동으로 SOC0 변환 트리거, ISR에서 처리
}
}
// ADC 인터럽트 서비스 루틴
interrupt void adc_isr(void) {
adcResult = AdcaResultRegs.ADCRESULT0; // SOC0 변환 결과 읽기
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
3. CPU 타이머 트리거 예제 (1ms)
// File: adc_cputimer_trigger.c
// Description: TMS320F28377D ADCINA0 채널 CPU 타이머 0 트리거 예제 (Bitfield 구조)
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28377D
// C2000Ware Version: 6.0.0.0
#include "F28x_Project.h"
// 인터럽트 핸들러 선언
interrupt void adc_isr(void);
interrupt void cputimer0_isr(void);
// ADC 결과 저장용 전역 변수
volatile Uint16 adcResult = 0; // SOC0 결과 (ADCINA0)
volatile Uint16 timerFlag = 0; // CPU 타이머 완료 플래그
// ADC 초기화 함수
void InitAdc(void) {
EALLOW; // 보호된 레지스터 접근 허용
CpuSysRegs.PCLKCR13.bit.ADC_A = 1; // ADCA 모듈 클럭 활성화
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 코어 전원 켜기
AdcaRegs.ADCCTL2.bit.PRESCALE = 0; // ADC 클럭 = SYSCLK/4 (50MHz at 200MHz SYSCLK)
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); // 12비트, 단일 입력 모드
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // SOC0의 EOC에서 ADCINT1 발생
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // ADCINT1 인터럽트 활성화
AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 1; // 연속 인터럽트 모드 활성화
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 초기화
EDIS;
DELAY_US(1000); // ADC 안정화를 위한 1ms 대기
}
// ADC SOC 설정 함수
void InitAdcSoc(void) {
EALLOW; // 보호된 레지스터 접근 허용
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // SOC0에 ADCINA0 채널 선택
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // 샘플링 윈도우 15 SYSCLK (75ns at 200MHz)
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 1; // CPU 타이머 0 트리거 선택 (TRIGSEL=1)
EDIS;
}
// CPU 타이머 초기화 함수 (1ms 주기)
void InitCpuTimer(void) {
EALLOW; // 보호된 레지스터 접근 허용
CpuSysRegs.PCLKCR0.bit.CPUTIMER0 = 1; // CPU 타이머 0 클럭 활성화
CpuTimer0Regs.TCR.bit.TSS = 1; // 타이머 정지 (설정 중)
CpuTimer0Regs.PRD.all = 200000; // 주기 = 200,000 SYSCLK (1ms at 200MHz)
CpuTimer0Regs.TPR.bit.TDDR = 0; // 분주 비율 1 (TDDR=0)
CpuTimer0Regs.TPRH.bit.TDDRH = 0; // 분주 비율 상위 비트 0
CpuTimer0Regs.TCR.bit.TRB = 1; // 주기 레지스터 재로드
CpuTimer0Regs.TCR.bit.TIE = 1; // 타이머 인터럽트 활성화
CpuTimer0Regs.TCR.bit.TSS = 0; // 타이머 시작
EDIS;
}
// 메인 함수
void main(void) {
// 시스템 초기화
InitSysCtrl(); // 시스템 클럭 및 PLL 초기화
InitGpio(); // GPIO 초기화
Device_cal(); // ADC 캘리브레이션 호출 (오프셋 보정)
DINT; // 전역 인터럽트 비활성화
InitPieCtrl(); // PIE 제어 레지스터 초기화
IER = 0x0000; // 인터럽트 마스크 초기화
IFR = 0x0000; // 인터럽트 플래그 클리어
InitPieVectTable(); // PIE 벡터 테이블 초기화
// 인터럽트 벡터 등록
EALLOW;
PieVectTable.ADCA1_INT = &adc_isr; // ADCINT1 인터럽트 핸들러 등록
PieVectTable.TIMER0_INT = &cputimer0_isr; // CPU 타이머 0 인터럽트 핸들러 등록
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // PIE 그룹 1, ADCINT1 활성화
PieCtrlRegs.PIEIER1.bit.INTx7 = 1; // PIE 그룹 1, TIMER0_INT 활성화
IER |= M_INT1; // CPU 인터럽트 1 활성화
EDIS;
// ADC 및 CPU 타이머 초기화
InitAdc(); // ADC 초기화
InitAdcSoc(); // ADC SOC 설정
InitCpuTimer(); // CPU 타이머 초기화
// 글로벌 인터럽트 및 실시간 디버깅 활성화
EINT; // 글로벌 인터럽트 활성화
ERTM; // 실시간 디버깅 모드 활성화
// 무한 루프: CPU 타이머가 ADC 변환 트리거
for(;;) {
// CPU 타이머가 자동으로 SOC0 변환 트리거, ISR에서 처리
}
}
// ADC 인터럽트 서비스 루틴
interrupt void adc_isr(void) {
adcResult = AdcaResultRegs.ADCRESULT0; // SOC0 변환 결과 읽기
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
// CPU 타이머 0 인터럽트 서비스 루틴
interrupt void cputimer0_isr(void) {
timerFlag = 1; // 타이머 완료 플래그 설정
CpuTimer0Regs.TCR.bit.TIF = 1; // 타이머 인터럽트 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
4. GPIO 트리거 예제
// File: adc_xbar_xint_trigger.c
// Description: TMS320F28377D ADCINA0 채널 Input X-BAR(GPIO0, XINT1) 트리거 예제 (Bitfield 구조)
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28377D
// C2000Ware Version: 6.0.0.0
#include "F28x_Project.h"
// 인터럽트 핸들러 선언
interrupt void adc_isr(void);
interrupt void xint1_isr(void);
// 전역 변수
volatile Uint16 adcResult = 0; // SOC0 결과 (ADCINA0)
volatile Uint16 xintFlag = 0; // XINT1 트리거 플래그
// ADC 초기화 함수
void InitAdc(void) {
EALLOW; // 보호된 레지스터 접근 허용
CpuSysRegs.PCLKCR13.bit.ADC_A = 1; // ADCA 모듈 클럭 활성화
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 코어 전원 켜기
AdcaRegs.ADCCTL2.bit.PRESCALE = 0; // ADC 클럭 = SYSCLK/4 (50MHz at 200MHz SYSCLK)
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); // 12비트, 단일 입력 모드
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // SOC0의 EOC에서 ADCINT1 발생
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // ADCINT1 인터럽트 활성화
AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 1; // 연속 인터럽트 모드 활성화
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 초기화
EDIS;
DELAY_US(1000); // ADC 안정화를 위한 1ms 대기
}
// ADC SOC 설정 함수
void InitAdcSoc(void) {
EALLOW; // 보호된 레지스터 접근 허용
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // SOC0에 ADCINA0 채널 선택
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // 샘플링 윈도우 15 SYSCLK (75ns at 200MHz)
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // Input X-BAR 트리거 선택 (TRIGSEL=5)
EDIS;
}
// GPIO 및 Input X-BAR 초기화 함수
void InitInputXbar(void) {
EALLOW; // 보호된 레지스터 접근 허용
GpioCtrlRegs.GPAMUX1.bit.GPIO0 = 0; // GPIO0을 GPIO 기능으로 설정
GpioCtrlRegs.GPADIR.bit.GPIO0 = 0; // GPIO0을 입력 방향으로 설정
GpioCtrlRegs.GPAQSEL1.bit.GPIO0 = 0; // GPIO0 입력 동기화 (SYSCLK 동기)
InputXbarRegs.INPUT4SELECT = 0; // GPIO0을 Input X-BAR INPUT4에 연결
XintRegs.XINT1CR.bit.POLARITY = 0; // XINT1 상승 에지 트리거
XintRegs.XINT1CR.bit.ENABLE = 1; // XINT1 인터럽트 활성화
EDIS;
}
// 메인 함수
void main(void) {
// 시스템 초기화
InitSysCtrl(); // 시스템 클럭 및 PLL 초기화 (InitPeripheralClocks 포함)
InitGpio(); // GPIO 초기화 (C2000Ware 기본 함수)
Device_cal(); // ADC 캘리브레이션 호출 (오프셋 보정)
DINT; // 전역 인터럽트 비활성화
InitPieCtrl(); // PIE 제어 레지스터 초기화
IER = 0x0000; // 인터럽트 마스크 초기화
IFR = 0x0000; // 인터럽트 플래그 클리어
InitPieVectTable(); // PIE 벡터 테이블 초기화
// 인터럽트 벡터 등록
EALLOW;
PieVectTable.ADCA1_INT = &adc_isr; // ADCINT1 인터럽트 핸들러 등록
PieVectTable.XINT1_INT = &xint1_isr; // XINT1 인터럽트 핸들러 등록
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // PIE 그룹 1, ADCINT1 활성화
PieCtrlRegs.PIEIER1.bit.INTx4 = 1; // PIE 그룹 1, XINT1 활성화
IER |= M_INT1; // CPU 인터럽트 1 활성화
EDIS;
// ADC 및 Input X-BAR 초기화
InitAdc(); // ADC 초기화
InitAdcSoc(); // ADC SOC 설정
InitInputXbar(); // GPIO 및 Input X-BAR 초기화
// 글로벌 인터럽트 및 실시간 디버깅 활성화
EINT; // 글로벌 인터럽트 활성화
ERTM; // 실시간 디버깅 모드 활성화
// 무한 루프: Input X-BAR가 ADC 변환 트리거
for(;;) {
// GPIO0을 통한 Input X-BAR가 SOC0 변환 트리거, ISR에서 처리
}
}
// ADC 인터럽트 서비스 루틴
interrupt void adc_isr(void) {
adcResult = AdcaResultRegs.ADCRESULT0; // SOC0 변환 결과 읽기
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
// XINT1 인터럽트 서비스 루틴
interrupt void xint1_isr(void) {
xintFlag = 1; // XINT1 트리거 플래그 설정
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
}
5. 버스트 모드 예제
// File: adc_burst_trigger.c
// Description: TMS320F28377D ADCINA0~ADCINA3 채널 소프트웨어 트리거 예제 (버스트 모드, 인터럽트 기반)
// Compiler: Code Composer Studio (TI C2000 Compiler)
// Target: TMS320F28377D
// C2000Ware Version: 6.0.0.0
#include "F28x_Project.h"
// 인터럽트 핸들러 선언
interrupt void adc_isr(void);
// 전역 변수
volatile Uint16 adcResults[4] = {0, 0, 0, 0}; // SOC0~SOC3 결과 (ADCINA0~ADCINA3)
volatile Uint16 burstComplete = 0; // 버스트 완료 플래그
// ADC 초기화 함수
void InitAdc(void) {
EALLOW; // 보호된 레지스터 접근 허용
CpuSysRegs.PCLKCR13.bit.ADC_A = 1; // ADCA 모듈 클럭 활성화
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // ADC 코어 전원 켜기
AdcaRegs.ADCCTL1.bit.INTPULSEPOS = 1; // 인터럽트 펄스 위치를 EOC 직후로 설정
AdcaRegs.ADCCTL2.bit.PRESCALE = 0; // ADC 클럭 = SYSCLK/4 (50MHz at 200MHz SYSCLK)
AdcSetMode(ADC_ADCA, ADC_RESOLUTION_12BIT, ADC_SIGNALMODE_SINGLE); // 12비트, 단일 입력 모드
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 3; // SOC3의 EOC에서 ADCINT1 발생
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // ADCINT1 인터럽트 활성화
AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 1; // 연속 인터럽트 모드 활성화
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 초기화
AdcaRegs.ADCBURSTCTL.bit.BURSTEN = 1; // 버스트 모드 활성화
AdcaRegs.ADCBURSTCTL.bit.BURSTSIZE = 3; // SOC0~SOC3 (4개 SOC) 샘플링
AdcaRegs.ADCBURSTCTL.bit.BURSTTRIGSEL = 0; // 소프트웨어 트리거 선택
EDIS;
DELAY_US(1000); // ADC 안정화를 위한 1ms 대기
}
// ADC SOC 설정 함수
void InitAdcSoc(void) {
EALLOW; // 보호된 레지스터 접근 허용
// SOC0: ADCINA0 채널
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADCINA0 선택
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // 샘플링 윈도우 15 SYSCLK (75ns)
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 0; // 트리거 무시 (버스트 모드)
// SOC1: ADCINA1 채널
AdcaRegs.ADCSOC1CTL.bit.CHSEL = 1; // ADCINA1 선택
AdcaRegs.ADCSOC1CTL.bit.ACQPS = 14; // 샘플링 윈도우
AdcaRegs.ADCSOC1CTL.bit.TRIGSEL = 0;
// SOC2: ADCINA2 채널
AdcaRegs.ADCSOC2CTL.bit.CHSEL = 2; // ADCINA2 선택
AdcaRegs.ADCSOC2CTL.bit.ACQPS = 14; // 샘플링 윈도우
AdcaRegs.ADCSOC2CTL.bit.TRIGSEL = 0;
// SOC3: ADCINA3 채널
AdcaRegs.ADCSOC3CTL.bit.CHSEL = 3; // ADCINA3 선택
AdcaRegs.ADCSOC3CTL.bit.ACQPS = 14; // 샘플링 윈도우
AdcaRegs.ADCSOC3CTL.bit.TRIGSEL = 0;
EDIS;
}
// 메인 함수
void main(void) {
// 시스템 초기화
InitSysCtrl(); // 시스템 클럭 및 주변 장치 초기화 (InitPeripheralClocks 포함)
InitGpio(); // GPIO 초기화 (C2000Ware 기본 함수)
Device_cal(); // ADC 캘리브레이션 호출 (오프셋 보정)
DINT; // 전역 인터럽트 비활성화
InitPieCtrl(); // PIE 제어 레지스터 초기화
IER = 0x0000; // 인터럽트 마스크 초기화
IFR = 0x0000; // 인터럽트 플래그 클리어
InitPieVectTable(); // PIE 벡터 테이블 초기화
// 인터럽트 벡터 등록
EALLOW;
PieVectTable.ADCA1_INT = &adc_isr; // ADCINT1 인터럽트 핸들러 등록
PieCtrlRegs.PIEIER1.bit.INTx1 = 1; // PIE 그룹 1, ADCINT1 활성화
IER |= M_INT1; // CPU 인터럽트 1 활성화
EDIS;
// ADC 초기화
InitAdc(); // ADC 초기화
InitAdcSoc(); // ADC SOC 설정
// 글로벌 인터럽트 및 실시간 디버깅 활성화
EINT; // 글로벌 인터럽트 활성화
ERTM; // 실시간 디버깅 모드 활성화
// 무한 루프: 소프트웨어 트리거로 ADC 변환 시작
for(;;) {
EALLOW;
AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1; // SOC0 변환 강제 시작 (버스트 모드 트리거)
EDIS;
DELAY_US(1000); // 1ms 대기 후 다음 버스트
}
}
// ADC 인터럽트 서비스 루틴
interrupt void adc_isr(void) {
adcResults[0] = AdcaResultRegs.ADCRESULT0; // SOC0 결과 (ADCINA0)
adcResults[1] = AdcaResultRegs.ADCRESULT1; // SOC1 결과 (ADCINA1)
adcResults[2] = AdcaResultRegs.ADCRESULT2; // SOC2 결과 (ADCINA2)
adcResults[3] = AdcaResultRegs.ADCRESULT3; // SOC3 결과 (ADCINA3)
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // ADCINT1 플래그 클리어
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1; // PIE 그룹 1 ACK
burstComplete = 1; // 버스트 완료 플래그 설정
}
주의사항 및 디버깅 팁
- 타이밍 문제:
- 트리거 간격이 너무 짧으면
ADCSOCOVF1
오버플로우 발생. RRPOINTER 리셋 또는 고우선순위 SOC 사용.
- 트리거 간격이 너무 짧으면
- 첫 번째 샘플 오류:
- ADCINA0의 첫 샘플이 부정확할 수 있음. 초기 변환 무시 또는 다른 채널 사용.
- 인터럽트 관리:
ADCINTFLGCLR
로 플래그 클리어 필수. 미클리어 시 코드 멈춤.
- GPIO 트리거:
- Input X-BAR 설정 확인, 외부 신호 안정성 점검.
- 디버깅:
- Code Composer Studio에서
adcResult
관찰. - 오실로스코프로 트리거 신호 확인.
- Code Composer Studio에서
결론
TMS320F28377D의 ADC 트리거 모드는 소프트웨어, ePWM, CPU 타이머, GPIO, 버스트 모드를 통해 다양한 애플리케이션에 유연성을 제공합니다. 전력 변환기, 모터 제어, 센서 인터페이스 등에서 최적의 샘플링을 구현해보세요
'MCU > C2000' 카테고리의 다른 글
TMS320F28335 DSP SCI 사용법: Bitfield 구조 활용 (0) | 2025.08.07 |
---|---|
TMS320F28335 DSP 사양 및 CCS 프로젝트 생성 절차 (0) | 2025.08.06 |
TI C2000 Lockstep 완벽 정리: 기능 안전을 위한 필수 기술 (0) | 2025.08.06 |
TMS320F28377D DSP SCI 사용법: Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |
TMS320F28377D DSP ADC 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |
TMS320F28377D DSP CPU 타이머 사용법 :Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |
TMS320F28377D DSP CCS 프로젝트 설정 및 기본 프로그램 (0) | 2025.08.06 |
TMS320F28377D DSP GPIO 사용법 : Bitfield 구조 활용 예제 코드(수정) (0) | 2025.08.06 |