기술자료
[E2E 스레드] 10채널 ADC 변환 인터럽트가 트리거 후 0.42us 만에 떴다? — F2800157 타이밍 계측 사례와 tEOC·tLAT 4사이클 정리
TI E2E 포럼의 TMS320F2800157 사례를 정리합니다. 10채널 ADC를 연속 변환했는데 ADC 인터럽트가 이론보다 약 6us 빨리 들어온다는 질문(스레드 #1683129)과, 이 스레드에서 확인된 ADC 파이프라인 타이밍(tEOC, tLAT) 내용입니다.
이 스레드는 2026년 10월 7일 현재 진행 중이며 일부 현상은 아직 해결되지 않았습니다. 확인된 내용과 아직 확인되지 않은 내용을 구분해서 적었습니다.
1. 포럼 질문자의 구성과 계산
모터 제어나 전력 변환기에서는 3상 전류, DC 링크 전압, 온도 센서처럼 아날로그 신호 8~10개를 한 번에 측정하는 경우가 많습니다. 질문자의 구성은 다음과 같습니다.
- 디바이스: TMS320F2800157
- SYSCLK 120MHz, ADCCLK 20MHz (분주 6)
- ePWM: Up-Down 카운트, TBPRD = 6000 (주기 100us), CMPC = 5990 다운카운트 시 SOCA 트리거
- ADC: SOC0~SOC9 전부 같은 SOCA 트리거, ACQPS = 14
- 인터럽트: ADCINT1 = SOC9 변환 완료, 펄스 모드 ADC_PULSE_END_OF_CONV
질문자가 계산한 예상 타이밍입니다.
- 샘플앤홀드 윈도우: (ACQPS + 1) × 8.33ns = 125ns (15 SYSCLK)
- 데이터시트의 tEOC: 61 SYSCLK (약 508.3ns)
- SOC 하나당 시작-시작 간격: 125ns + 508.3ns ≈ 633ns (76 SYSCLK)
- 10개 SOC 총 소요: 약 6.35us
TI 답변도 2 + 10 × (15 + 61) = 762 SYSCLK ≈ 6.35us로 이 계산이 맞다고 확인했습니다.
2. 계측 방법과 이상한 결과
질문자는 오실로스코프로 다음과 같이 측정했습니다.
- ePWM ISR(TBCTR = 0)에서 GPIO25를 High
- ADC ISR(SOC9 변환 완료)에서 GPIO25를 Low
TBCTR = 0에서 다운카운트 5990까지는 6000 + 10 = 6010 TBCLK, 즉 50.08us입니다. 따라서 GPIO25 High 폭은 50.08us + 6.35us = 56.43us가 되어야 합니다. 그런데 실측은 50.5us였습니다.

여기서 0.42us는 펄스 폭이 아닙니다. SOCA 트리거(50.08us 지점)부터 ADC ISR이 GPIO를 내리기까지의 지연입니다. 10개 변환에 필요한 6.35us 중 약 6us가 사라진 것처럼 보였습니다.
3. 원인 추적: TI의 1차 가설과 시험 결과
TI의 1차 답변 요지입니다.
10개 SOC의 요청 플래그는 트리거 순간 동시에 세트되지만, 변환은 라운드로빈 중재기가 한 번에 하나씩 처리합니다. 6.35us 계산은 맞습니다. 다만 ADC 인터럽트 플래그를 지우지 않으면 이전 주기의 대기 중인 인터럽트가 새 주기의 트리거 직후에 발생할 수 있으며, 이것이 유력한 원인(probable cause)입니다. 인터럽트를 enable하기 전과 ISR을 종료하기 전에 대기 중인 INT, OVF 플래그를 모두 지우십시오.
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1); ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
질문자는 ADC ISR에 ADC_clearInterruptOverflowStatus()를 추가했지만 "개선도 변화도 없었다"고 보고했습니다. 즉 이 방법만으로는 현상이 해결되지 않았습니다. 플래그 정리는 여전히 좋은 습관이지만, 이 사례의 직접 원인으로 확인된 것은 아닙니다.
4. 질문자가 보고한 원인 후보: ADC_setSOCPriority()
스레드가 이어진 뒤 질문자는 다음과 같이 보고했습니다.
- 초기화 코드에서 ADC_PRI_ALL_HIPRI를 지정했는데 ADCSOCPRICTL이 계속 0으로 읽혔고, 지정한 값이 ADCINTSEL3N4 레지스터에 나타났다.
- 사용한 C2000Ware는 5.00.00.00이며, ADC_setSOCPriority()가 ADCSOCPRICTL에 HWREGH 대신 HWREG로 쓰고 있었다고 판단했다.
- HWREGH로 고치자 "ADC 변환 타이밍이 기대대로 나온다"고 보고했다.
읽을 때 주의할 점: 이는 질문자 1인의 디버깅 보고이며 TI가 확인한 내용이 아닙니다. 레지스터 쓰기 문제가 조기 인터럽트로 이어진 구체적 메커니즘은 스레드에서 설명되지 않았습니다.
참고로 C2000Ware 26.00.00.00의 F280015x driverlib(adc.h)에서 확인해 보니 이 함수는 HWREGH로 쓰면서 SOCPRIORITY 필드를 마스크 처리하고 있습니다. 최신 버전에서는 이미 수정되었을 가능성이 높지만, 어느 버전에서 고쳐졌는지는 확인하지 못했습니다.
// C2000Ware 26.00.00.00 (F280015x) 구현 형태 HWREGH(base + ADC_O_SOCPRICTL) = (HWREGH(base + ADC_O_SOCPRICTL) & ~ADC_SOCPRICTL_SOCPRIORITY_M) | (uint16_t)priMode;
5. 아직 풀리지 않은 질문
위 수정 후에도 질문자에게는 한 가지 현상이 남았습니다. 트리거를 TBCTR = 4800, 3600, 2400, 1200(다운카운트)에 두면 SOC0~SOC9가 모두 ADCSOCFLG1에서 관찰되지만, 5990(그리고 5100까지)에서는 SOC9만 관찰되지 않는다는 것입니다.
이에 TI는 다음 두 가지를 요청했고, 이 글을 정리하는 시점에는 후속 답변이 없습니다.
1) ePWM ISR 시작에서 GPIO_togglePin()으로 실제로 100us마다 토글되는지 확인
2) ADCCTL2.PRESCALE에 실제로 기록된 값을 확인 (ADC가 의도보다 빠르게 도는 것일 수 있다는 의견)
같은 증상이 있다면 레지스터에 실제로 기록된 값을 먼저 확인해 보시기 바랍니다.
6. 확인된 하드웨어 사실: tEOC와 tLAT의 4사이클
TI 답변이 데이터시트 표(6-24, 6-25)를 인용해 정리한 내용입니다. 두 값 모두 샘플앤홀드 윈도우가 끝난 시점을 기준으로 합니다.

- tEOC (61 SYSCLK): ADCINT 플래그가 세트되고, 다음 SOC의 샘플앤홀드가 시작될 수 있는 시점입니다.
- tLAT (65 SYSCLK): 변환 결과가 ADCRESULTx에 실제로 래치되는 시점입니다.
- 차이 4 SYSCLK (약 33.3ns): 이 구간에서는 다음 SOC가 이미 샘플링 중이지만 현재 결과는 아직 레지스터에 없습니다.
- SOC 간격은 tSH + tEOC = 76 SYSCLK(633ns)입니다. tSH + tLAT = 80 SYSCLK(667ns) 방식이었다면 10개 기준 40 SYSCLK(약 333ns)가 더 걸립니다. 파이프라이닝으로 절약되는 시간입니다.
ADC_PULSE_END_OF_CONV로 설정하면 인터럽트는 tEOC에 나가고 결과는 4사이클 뒤에 유효해집니다. 따라서 ISR에 진입하자마자 ADCRESULTx를 읽으면 직전 변환값이 읽힐 수 있습니다. 다만 TI도 CPU의 인터럽트 지연이 보통 4사이클보다 길어서 일반적인 ISR에서는 대부분 결과가 준비되어 있다고 밝혔습니다.
진입 직후 곧바로 결과를 읽는 초단 ISR이나 CLA 연동을 구성한다면 이 4사이클을 설계에 반영하시기 바랍니다. (이 문장은 TI 설명에서 일반화한 주의 사항입니다.)
7. 실무 체크리스트
체크 1. 플래그는 enable 전과 ISR 종료 전에 모두 정리
이번 사례에서 직접 원인으로 확인되지는 않았지만 비용이 거의 없는 방어 코드입니다.
// 초기화: 인터럽트 enable 전 잔여 플래그 정리
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
__interrupt void adc_isr_EOC(void)
{
GPIO_writePin(25, 0); // 계측용 (PIE ACK 전에)
uint16_t adcResult9 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER9);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}체크 2. "설정했다"가 아니라 "기록됐다"를 확인
API를 호출했더라도 레지스터에 의도한 값이 들어갔는지는 별개입니다. 우선순위를 쓴다면 디버거 Expressions 창에서 ADCSOCPRICTL과 ADCCTL2.PRESCALE의 실제 값을 확인하십시오. 아래처럼 직접 읽어 비교할 수도 있습니다.
uint16_t socpri = HWREGH(ADCA_BASE + ADC_O_SOCPRICTL); // 의도한 값과 같은지
체크 3. GPIO 토글만 믿지 말고 카운터와 플래그로 교차 확인
GPIO 폭은 ISR 지연의 영향을 받습니다. 아래 방법으로 교차 확인하십시오(TI가 제안한 방식을 포함합니다).
- ADC ISR 진입 즉시 EPWM_getTimeBaseCounterValue()로 TBCTR을 읽어 트리거 대비 경과 사이클을 역산
- ADCSOCFLG1을 직접 읽어 SOC 요청이 어디까지 처리됐는지 확인
- ePWM ISR 시작에서 GPIO_togglePin()을 하나 더 두어 ISR이 설계 주기대로 도는지 먼저 확인
uint16_t tbctrAtIsr = EPWM_getTimeBaseCounterValue(EPWM1_BASE); // 트리거(5990 down) 대비 경과 역산
체크 4. 한 트리거에 10채널을 묶으면 채널 간 시차가 약 5.7us
각 SOC의 샘플앤홀드는 76 SYSCLK 간격으로 이어서 시작됩니다. SOC0과 SOC9 사이 시차는 9 × 76 = 684 SYSCLK ≈ 5.7us입니다(변환 완료 시점으로 보면 SOC0 약 0.65us, SOC9 약 6.35us).
- 3상 전류처럼 동시성이 중요한 신호는 앞쪽 SOC(SOC0~2)에 배치
- 온도, 저속 전압 센서는 뒤쪽 SOC나 별도 트리거로 분리
- 우선순위(ADCSOCPRICTL)를 쓸 때는 사용하는 SDK 버전에서 실제로 기록되는지 확인(체크 2)
8. 핵심 요약
1) 10개 SOC는 같은 트리거로 동시에 요청되지만 변환은 하나씩 이뤄지며, 총 약 6.35us라는 계산은 TI도 확인했습니다.
2) 질문자의 0.42us는 펄스 폭이 아니라 SOC 트리거 후 ADC ISR까지의 지연으로, 인터럽트가 비정상적으로 일찍 들어왔다는 뜻입니다.
3) TI의 1차 가설은 이전 주기의 대기 중 플래그였으나 오버플로 클리어만으로는 개선되지 않았습니다. 질문자는 C2000Ware 5.00.00.00의 ADC_setSOCPriority() 레지스터 쓰기 문제를 보고했고 수정 후 타이밍이 정상화됐다고 했지만, TI가 확인한 내용은 아니며 이유도 스레드에서 설명되지 않았습니다.
4) 트리거가 TBCTR = 5990일 때 SOC9가 ADCSOCFLG1에 보이지 않는 현상은 미해결입니다. ADCCTL2.PRESCALE 값 확인이 TI의 요청 사항입니다.
5) tEOC(61)와 tLAT(65) 사이에는 4 SYSCLK(약 33.3ns) 차이가 있어, 인터럽트 직후 결과를 곧바로 읽는 구성에서는 반영해야 합니다.
설정 API를 호출했다는 것과 레지스터에 그 값이 들어갔다는 것은 다른 이야기입니다. 스레드가 마무리되면 결과를 이어서 정리하겠습니다.
원문(출처) : TI E2E 커뮤니티 https://e2e.ti.com/thread/1683129
| 번호 | 제목 | 작성자 | 날짜 |
|---|
- 1




